5353function abstract_call_gf_by_type (interp:: AbstractInterpreter , @nospecialize (f),
5454 arginfo:: ArgInfo , si:: StmtInfo , @nospecialize (atype),
5555 sv:: InferenceState , max_methods:: Int )
56- ⊑ ᵢ = ⊑ (typeinf_lattice (interp))
56+ ⊑ ₚ = ⊑ (ipo_lattice (interp))
5757 if ! should_infer_this_call (sv)
5858 add_remark! (interp, sv, " Skipped call in throw block" )
5959 nonoverlayed = false
@@ -134,7 +134,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
134134 result, f, this_arginfo, si, match, sv)
135135 const_result = nothing
136136 if const_call_result != = nothing
137- if const_call_result. rt ⊑ ᵢ rt
137+ if const_call_result. rt ⊑ ₚ rt
138138 rt = const_call_result. rt
139139 (; effects, const_result, edge) = const_call_result
140140 end
@@ -167,7 +167,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
167167 this_const_rt = widenwrappedconditional (const_call_result. rt)
168168 # return type of const-prop' inference can be wider than that of non const-prop' inference
169169 # e.g. in cases when there are cycles but cached result is still accurate
170- if this_const_rt ⊑ ᵢ this_rt
170+ if this_const_rt ⊑ ₚ this_rt
171171 this_conditional = this_const_conditional
172172 this_rt = this_const_rt
173173 (; effects, const_result, edge) = const_call_result
@@ -2399,19 +2399,52 @@ function abstract_eval_ssavalue(s::SSAValue, ssavaluetypes::Vector{Any})
23992399 return typ
24002400end
24012401
2402- function widenreturn (ipo_lattice:: AbstractLattice , @nospecialize (rt), @nospecialize (bestguess), nargs:: Int , slottypes:: Vector{Any} , changes:: VarTable )
2403- ⊑ ₚ = ⊑ (ipo_lattice)
2404- inner_lattice = widenlattice (ipo_lattice)
2405- ⊑ ᵢ = ⊑ (inner_lattice)
2406- if ! (bestguess ⊑ ₚ Bool) || bestguess === Bool
2402+ struct BestguessInfo{Interp<: AbstractInterpreter }
2403+ interp:: Interp
2404+ bestguess
2405+ nargs:: Int
2406+ slottypes:: Vector{Any}
2407+ changes:: VarTable
2408+ function BestguessInfo (interp:: Interp , @nospecialize (bestguess), nargs:: Int ,
2409+ slottypes:: Vector{Any} , changes:: VarTable ) where Interp<: AbstractInterpreter
2410+ new {Interp} (interp, bestguess, nargs, slottypes, changes)
2411+ end
2412+ end
2413+
2414+ """
2415+ widenreturn(@nospecialize(rt), info::BestguessInfo) -> new_bestguess
2416+
2417+ Appropriately converts inferred type of a return value `rt` to such a type
2418+ that we know we can store in the cache and is valid and good inter-procedurally,
2419+ E.g. if `rt isa Conditional` then `rt` should be converted to `InterConditional`
2420+ or the other cachable lattice element.
2421+
2422+ External lattice `𝕃ₑ::ExternalLattice` may overload:
2423+ - `widenreturn(𝕃ₑ::ExternalLattice, @nospecialize(rt), info::BestguessInfo)`
2424+ - `widenreturn_noslotwrapper(𝕃ₑ::ExternalLattice, @nospecialize(rt), info::BestguessInfo)`
2425+ """
2426+ function widenreturn (@nospecialize (rt), info:: BestguessInfo )
2427+ return widenreturn (typeinf_lattice (info. interp), rt, info)
2428+ end
2429+
2430+ function widenreturn (𝕃ᵢ:: AbstractLattice , @nospecialize (rt), info:: BestguessInfo )
2431+ return widenreturn (widenlattice (𝕃ᵢ), rt, info)
2432+ end
2433+ function widenreturn_noslotwrapper (𝕃ᵢ:: AbstractLattice , @nospecialize (rt), info:: BestguessInfo )
2434+ return widenreturn_noslotwrapper (widenlattice (𝕃ᵢ), rt, info)
2435+ end
2436+
2437+ function widenreturn (𝕃ᵢ:: ConditionalsLattice , @nospecialize (rt), info:: BestguessInfo )
2438+ ⊑ ᵢ = ⊑ (𝕃ᵢ)
2439+ if ! (⊑ (ipo_lattice (info. interp), info. bestguess, Bool)) || info. bestguess === Bool
24072440 # give up inter-procedural constraint back-propagation
24082441 # when tmerge would widen the result anyways (as an optimization)
24092442 rt = widenconditional (rt)
24102443 else
24112444 if isa (rt, Conditional)
24122445 id = rt. slot
2413- if 1 ≤ id ≤ nargs
2414- old_id_type = widenconditional (slottypes[id]) # same as `(states[1]::VarTable)[id].typ`
2446+ if 1 ≤ id ≤ info . nargs
2447+ old_id_type = widenconditional (info . slottypes[id]) # same as `(states[1]::VarTable)[id].typ`
24152448 if (! (rt. thentype ⊑ ᵢ old_id_type) || old_id_type ⊑ ᵢ rt. thentype) &&
24162449 (! (rt. elsetype ⊑ ᵢ old_id_type) || old_id_type ⊑ ᵢ rt. elsetype)
24172450 # discard this `Conditional` since it imposes
@@ -2428,44 +2461,69 @@ function widenreturn(ipo_lattice::AbstractLattice, @nospecialize(rt), @nospecial
24282461 end
24292462 if isa (rt, Conditional)
24302463 rt = InterConditional (rt. slot, rt. thentype, rt. elsetype)
2431- elseif is_lattice_bool (ipo_lattice, rt)
2432- if isa (bestguess, InterConditional)
2433- # if the bestguess so far is already `Conditional`, try to convert
2434- # this `rt` into `Conditional` on the slot to avoid overapproximation
2435- # due to conflict of different slots
2436- rt = bool_rt_to_conditional (rt, slottypes, changes, bestguess. slot)
2437- else
2438- # pick up the first "interesting" slot, convert `rt` to its `Conditional`
2439- # TODO : ideally we want `Conditional` and `InterConditional` to convey
2440- # constraints on multiple slots
2441- for slot_id in 1 : nargs
2442- rt = bool_rt_to_conditional (rt, slottypes, changes, slot_id)
2443- rt isa InterConditional && break
2444- end
2445- end
2464+ elseif is_lattice_bool (𝕃ᵢ, rt)
2465+ rt = bool_rt_to_conditional (rt, info)
24462466 end
24472467 end
2448-
2449- # only propagate information we know we can store
2450- # and is valid and good inter-procedurally
24512468 isa (rt, Conditional) && return InterConditional (rt)
24522469 isa (rt, InterConditional) && return rt
2453- return widenreturn_noconditional (widenlattice (ipo_lattice), rt)
2470+ return widenreturn (widenlattice (𝕃ᵢ), rt, info)
2471+ end
2472+ function bool_rt_to_conditional (@nospecialize (rt), info:: BestguessInfo )
2473+ bestguess = info. bestguess
2474+ if isa (bestguess, InterConditional)
2475+ # if the bestguess so far is already `Conditional`, try to convert
2476+ # this `rt` into `Conditional` on the slot to avoid overapproximation
2477+ # due to conflict of different slots
2478+ rt = bool_rt_to_conditional (rt, bestguess. slot, info)
2479+ else
2480+ # pick up the first "interesting" slot, convert `rt` to its `Conditional`
2481+ # TODO : ideally we want `Conditional` and `InterConditional` to convey
2482+ # constraints on multiple slots
2483+ for slot_id = 1 : info. nargs
2484+ rt = bool_rt_to_conditional (rt, slot_id, info)
2485+ rt isa InterConditional && break
2486+ end
2487+ end
2488+ return rt
2489+ end
2490+ function bool_rt_to_conditional (@nospecialize (rt), slot_id:: Int , info:: BestguessInfo )
2491+ ⊑ ᵢ = ⊑ (typeinf_lattice (info. interp))
2492+ old = info. slottypes[slot_id]
2493+ new = widenconditional (info. changes[slot_id]. typ) # avoid nested conditional
2494+ if new ⊑ ᵢ old && ! (old ⊑ ᵢ new)
2495+ if isa (rt, Const)
2496+ val = rt. val
2497+ if val === true
2498+ return InterConditional (slot_id, new, Bottom)
2499+ elseif val === false
2500+ return InterConditional (slot_id, Bottom, new)
2501+ end
2502+ elseif rt === Bool
2503+ return InterConditional (slot_id, new, new)
2504+ end
2505+ end
2506+ return rt
24542507end
24552508
2456- function widenreturn_noconditional (inner_lattice:: AbstractLattice , @nospecialize (rt))
2457- isa (rt, Const) && return rt
2458- isa (rt, Type) && return rt
2509+ function widenreturn (𝕃ᵢ:: PartialsLattice , @nospecialize (rt), info:: BestguessInfo )
2510+ return widenreturn_partials (𝕃ᵢ, rt, info)
2511+ end
2512+ function widenreturn_noslotwrapper (𝕃ᵢ:: PartialsLattice , @nospecialize (rt), info:: BestguessInfo )
2513+ return widenreturn_partials (𝕃ᵢ, rt, info)
2514+ end
2515+ function widenreturn_partials (𝕃ᵢ:: PartialsLattice , @nospecialize (rt), info:: BestguessInfo )
24592516 if isa (rt, PartialStruct)
24602517 fields = copy (rt. fields)
24612518 local anyrefine = false
2519+ 𝕃 = typeinf_lattice (info. interp)
24622520 for i in 1 : length (fields)
24632521 a = fields[i]
2464- a = isvarargtype (a) ? a : widenreturn_noconditional (inner_lattice , a)
2522+ a = isvarargtype (a) ? a : widenreturn_noslotwrapper (𝕃 , a, info )
24652523 if ! anyrefine
24662524 # TODO : consider adding && const_prop_profitable(a) here?
24672525 anyrefine = has_const_info (a) ||
2468- ⊏ (inner_lattice , a, fieldtype (rt. typ, i))
2526+ ⊏ (𝕃 , a, fieldtype (rt. typ, i))
24692527 end
24702528 fields[i] = a
24712529 end
@@ -2474,6 +2532,24 @@ function widenreturn_noconditional(inner_lattice::AbstractLattice, @nospecialize
24742532 if isa (rt, PartialOpaque)
24752533 return rt # XXX : this case was missed in #39512
24762534 end
2535+ return widenreturn (widenlattice (𝕃ᵢ), rt, info)
2536+ end
2537+
2538+ function widenreturn (:: ConstsLattice , @nospecialize (rt), :: BestguessInfo )
2539+ return widenreturn_consts (rt)
2540+ end
2541+ function widenreturn_noslotwrapper (:: ConstsLattice , @nospecialize (rt), :: BestguessInfo )
2542+ return widenreturn_consts (rt)
2543+ end
2544+ function widenreturn_consts (@nospecialize (rt))
2545+ isa (rt, Const) && return rt
2546+ return widenconst (rt)
2547+ end
2548+
2549+ function widenreturn (:: JLTypeLattice , @nospecialize (rt), :: BestguessInfo )
2550+ return widenconst (rt)
2551+ end
2552+ function widenreturn_noslotwrapper (:: JLTypeLattice , @nospecialize (rt), :: BestguessInfo )
24772553 return widenconst (rt)
24782554end
24792555
@@ -2537,15 +2613,15 @@ end
25372613 end
25382614end
25392615
2540- function update_bbstate! (lattice :: AbstractLattice , frame:: InferenceState , bb:: Int , vartable:: VarTable )
2616+ function update_bbstate! (𝕃ᵢ :: AbstractLattice , frame:: InferenceState , bb:: Int , vartable:: VarTable )
25412617 bbtable = frame. bb_vartables[bb]
25422618 if bbtable === nothing
25432619 # if a basic block hasn't been analyzed yet,
25442620 # we can update its state a bit more aggressively
25452621 frame. bb_vartables[bb] = copy (vartable)
25462622 return true
25472623 else
2548- return stupdate! (lattice , bbtable, vartable)
2624+ return stupdate! (𝕃ᵢ , bbtable, vartable)
25492625 end
25502626end
25512627
@@ -2567,6 +2643,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
25672643 ssavaluetypes = frame. ssavaluetypes
25682644 bbs = frame. cfg. blocks
25692645 nbbs = length (bbs)
2646+ 𝕃ₚ, 𝕃ᵢ = ipo_lattice (interp), typeinf_lattice (interp)
25702647
25712648 currbb = frame. currbb
25722649 if currbb != 1
@@ -2636,19 +2713,19 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
26362713 # We continue with the true branch, but process the false
26372714 # branch here.
26382715 if isa (condt, Conditional)
2639- else_change = conditional_change (currstate, condt. elsetype, condt. slot)
2716+ else_change = conditional_change (𝕃ᵢ, currstate, condt. elsetype, condt. slot)
26402717 if else_change != = nothing
26412718 false_vartable = stoverwrite1! (copy (currstate), else_change)
26422719 else
26432720 false_vartable = currstate
26442721 end
2645- changed = update_bbstate! (typeinf_lattice (interp) , frame, falsebb, false_vartable)
2646- then_change = conditional_change (currstate, condt. thentype, condt. slot)
2722+ changed = update_bbstate! (𝕃ᵢ , frame, falsebb, false_vartable)
2723+ then_change = conditional_change (𝕃ᵢ, currstate, condt. thentype, condt. slot)
26472724 if then_change != = nothing
26482725 stoverwrite1! (currstate, then_change)
26492726 end
26502727 else
2651- changed = update_bbstate! (typeinf_lattice (interp) , frame, falsebb, currstate)
2728+ changed = update_bbstate! (𝕃ᵢ , frame, falsebb, currstate)
26522729 end
26532730 if changed
26542731 handle_control_backedge! (interp, frame, currpc, stmt. dest)
@@ -2660,7 +2737,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
26602737 elseif isa (stmt, ReturnNode)
26612738 bestguess = frame. bestguess
26622739 rt = abstract_eval_value (interp, stmt. val, currstate, frame)
2663- rt = widenreturn (ipo_lattice (interp), rt, bestguess, nargs, slottypes, currstate)
2740+ rt = widenreturn (rt, BestguessInfo (interp, bestguess, nargs, slottypes, currstate) )
26642741 # narrow representation of bestguess slightly to prepare for tmerge with rt
26652742 if rt isa InterConditional && bestguess isa Const
26662743 let slot_id = rt. slot
@@ -2680,9 +2757,9 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
26802757 if ! isempty (frame. limitations)
26812758 rt = LimitedAccuracy (rt, copy (frame. limitations))
26822759 end
2683- if tchanged (ipo_lattice (interp) , rt, bestguess)
2760+ if tchanged (𝕃ₚ , rt, bestguess)
26842761 # new (wider) return type for frame
2685- bestguess = tmerge (ipo_lattice (interp) , bestguess, rt)
2762+ bestguess = tmerge (𝕃ₚ , bestguess, rt)
26862763 # TODO : if bestguess isa InterConditional && !interesting(bestguess); bestguess = widenconditional(bestguess); end
26872764 frame. bestguess = bestguess
26882765 for (caller, caller_pc) in frame. cycle_backedges
@@ -2698,7 +2775,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
26982775 # Propagate entry info to exception handler
26992776 l = stmt. args[1 ]:: Int
27002777 catchbb = block_for_inst (frame. cfg, l)
2701- if update_bbstate! (typeinf_lattice (interp) , frame, catchbb, currstate)
2778+ if update_bbstate! (𝕃ᵢ , frame, catchbb, currstate)
27022779 push! (W, catchbb)
27032780 end
27042781 ssavaluetypes[currpc] = Any
@@ -2723,7 +2800,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
27232800 # propagate new type info to exception handler
27242801 # the handling for Expr(:enter) propagates all changes from before the try/catch
27252802 # so this only needs to propagate any changes
2726- if stupdate1! (typeinf_lattice (interp) , states[exceptbb]:: VarTable , changes)
2803+ if stupdate1! (𝕃ᵢ , states[exceptbb]:: VarTable , changes)
27272804 push! (W, exceptbb)
27282805 end
27292806 cur_hand = frame. handler_at[cur_hand]
@@ -2735,7 +2812,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
27352812 continue
27362813 end
27372814 if ! isempty (frame. ssavalue_uses[currpc])
2738- record_ssa_assign! (currpc, type, frame)
2815+ record_ssa_assign! (𝕃ᵢ, currpc, type, frame)
27392816 else
27402817 ssavaluetypes[currpc] = type
27412818 end
@@ -2748,7 +2825,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
27482825
27492826 # Case 2: Directly branch to a different BB
27502827 begin @label branch
2751- if update_bbstate! (typeinf_lattice (interp) , frame, nextbb, currstate)
2828+ if update_bbstate! (𝕃ᵢ , frame, nextbb, currstate)
27522829 push! (W, nextbb)
27532830 end
27542831 end
@@ -2772,13 +2849,13 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
27722849 nothing
27732850end
27742851
2775- function conditional_change (state:: VarTable , @nospecialize (typ), slot:: Int )
2852+ function conditional_change (𝕃ᵢ :: AbstractLattice , state:: VarTable , @nospecialize (typ), slot:: Int )
27762853 vtype = state[slot]
27772854 oldtyp = vtype. typ
27782855 if iskindtype (typ)
27792856 # this code path corresponds to the special handling for `isa(x, iskindtype)` check
27802857 # implemented within `abstract_call_builtin`
2781- elseif ignorelimited (typ) ⊑ ignorelimited (oldtyp)
2858+ elseif ⊑ (𝕃ᵢ, ignorelimited (typ), ignorelimited (oldtyp) )
27822859 # approximate test for `typ ∩ oldtyp` being better than `oldtyp`
27832860 # since we probably formed these types with `typesubstract`,
27842861 # the comparison is likely simple
@@ -2788,29 +2865,11 @@ function conditional_change(state::VarTable, @nospecialize(typ), slot::Int)
27882865 if oldtyp isa LimitedAccuracy
27892866 # typ is better unlimited, but we may still need to compute the tmeet with the limit
27902867 # "causes" since we ignored those in the comparison
2791- typ = tmerge (typ, LimitedAccuracy (Bottom, oldtyp. causes))
2868+ typ = tmerge (𝕃ᵢ, typ, LimitedAccuracy (Bottom, oldtyp. causes))
27922869 end
27932870 return StateUpdate (SlotNumber (slot), VarState (typ, vtype. undef), state, true )
27942871end
27952872
2796- function bool_rt_to_conditional (@nospecialize (rt), slottypes:: Vector{Any} , state:: VarTable , slot_id:: Int )
2797- old = slottypes[slot_id]
2798- new = widenconditional (state[slot_id]. typ) # avoid nested conditional
2799- if new ⊑ old && ! (old ⊑ new)
2800- if isa (rt, Const)
2801- val = rt. val
2802- if val === true
2803- return InterConditional (slot_id, new, Bottom)
2804- elseif val === false
2805- return InterConditional (slot_id, Bottom, new)
2806- end
2807- elseif rt === Bool
2808- return InterConditional (slot_id, new, new)
2809- end
2810- end
2811- return rt
2812- end
2813-
28142873# make as much progress on `frame` as possible (by handling cycles)
28152874function typeinf_nocycle (interp:: AbstractInterpreter , frame:: InferenceState )
28162875 typeinf_local (interp, frame)
0 commit comments