• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / 1541

08 Dec 2025 04:29PM UTC coverage: 76.699% (-0.04%) from 76.74%
1541

push

buildkite

web-flow
codegen: implement `sret_union` ABI for pointer-ful types (#55045)

This effectively expands our existing `union` ABI to cover both of these
existing cases:
 - `sret`  ABI (which can stack-allocate a _single pointer-ful_ type)
 - `union` ABI (which can stack-allocate _many pointer-free_ types)

This provides some nice speed-ups for temporary "wrappers":
```julia
const v = Any[]
@noinline maybe_wrapped(i) = (i % 32 != 0) ? Some(v) : nothing
function foo()
    count = 0
    for i = 1:1_000_000
        count += (maybe_wrapped(i) !== nothing) ? 1 : 0
    end
    return count
end
```

On this PR this gives:
```julia
julia> @btime foo()
  1.675 ms (0 allocations: 0 bytes)
968750
```

compared to current master:
```julia
julia> @btime foo()
  6.877 ms (968750 allocations: 14.78 MiB)
968750
```

Co-authored-by: Gabriel Baraldi <baraldigabriel@gmail.com>
Co-authored-by: Jameson Nash <vtjnash@gmail.com>

62469 of 81447 relevant lines covered (76.7%)

22102469.65 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.49
/Compiler/src/abstractinterpretation.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
struct SlotRefinement
4
    slot::SlotNumber
5
    typ::Any
6
    SlotRefinement(slot::SlotNumber, @nospecialize(typ)) = new(slot, typ)
3,777✔
7
end
8

9
# See if the inference result of the current statement's result value might affect
10
# the final answer for the method (aside from optimization potential and exceptions).
11
# To do that, we need to check both for slot assignment and SSA usage.
12
call_result_unused(sv::InferenceState, currpc::Int) =
1,634,399✔
13
    isexpr(sv.src.code[currpc], :call) && isempty(sv.ssavalue_uses[currpc])
14
call_result_unused(si::StmtInfo) = !si.used
1,868,010✔
15

16
is_const_bool_or_bottom(@nospecialize(b)) = (isa(b, Const) && isa(b.val, Bool)) || b == Bottom
×
17
function can_propagate_conditional(@nospecialize(rt), argtypes::Vector{Any})
249,502✔
18
    isa(rt, InterConditional) || return false
497,973✔
19
    if rt.slot > length(argtypes)
1,031✔
20
        # In the vararg tail - can't be conditional
21
        @assert isvarargtype(argtypes[end])
×
22
        return false
×
23
    end
24
    return isa(argtypes[rt.slot], Conditional) &&
1,031✔
25
        is_const_bool_or_bottom(rt.thentype) && is_const_bool_or_bottom(rt.thentype)
26
end
27

28
function propagate_conditional(rt::InterConditional, cond::Conditional)
×
29
    new_thentype = rt.thentype === Const(false) ? cond.elsetype : cond.thentype
×
30
    new_elsetype = rt.elsetype === Const(true) ? cond.thentype : cond.elsetype
×
31
    if rt.thentype == Bottom
×
32
        @assert rt.elsetype != Bottom
×
33
        return Conditional(cond.slot, Bottom, new_elsetype)
×
34
    elseif rt.elsetype == Bottom
×
35
        @assert rt.thentype != Bottom
×
36
        return Conditional(cond.slot, new_thentype, Bottom)
×
37
    end
38
    return Conditional(cond.slot, new_thentype, new_elsetype)
×
39
end
40

41
mutable struct SafeBox{T}
42
    x::T
43
    SafeBox{T}(x::T) where T = new{T}(x)
227,134✔
44
    SafeBox(@nospecialize x) = new{Any}(x)
×
45
end
46
getindex(box::SafeBox) = box.x
916,960✔
47
setindex!(box::SafeBox{T}, x::T) where T = setfield!(box, :x, x)
229,978✔
48

49
struct FailedMethodMatch
50
    reason::String
35✔
51
end
52

53
struct MethodMatchTarget
54
    match::MethodMatch
1,047,418✔
55
    edges::Vector{Union{Nothing,CodeInstance}}
56
    call_results::Vector{Union{Nothing,InferredCallResult}}
57
    edge_idx::Int
58
end
59

60
struct MethodMatches
61
    applicable::Vector{MethodMatchTarget}
1,004,805✔
62
    info::MethodMatchInfo
63
    valid_worlds::WorldRange
64
end
65
any_ambig(result::MethodLookupResult) = result.ambig
1,038,217✔
66
any_ambig(info::MethodMatchInfo) = any_ambig(info.results)
1,038,217✔
67
any_ambig(m::MethodMatches) = any_ambig(m.info)
1,002,933✔
68
fully_covering(info::MethodMatchInfo) = info.fullmatch
1,494,329✔
69
fully_covering(m::MethodMatches) = fully_covering(m.info)
1,005,299✔
70

71
struct UnionSplitMethodMatches
72
    applicable::Vector{MethodMatchTarget}
17,697✔
73
    applicable_argtypes::Vector{Vector{Any}}
74
    info::UnionSplitInfo
75
    valid_worlds::WorldRange
76
end
77
any_ambig(info::UnionSplitInfo) = any(any_ambig, info.split)
51,490✔
78
any_ambig(m::UnionSplitMethodMatches) = any_ambig(m.info)
51,490✔
79
fully_covering(info::UnionSplitInfo) = all(fully_covering, info.split)
17,245✔
80
fully_covering(m::UnionSplitMethodMatches) = fully_covering(m.info)
17,245✔
81

82
nmatches(info::MethodMatchInfo) = length(info.results)
×
83
function nmatches(info::UnionSplitInfo)
×
84
    n = 0
×
85
    for mminfo in info.split
×
86
        n += nmatches(mminfo)
×
87
    end
×
88
    return n
×
89
end
90

91
# intermediate state for computing gfresult
92
mutable struct CallInferenceState
93
    inferidx::Int
94
    rettype
95
    exctype
96
    all_effects::Effects
97
    conditionals::Union{Nothing,Tuple{Vector{Any},Vector{Any}}} # keeps refinement information of call argument types when the return type is boolean
98
    slotrefinements::Union{Nothing,Vector{Any}} # keeps refinement information on slot types obtained from call signature
99

100
    # some additional fields for untyped objects (just to avoid capturing)
101
    const func
102
    const matches::Union{MethodMatches,UnionSplitMethodMatches}
103
    function CallInferenceState(@nospecialize(func), matches::Union{MethodMatches,UnionSplitMethodMatches})
104
        return new(#=inferidx=#1, #=rettype=#Bottom, #=exctype=#Bottom, #=all_effects=#EFFECTS_TOTAL,
1,023,071✔
105
            #=conditionals=#nothing, #=slotrefinements=#nothing, func, matches)
106
    end
107
end
108

109
function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(func),
1,028,218✔
110
                                  arginfo::ArgInfo, si::StmtInfo, @nospecialize(atype),
111
                                  sv::AbsIntState, max_methods::Int)
112
    ๐•ƒโ‚š, ๐•ƒแตข = ipo_lattice(interp), typeinf_lattice(interp)
1,028,218✔
113
    โŠ‘โ‚š, โŠ”โ‚š, โŠ”แตข  = partialorder(๐•ƒโ‚š), join(๐•ƒโ‚š), join(๐•ƒแตข)
1,028,218✔
114
    argtypes = arginfo.argtypes
1,028,218✔
115
    if si.saw_latestworld
1,028,218✔
116
        add_remark!(interp, sv, "Cannot infer call, because we previously saw :latestworld")
×
117
        return Future(CallMeta(Any, Any, Effects(), NoCallInfo()))
×
118
    end
119
    matches = find_method_matches(interp, argtypes, atype; max_methods)
2,038,619✔
120
    if isa(matches, FailedMethodMatch)
1,028,218✔
121
        add_remark!(interp, sv, matches.reason)
5,147✔
122
        return Future(CallMeta(Any, Any, Effects(), NoCallInfo()))
5,147✔
123
    end
124

125
    (; valid_worlds, applicable) = matches
1,023,071✔
126
    update_valid_age!(sv, get_inference_world(interp), valid_worlds) # need to record the negative world now, since even if we don't generate any useful information, inlining might want to add an invoke edge and it won't have this information anymore
1,023,071✔
127
    if bail_out_toplevel_call(interp, sv)
1,023,071✔
128
        local napplicable = length(applicable)
1,058✔
129
        for i = 1:napplicable
1,058✔
130
            local sig = applicable[i].match.spec_types
1,058✔
131
            if !isdispatchtuple(sig)
1,058✔
132
                # only infer fully concrete call sites in top-level expressions (ignoring even isa_compileable_sig matches)
133
                add_remark!(interp, sv, "Refusing to infer non-concrete call site in top-level expression")
×
134
                return Future(CallMeta(Any, Any, Effects(), NoCallInfo()))
×
135
            end
136
        end
1,058✔
137
    end
138

139
    # final result
140
    gfresult = Future{CallMeta}()
1,023,071✔
141
    state = CallInferenceState(func, matches)
1,040,768✔
142

143
    # split the for loop off into a function, so that we can pause and restart it at will
144
    function infercalls(interp, sv)
2,197,100✔
145
        local napplicable = length(applicable)
1,174,029✔
146
        local multiple_matches = napplicable > 1
1,174,029✔
147
        while state.inferidx <= napplicable
2,070,363✔
148
            (; match, edges, call_results, edge_idx) = applicable[state.inferidx]
1,047,849✔
149
            local method = match.method
1,047,849✔
150
            local sig = match.spec_types
1,047,849✔
151
            if bail_out_call(interp, InferenceLoopState(state.rettype, state.all_effects), sv)
1,047,849✔
152
                add_remark!(interp, sv, "Call inference reached maximally imprecise information: bailing on doing more abstract inference.")
557✔
153
                break
557✔
154
            end
155
            # TODO: this is unmaintained now as it didn't seem to improve things, though it does avoid hard-coding the union split at the higher level,
156
            # it also can hurt infer-ability of some constrained parameter types (e.g. quacks like a duck)
157
            # sigtuple = unwrap_unionall(sig)::DataType
158
            # splitunions = 1 < unionsplitcost(sigtuple.parameters) * napplicable <= InferenceParams(interp).max_union_splitting
159
            #if splitunions
160
            #    splitsigs = switchtupleunion(sig)
161
            #    for sig_n in splitsigs
162
            #        result = abstract_call_method(interp, method, sig_n, svec(), multiple_matches, si, sv)::Future
163
            #        handle1(...)
164
            #    end
165
            #end
166
            mresult = abstract_call_method(interp, method, sig, match.sparams, multiple_matches, si, sv)::Future
1,047,292✔
167
            function handle1(interp, sv)
2,094,584✔
168
                local (; rt, exct, effects, edge, call_result) = mresult[]
1,198,250✔
169
                this_conditional = ignorelimited(rt)
2,094,513✔
170
                this_rt = widenwrappedconditional(rt)
1,047,292✔
171
                this_exct = exct
1,047,292✔
172
                # try constant propagation with argtypes for this match
173
                # this is in preparation for inlining, or improving the return result
174
                local matches = state.matches
1,047,292✔
175
                this_argtypes = isa(matches, MethodMatches) ? argtypes : matches.applicable_argtypes[state.inferidx]
1,084,610✔
176
                this_arginfo = ArgInfo(arginfo.fargs, this_argtypes)
2,041,196✔
177
                const_call_result = abstract_call_method_with_const_args(interp,
1,198,250✔
178
                    mresult[], state.func, this_arginfo, si, match, sv)
179
                if const_call_result !== nothing
1,047,292✔
180
                    this_const_conditional = ignorelimited(const_call_result.rt)
863,835✔
181
                    this_const_rt = widenwrappedconditional(const_call_result.rt)
431,931✔
182
                    const_result = const_edge = nothing
431,931✔
183
                    if this_const_rt โŠ‘โ‚š this_rt
431,931✔
184
                        # As long as the const-prop result we have is not *worse* than
185
                        # what we found out on types, we'd like to use it. Even if the
186
                        # end result is exactly equivalent, it is likely that the IR
187
                        # we produced while constproping is better than that with
188
                        # generic types.
189
                        # Return type of const-prop' inference can be wider than that of non const-prop' inference
190
                        # e.g. in cases when there are cycles but cached result is still accurate
191
                        this_conditional = this_const_conditional
431,919✔
192
                        this_rt = this_const_rt
431,919✔
193
                        (; effects, const_result, const_edge) = const_call_result
431,919✔
194
                    elseif is_better_effects(const_call_result.effects, effects)
12✔
195
                        (; effects, const_result, const_edge) = const_call_result
6✔
196
                    else
197
                        add_remark!(interp, sv, "[constprop] Discarded because the result was wider than inference")
6✔
198
                    end
199
                    # Treat the exception type separately. Currently, constprop often cannot determine the exception type
200
                    # because consistent-cy does not apply to exceptions.
201
                    if const_call_result.exct โ‹ค this_exct
431,931✔
202
                        this_exct = const_call_result.exct
184,074✔
203
                        (; const_result, const_edge) = const_call_result
184,074✔
204
                    else
205
                        add_remark!(interp, sv, "[constprop] Discarded exception type because result was wider than inference")
247,857✔
206
                    end
207
                    if const_edge !== nothing
431,931✔
208
                        edge = const_edge
420,169✔
209
                        update_valid_age!(sv, get_inference_world(interp), world_range(const_edge))
420,169✔
210
                    end
211
                    if const_result !== nothing
431,931✔
212
                        call_result = const_result
431,925✔
213
                    end
214
                end
215

216
                state.all_effects = merge_effects(state.all_effects, effects)
2,090,952✔
217
                @assert !(this_conditional isa Conditional || this_rt isa MustAlias) "invalid lattice element returned from inter-procedural context"
1,047,292✔
218
                if can_propagate_conditional(this_conditional, argtypes)
1,047,292✔
219
                    # The only case where we need to keep this in rt is where
220
                    # we can directly propagate the conditional to a slot argument
221
                    # that is not one of our arguments, otherwise we keep all the
222
                    # relevant information in `conditionals` below.
223
                    this_rt = this_conditional
2,766✔
224
                end
225

226
                state.rettype = state.rettype โŠ”โ‚š this_rt
1,047,586✔
227
                state.exctype = state.exctype โŠ”โ‚š this_exct
1,047,586✔
228
                if has_conditional(๐•ƒโ‚š, sv) && this_conditional !== Bottom && is_lattice_bool(๐•ƒโ‚š, state.rettype) && arginfo.fargs !== nothing
1,047,292✔
229
                    local conditionals = state.conditionals
164,177✔
230
                    if conditionals === nothing
164,177✔
231
                        conditionals = state.conditionals = (
451,177✔
232
                            Any[Bottom for _ in 1:length(argtypes)],
233
                            Any[Bottom for _ in 1:length(argtypes)])
234
                    end
235
                    for i = 1:length(argtypes)
184,314✔
236
                        cnd = conditional_argtype(๐•ƒแตข, this_conditional, match.spec_types, argtypes, i)
458,237✔
237
                        conditionals[1][i] = conditionals[1][i] โŠ”แตข cnd.thentype
458,237✔
238
                        conditionals[2][i] = conditionals[2][i] โŠ”แตข cnd.elsetype
458,237✔
239
                    end
752,297✔
240
                end
241
                edges[edge_idx] = edge
1,047,292✔
242
                call_results[edge_idx] = call_result
1,047,292✔
243

244
                state.inferidx += 1
1,047,292✔
245
                return true
1,047,292✔
246
            end # function handle1
247
            if isready(mresult) && handle1(interp, sv)
1,198,250✔
248
                continue
896,334✔
249
            else
250
                push!(sv.tasks, handle1)
150,958✔
251
                return false
150,958✔
252
            end
253
        end # while
896,334✔
254

255
        seenall = state.inferidx > napplicable
1,023,071✔
256
        retinfo = state.matches.info
1,023,071✔
257
        if seenall # small optimization to skip some work that is already implied
1,023,071✔
258
            if !fully_covering(state.matches) || any_ambig(state.matches)
2,041,623✔
259
                # Account for the fact that we may encounter a MethodError with a non-covered or ambiguous signature.
260
                state.all_effects = Effects(state.all_effects; nothrow=false)
3,411✔
261
                state.exctype = state.exctype โŠ”โ‚š MethodError
3,423✔
262
            end
263
            local fargs = arginfo.fargs
1,022,514✔
264
            if sv isa InferenceState && fargs !== nothing
1,022,514✔
265
                state.slotrefinements = collect_slot_refinements(๐•ƒแตข, applicable, argtypes, fargs, sv)
969,696✔
266
            end
267
            state.rettype = from_interprocedural!(interp, state.rettype, sv, arginfo, state.conditionals)
1,164,105✔
268
            if call_result_unused(si) && !(state.rettype === Bottom)
1,022,514✔
269
                add_remark!(interp, sv, "Call result type was widened because the return value is unused")
70,191✔
270
                # We're mainly only here because the optimizer might want this code,
271
                # but we ourselves locally don't typically care about it locally
272
                # (beyond checking if it always throws).
273
                # So avoid adding an edge, since we don't want to bother attempting
274
                # to improve our result even if it does change (to always throw),
275
                # and avoid keeping track of a more complex result type.
276
                state.rettype = Any
70,191✔
277
            end
278
            # if from_interprocedural added any pclimitations to the set inherited from the arguments,
279
            if isa(sv, InferenceState)
1,022,514✔
280
                # TODO (#48913) implement a proper recursion handling for irinterp:
281
                # This works most of the time just because currently the `:terminate` condition often guarantees that
282
                # irinterp doesn't fail into unresolved cycles, but it is not a good (or working) solution.
283
                # We should revisit this once we have a better story for handling cycles in irinterp.
284
                delete!(sv.pclimitations, sv) # remove self, if present
1,022,514✔
285
            end
286
        else
287
            # there is unanalyzed candidate, widen type and effects to the top
288
            state.rettype = state.exctype = Any
557✔
289
            state.all_effects = Effects()
557✔
290
        end
291

292
        # Also considering inferring the compilation signature for this method, so
293
        # it is available to the compiler in case it ends up needing it for the invoke.
294
        if (isa(sv, InferenceState) && infer_compilation_signature(interp) &&
1,035,694✔
295
            (!is_removable_if_unused(state.all_effects) || !call_result_unused(si)))
296
            inferidx = SafeBox{Int}(1)
227,134✔
297
            function infercalls2(interp, sv)
454,179✔
298
                local napplicable = length(applicable)
227,045✔
299
                local multiple_matches = napplicable > 1
227,045✔
300
                while inferidx[] <= napplicable
457,004✔
301
                    (; match, call_results, edge_idx) = applicable[inferidx[]]
229,978✔
302
                    inferidx[] += 1
229,978✔
303
                    local method = match.method
229,978✔
304
                    local sig = match.spec_types
229,978✔
305
                    mi = specialize_method(match; preexisting=true)
229,978✔
306
                    local call_result = call_results[edge_idx]
229,978✔
307
                    if mi === nothing || !(call_result isa InferenceResult) || !const_prop_methodinstance_heuristic(interp, call_result, mi, arginfo, sv)
459,956✔
308
                        csig = get_compileable_sig(method, sig, match.sparams)
22,517✔
309
                        if csig !== nothing && (!seenall || csig !== sig) # corresponds to whether the first look already looked at this, so repeating abstract_call_method is not useful
45,003✔
310
                            #println(sig, " changed to ", csig, " for ", method)
311
                            sp_ = ccall(:jl_type_intersection_with_env, Any, (Any, Any), csig, method.sig)::SimpleVector
6,532✔
312
                            sparams = sp_[2]::SimpleVector
6,532✔
313
                            mresult = abstract_call_method(interp, method, csig, sparams, multiple_matches, StmtInfo(false, false), sv)::Future
6,532✔
314
                            isready(mresult) || return false # wait for mresult Future to resolve off the callstack before continuing
6,551✔
315
                        end
316
                    end
317
                end
229,959✔
318
                return true
227,026✔
319
            end
320
            # start making progress on the first call
321
            infercalls2(interp, sv) || push!(sv.tasks, infercalls2)
227,153✔
322
        end
323

324
        gfresult[] = CallMeta(state.rettype, state.exctype, state.all_effects, retinfo, state.slotrefinements)
1,041,798✔
325
        return true
1,023,071✔
326
    end # function infercalls
327
    # start making progress on the first call
328
    infercalls(interp, sv) || push!(sv.tasks, infercalls)
1,169,300✔
329
    return gfresult
1,023,071✔
330
end
331

332
function find_method_matches(interp::AbstractInterpreter, argtypes::Vector{Any}, @nospecialize(atype);
2,038,733✔
333
                             max_union_splitting::Int = InferenceParams(interp).max_union_splitting,
334
                             max_methods::Int = InferenceParams(interp).max_methods)
335
    if is_union_split_eligible(typeinf_lattice(interp), argtypes, max_union_splitting)
1,028,275✔
336
        return find_union_split_method_matches(interp, argtypes, max_methods)
17,817✔
337
    end
338
    return find_simple_method_matches(interp, atype, max_methods)
1,010,458✔
339
end
340

341
# NOTE this is valid as far as any "constant" lattice element doesn't represent `Union` type
342
is_union_split_eligible(๐•ƒ::AbstractLattice, argtypes::Vector{Any}, max_union_splitting::Int) =
1,028,275✔
343
    1 < unionsplitcost(๐•ƒ, argtypes) <= max_union_splitting
344

345
function find_union_split_method_matches(interp::AbstractInterpreter, argtypes::Vector{Any},
17,817✔
346
                                         max_methods::Int)
347
    split_argtypes = switchtupleunion(typeinf_lattice(interp), argtypes)
17,817✔
348
    infos = MethodMatchInfo[]
17,817✔
349
    applicable = MethodMatchTarget[]
17,817✔
350
    applicable_argtypes = Vector{Any}[] # arrays like `argtypes`, including constants, for each match
17,817✔
351
    valid_worlds = WorldRange()
17,817✔
352
    for i in 1:length(split_argtypes)
20,734✔
353
        arg_n = split_argtypes[i]::Vector{Any}
38,968✔
354
        sig_n = argtypes_to_type(arg_n)
38,968✔
355
        sig_n === Bottom && continue
38,968✔
356
        thismatches = findall(sig_n, method_table(interp); limit = max_methods)
39,088✔
357
        if thismatches === nothing
38,968✔
358
            return FailedMethodMatch("For one of the union split cases, too many methods matched")
120✔
359
        end
360
        valid_worlds = intersect(valid_worlds, thismatches.valid_worlds)
38,848✔
361
        thisfullmatch = any(match::MethodMatch->match.fully_covers, thismatches)
77,465✔
362
        mt = Core.methodtable
38,848✔
363
        thisinfo = MethodMatchInfo(thismatches, mt, sig_n, thisfullmatch)
38,848✔
364
        push!(infos, thisinfo)
38,848✔
365
        for idx = 1:length(thismatches)
44,730✔
366
            push!(applicable, MethodMatchTarget(thismatches[idx], thisinfo.edges, thisinfo.call_results, idx))
37,908✔
367
            push!(applicable_argtypes, arg_n)
37,908✔
368
        end
37,908✔
369
    end
59,999✔
370
    info = UnionSplitInfo(infos)
17,697✔
371
    return UnionSplitMethodMatches(
17,697✔
372
        applicable, applicable_argtypes, info, valid_worlds)
373
end
374

375
function find_simple_method_matches(interp::AbstractInterpreter, @nospecialize(atype), max_methods::Int)
1,009,832✔
376
    matches = findall(atype, method_table(interp); limit = max_methods)
1,014,821✔
377
    if matches === nothing
1,009,832✔
378
        # this means too many methods matched
379
        # (assume this will always be true, so we don't compute / update valid age in this case)
380
        return FailedMethodMatch("Too many methods matched")
5,027✔
381
    end
382
    fullmatch = any(match::MethodMatch->match.fully_covers, matches)
2,021,455✔
383
    mt = Core.methodtable
1,004,805✔
384
    info = MethodMatchInfo(matches, mt, atype, fullmatch)
1,004,805✔
385
    applicable = MethodMatchTarget[MethodMatchTarget(matches[idx], info.edges, info.call_results, idx) for idx = 1:length(matches)]
1,010,341✔
386
    return MethodMatches(applicable, info, matches.valid_worlds)
1,004,805✔
387
end
388

389
"""
390
    from_interprocedural!(interp::AbstractInterpreter, rt, sv::AbsIntState,
391
                          arginfo::ArgInfo, maybecondinfo) -> newrt
392

393
Converts inter-procedural return type `rt` into a local lattice element `newrt`,
394
that is appropriate in the context of current local analysis frame `sv`, especially:
395
- unwraps `rt::LimitedAccuracy` and collects its limitations into the current frame `sv`
396
- converts boolean `rt` to new boolean `newrt` in a way `newrt` can propagate extra conditional
397
  refinement information, e.g. translating `rt::InterConditional` into `newrt::Conditional`
398
  that holds a type constraint information about a variable in `sv`
399

400
This function _should_ be used wherever we propagate results returned from
401
`abstract_call_method` or `abstract_call_method_with_const_args`.
402

403
When `maybecondinfo !== nothing`, this function also tries extra conditional argument type refinement.
404
In such cases `maybecondinfo` should be either of:
405
- `maybecondinfo::Tuple{Vector{Any},Vector{Any}}`: precomputed argument type refinement information
406
- method call signature tuple type
407
When we deal with multiple `MethodMatch`es, it's better to precompute `maybecondinfo` by
408
`tmerge`ing argument signature type of each method call.
409
"""
410
function from_interprocedural!(interp::AbstractInterpreter, @nospecialize(rt), sv::AbsIntState,
815,850✔
411
                               arginfo::ArgInfo, @nospecialize(maybecondinfo))
412
    rt = collect_limitations!(rt, sv)
2,044,630✔
413
    if isa(rt, InterMustAlias)
1,022,352✔
414
        rt = from_intermustalias(typeinf_lattice(interp), rt, arginfo, sv)
147✔
415
    elseif is_lattice_bool(ipo_lattice(interp), rt)
1,022,205✔
416
        if maybecondinfo === nothing
163,409✔
417
            rt = widenconditional(rt)
1,866✔
418
        else
419
            rt = from_interconditional(typeinf_lattice(interp), rt, sv, arginfo, maybecondinfo)
161,543✔
420
        end
421
    end
422
    @assert !(rt isa InterConditional || rt isa InterMustAlias) "invalid lattice element returned from inter-procedural context"
1,022,352✔
423
    return rt
1,022,352✔
424
end
425

426
function collect_limitations!(@nospecialize(typ), sv::InferenceState)
427
    if isa(typ, LimitedAccuracy)
6,618,321✔
428
        union!(sv.pclimitations, typ.causes)
257✔
429
        return typ.typ
257✔
430
    end
431
    return typ
6,618,064✔
432
end
433

434
function from_intermustalias(๐•ƒแตข::AbstractLattice, rt::InterMustAlias, arginfo::ArgInfo, sv::AbsIntState)
147✔
435
    fargs = arginfo.fargs
147✔
436
    if fargs !== nothing && 1 โ‰ค rt.slot โ‰ค length(fargs)
147✔
437
        arg = ssa_def_slot(fargs[rt.slot], sv)
147✔
438
        if isa(arg, SlotNumber)
147✔
439
            argtyp = widenslotwrapper(arginfo.argtypes[rt.slot])
147✔
440
            โŠ‘ = partialorder(๐•ƒแตข)
147✔
441
            if rt.vartyp โŠ‘ argtyp
147✔
442
                return MustAlias(arg, rt.vartyp, rt.fldidx, rt.fldtyp)
147✔
443
            else
444
                # TODO optimize this case?
445
            end
446
        end
447
    end
448
    return widenmustalias(rt)
×
449
end
450

451
function from_interconditional(๐•ƒแตข::AbstractLattice, @nospecialize(rt), sv::AbsIntState,
20,089✔
452
                               arginfo::ArgInfo, @nospecialize(maybecondinfo))
453
    has_conditional(๐•ƒแตข, sv) || return widenconditional(rt)
20,089✔
454
    (; fargs, argtypes) = arginfo
20,089✔
455
    fargs === nothing && return widenconditional(rt)
20,089✔
456
    if can_propagate_conditional(rt, argtypes)
20,089✔
457
        return propagate_conditional(rt, argtypes[rt.slot]::Conditional)
6✔
458
    end
459
    slot = 0
20,083✔
460
    alias = nothing
20,083✔
461
    thentype = elsetype = Any
20,083✔
462
    condval = maybe_extract_const_bool(rt)
23,313✔
463
    โŠ‘, โ‹ค, โŠ“ = partialorder(๐•ƒแตข), strictneqpartialorder(๐•ƒแตข), meet(๐•ƒแตข)
20,083✔
464
    for i in 1:length(fargs)
40,124✔
465
        # find the first argument which supports refinement,
466
        # and intersect all equivalent arguments with it
467
        argtyp = argtypes[i]
56,579✔
468
        if alias === nothing
56,579✔
469
            arg = ssa_def_slot(fargs[i], sv)
56,570✔
470
            if isa(arg, SlotNumber) && widenslotwrapper(argtyp) isa Type
56,570✔
471
                old = argtyp
2,063✔
472
                id = slot_id(arg)
2,063✔
473
            elseif argtyp isa MustAlias
54,507✔
474
                old = argtyp.fldtyp
24✔
475
                id = argtyp.slot
24✔
476
            else
477
                continue # unlikely to refine
54,483✔
478
            end
479
        elseif argtyp isa MustAlias && issubalias(argtyp, alias)
9✔
480
            arg = nothing
6✔
481
            old = alias.fldtyp
6✔
482
            id = alias.slot
6✔
483
        else
484
            continue
3✔
485
        end
486
        if slot == 0 || id == slot
2,099✔
487
            if isa(maybecondinfo, Tuple{Vector{Any},Vector{Any}})
2,093✔
488
                # if we have already computed argument refinement information, apply that now to get the result
489
                new_thentype = maybecondinfo[1][i]
2,093✔
490
                new_elsetype = maybecondinfo[2][i]
2,093✔
491
            else
492
                # otherwise compute it on the fly
493
                cnd = conditional_argtype(๐•ƒแตข, rt, maybecondinfo, argtypes, i)
×
494
                new_thentype = cnd.thentype
×
495
                new_elsetype = cnd.elsetype
×
496
            end
497
            if condval === false
2,093✔
498
                thentype = Bottom
6✔
499
            elseif new_thentype โŠ‘ thentype
2,087✔
500
                thentype = new_thentype
2,084✔
501
            else
502
                thentype = thentype โŠ“ widenconst(new_thentype)
3✔
503
            end
504
            if condval === true
2,093✔
505
                elsetype = Bottom
30✔
506
            elseif new_elsetype โŠ‘ elsetype
2,063✔
507
                elsetype = new_elsetype
2,060✔
508
            else
509
                elsetype = elsetype โŠ“ widenconst(new_elsetype)
3✔
510
            end
511
            if (slot > 0 || condval !== false) && thentype โ‹ค old
4,132✔
512
                slot = id
43✔
513
                if !(arg isa SlotNumber) && argtyp isa MustAlias
43✔
514
                    alias = argtyp
27✔
515
                end
516
            elseif (slot > 0 || condval !== true) && elsetype โ‹ค old
4,073✔
517
                slot = id
3✔
518
                if !(arg isa SlotNumber) && argtyp isa MustAlias
3✔
519
                    alias = argtyp
3✔
520
                end
521
            else # reset: no new useful information for this slot
522
                slot = 0
2,047✔
523
                alias = nothing
2,047✔
524
                thentype = elsetype = Any
2,047✔
525
            end
526
        end
527
    end
93,075✔
528
    if thentype === Bottom && elsetype === Bottom
20,083✔
529
        return Bottom # accidentally proved this call to be dead / throw !
×
530
    elseif slot > 0
20,083✔
531
        if alias !== nothing
40✔
532
            return form_mustalias_conditional(alias, thentype, elsetype)
24✔
533
        end
534
        return Conditional(slot, thentype, elsetype) # record a Conditional improvement to this slot
16✔
535
    end
536
    return widenconditional(rt)
20,043✔
537
end
538

539
function conditional_argtype(๐•ƒแตข::AbstractLattice, @nospecialize(rt), @nospecialize(sig),
56,885✔
540
                             argtypes::Vector{Any}, i::Int)
541
    if isa(rt, InterConditional) && rt.slot == i
56,885✔
542
        return rt
1,020✔
543
    else
544
        argt = widenslotwrapper(argtypes[i])
55,865✔
545
        if isvarargtype(argt)
55,865✔
546
            @assert fieldcount(sig) == i
×
547
            argt = unwrapva(argt)
×
548
        end
549
        thentype = elsetype = tmeet(๐•ƒแตข, argt, fieldtype(sig, i))
55,865✔
550
        condval = maybe_extract_const_bool(rt)
66,349✔
551
        condval === true && (elsetype = Bottom)
55,865✔
552
        condval === false && (thentype = Bottom)
55,865✔
553
        return InterConditional(i, thentype, elsetype)
55,865✔
554
    end
555
end
556

557
function collect_slot_refinements(๐•ƒแตข::AbstractLattice, applicable::Vector{MethodMatchTarget},
185,136✔
558
    argtypes::Vector{Any}, fargs::Vector{Any}, sv::InferenceState)
559
    โŠ, โŠ” = strictpartialorder(๐•ƒแตข), join(๐•ƒแตข)
185,136✔
560
    slotrefinements = nothing
185,136✔
561
    for i = 1:length(fargs)
369,990✔
562
        fargแตข = fargs[i]
532,758✔
563
        if fargแตข isa SlotNumber
532,758✔
564
            fidx = slot_id(fargแตข)
117,430✔
565
            argt = widenslotwrapper(argtypes[i])
117,653✔
566
            if isvarargtype(argt)
117,430✔
567
                argt = unwrapva(argt)
×
568
            end
569
            sigt = Bottom
117,430✔
570
            for j = 1:length(applicable)
234,628✔
571
                (;match) = applicable[j]
117,433✔
572
                valid_as_lattice(match.spec_types, true) || continue
234,866✔
573
                sigt = sigt โŠ” fieldtype(match.spec_types, i)
234,866✔
574
            end
117,452✔
575
            if sigt โŠ argt # i.e. signature type is strictly more specific than the type of the argument slot
117,430✔
576
                if slotrefinements === nothing
16✔
577
                    slotrefinements = fill!(Vector{Any}(undef, length(sv.slottypes)), nothing)
80✔
578
                end
579
                slotrefinements[fidx] = sigt
16✔
580
            end
581
        end
582
    end
880,380✔
583
    return slotrefinements
185,136✔
584
end
585

586
const RECURSION_UNUSED_MSG = "Bounded recursion detected with unused result. Annotated return type may be wider than true result."
587
const RECURSION_MSG = "Bounded recursion detected. Call was widened to force convergence."
588
const RECURSION_MSG_HARDLIMIT = "Bounded recursion detected under hardlimit. Call was widened to force convergence."
589

590
function abstract_call_method(interp::AbstractInterpreter,
1,054,176✔
591
                              method::Method, @nospecialize(sig), sparams::SimpleVector,
592
                              hardlimit::Bool, si::StmtInfo, sv::AbsIntState)
593
    sigtuple = unwrap_unionall(sig)
1,054,176✔
594
    sigtuple isa DataType ||
1,054,176✔
595
        return Future(MethodCallResult(Any, Any, Effects(), nothing, false, false))
596
    all(@nospecialize(x) -> isvarargtype(x) || valid_as_lattice(x, true), sigtuple.parameters) ||
7,183,765✔
597
        return Future(MethodCallResult(Union{}, Any, EFFECTS_THROWS, nothing, false, false)) # catch bad type intersections early
598

599
    if is_nospecializeinfer(method)
1,054,158✔
600
        sig = get_nospecializeinfer_sig(method, sig, sparams)
737✔
601
    end
602

603
    # Limit argument type tuple growth of functions:
604
    # look through the parents list to see if there's a call to the same method
605
    # and from the same method.
606
    # Returns the topmost occurrence of that repeated edge.
607
    edgecycle = edgelimited = false
1,054,158✔
608
    topmost = nothing
1,054,158✔
609

610
    for svโ€ฒ in AbsIntStackUnwind(sv)
2,103,651✔
611
        infmi = frame_instance(svโ€ฒ)
41,726,608✔
612
        if method === infmi.def
20,863,304✔
613
            if infmi.specTypes::Type == sig::Type
8,558✔
614
                # avoid widening when detecting self-recursion
615
                # TODO: merge call cycle and return right away
616
                topmost = nothing
2,922✔
617
                edgecycle = true
2,922✔
618
                break
2,922✔
619
            end
620
            topmost === nothing || continue
5,636✔
621
            if edge_matches_sv(interp, svโ€ฒ, method, sig, sparams, hardlimit, sv)
9,352✔
622
                topmost = svโ€ฒ
2,008✔
623
                edgecycle = true
2,008✔
624
            end
625
        end
626
    end
20,860,382✔
627
    washardlimit = hardlimit
1,054,158✔
628

629
    if topmost !== nothing
1,054,158✔
630
        msig = unwrap_unionall(method.sig)::DataType
1,795✔
631
        spec_len = length(msig.parameters) + 1
1,795✔
632
        mi = frame_instance(sv)
1,795✔
633

634
        if isdefined(method, :recursion_relation)
1,795✔
635
            # We don't require the recursion_relation to be transitive, so
636
            # apply a hard limit
637
            hardlimit = true
×
638
        end
639

640
        if method === mi.def
1,795✔
641
            # Under direct self-recursion, permit much greater use of reducers.
642
            # here we assume that complexity(specTypes) :>= complexity(sig)
643
            comparison = mi.specTypes
746✔
644
            l_comparison = length((unwrap_unionall(comparison)::DataType).parameters)
746✔
645
            spec_len = max(spec_len, l_comparison)
746✔
646
        elseif !hardlimit && isa(topmost, InferenceState)
1,049✔
647
            # Without a hardlimit, permit use of reducers too.
648
            comparison = frame_instance(topmost).specTypes
437✔
649
            # n.b. currently don't allow vararg reducers
650
            #l_comparison = length((unwrap_unionall(comparison)::DataType).parameters)
651
            #spec_len = max(spec_len, l_comparison)
652
        else
653
            comparison = method.sig
612✔
654
        end
655

656
        # see if the type is actually too big (relative to the caller), and limit it if required
657
        newsig = limit_type_size(sig, comparison, hardlimit ? comparison : mi.specTypes, InferenceParams(interp).tuple_complexity_limit_depth, spec_len)
2,529✔
658

659
        if newsig !== sig
1,795✔
660
            # continue inference, but note that we've limited parameter complexity
661
            # on this call (to ensure convergence), so that we don't cache this result
662
            if call_result_unused(si)
583✔
663
                add_remark!(interp, sv, RECURSION_UNUSED_MSG)
473✔
664
                # if we don't (typically) actually care about this result,
665
                # don't bother trying to examine some complex abstract signature
666
                # since it's very unlikely that we'll try to inline this,
667
                # or want make an invoke edge to its calling convention return type.
668
                # (non-typically, this means that we lose the ability to detect a guaranteed StackOverflow in some cases)
669
                return Future(MethodCallResult(Any, Any, Effects(), nothing, true, true))
473✔
670
            end
671
            add_remark!(interp, sv, washardlimit ? RECURSION_MSG_HARDLIMIT : RECURSION_MSG)
110✔
672
            # TODO (#48913) implement a proper recursion handling for irinterp:
673
            # This works just because currently the `:terminate` condition usually means this is unreachable here
674
            # for irinterp because there are not unresolved cycles, but it's not a good solution.
675
            # We should revisit this once we have a better story for handling cycles in irinterp.
676
            if isa(sv, InferenceState)
110✔
677
                # since the hardlimit is against the edge to the parent frame,
678
                # we should try to poison the whole edge, not just the topmost frame
679
                parentframe = frame_parent(topmost)
110✔
680
                while !isa(parentframe, InferenceState)
110✔
681
                    # attempt to find a parent frame that can handle this LimitedAccuracy result correctly
682
                    # so we don't try to cache this incomplete intermediate result
683
                    parentframe === nothing && break
×
684
                    parentframe = frame_parent(parentframe)
×
685
                end
×
686
                if isa(parentframe, InferenceState)
110✔
687
                    poison_callstack!(sv, parentframe)
110✔
688
                elseif isa(topmost, InferenceState)
×
689
                    poison_callstack!(sv, topmost)
×
690
                end
691
            end
692
            # n.b. this heuristic depends on the non-local state, so we must record the limit later
693
            sig = newsig
110✔
694
            sparams = svec()
110✔
695
            edgelimited = true
110✔
696
        end
697
    end
698

699
    # if sig changed, may need to recompute the sparams environment
700
    if isa(method.sig, UnionAll) && isempty(sparams)
1,053,685✔
701
        recomputed = ccall(:jl_type_intersection_with_env, Any, (Any, Any), sig, method.sig)::SimpleVector
24✔
702
        #@assert recomputed[1] !== Bottom
703
        # We must not use `sig` here, since that may re-introduce structural complexity that
704
        # our limiting heuristic sought to eliminate. The alternative would be to not increment depth over covariant contexts,
705
        # but we prefer to permit inference of tuple-destructuring, so we don't do that right now
706
        # For example, with a signature such as `Tuple{T, Ref{T}} where {T <: S}`
707
        # we might want to limit this to `Tuple{S, Ref}`, while type-intersection can instead give us back the original type
708
        # (which moves `S` back up to a lower comparison depth)
709
        # Optionally, we could try to drive this to a fixed point, but I think this is getting too complex,
710
        # and this would only cause more questions and more problems
711
        # (the following is only an example, most of the statements are probable in the wrong order):
712
        #     newsig = sig
713
        #     seen = IdSet()
714
        #     while !(newsig in seen)
715
        #         push!(seen, newsig)
716
        #         lsig = length((unwrap_unionall(sig)::DataType).parameters)
717
        #         newsig = limit_type_size(newsig, sig, sv.linfo.specTypes, InferenceParams(interp).tuple_complexity_limit_depth, lsig)
718
        #         recomputed = ccall(:jl_type_intersection_with_env, Any, (Any, Any), newsig, method.sig)::SimpleVector
719
        #         newsig = recomputed[2]
720
        #     end
721
        #     sig = ?
722
        sparams = recomputed[2]::SimpleVector
24✔
723
    end
724

725
    return typeinf_edge(interp, method, sig, sparams, sv, edgecycle, edgelimited)
1,053,685✔
726
end
727

728
function edge_matches_sv(interp::AbstractInterpreter, frame::AbsIntState,
4,676✔
729
                         method::Method, @nospecialize(sig), sparams::SimpleVector,
730
                         hardlimit::Bool, sv::AbsIntState)
731
    # The `method_for_inference_heuristics` will expand the given method's generator if
732
    # necessary in order to retrieve this field from the generated `CodeInfo`, if it exists.
733
    # The other `CodeInfo`s we inspect will already have this field inflated, so we just
734
    # access it directly instead (to avoid regeneration).
735
    world = get_inference_world(interp)
4,676✔
736
    callee_method2 = method_for_inference_heuristics(method, sig, sparams, world)
4,676✔
737
    inf_method2 = method_for_inference_limit_heuristics(frame)
4,676✔
738
    if callee_method2 !== inf_method2 # limit only if user token match
4,676✔
739
        return false
×
740
    end
741
    if isa(frame, InferenceState) && cache_owner(frame.interp) !== cache_owner(interp)
4,676✔
742
        # Don't assume that frames in different interpreters are the same
743
        return false
×
744
    end
745
    if !hardlimit || InferenceParams(interp).ignore_recursion_hardlimit
5,800✔
746
        # if this is a soft limit,
747
        # also inspect the parent of this edge,
748
        # to see if they are the same Method as sv
749
        # in which case we'll need to ensure it is convergent
750
        # otherwise, we don't
751

752
        # check in the cycle list first
753
        # all items in here are considered mutual parents of all others
754
        if !any(p::AbsIntState->matches_sv(p, sv), callers_in_cycle(frame))
15,865✔
755
            let parent = cycle_parent(frame)
6,517✔
756
                parent === nothing && return false
3,269✔
757
                (is_cached(parent) || frame_parent(parent) !== nothing) || return false
3,660✔
758
                matches_sv(parent, sv) || return false
5,895✔
759
            end
760
        end
761

762
        # If the method defines a recursion relation, give it a chance
763
        # to tell us that this recursion is actually ok.
764
        if isdefined(method, :recursion_relation)
884✔
765
            if Core._call_in_world_total(get_world_counter(), method.recursion_relation, method, callee_method2, sig, frame_instance(frame).specTypes)
×
766
                return false
×
767
            end
768
        end
769
    end
770
    return true
2,008✔
771
end
772

773
# This function is used for computing alternate limit heuristics
774
function method_for_inference_heuristics(method::Method, @nospecialize(sig), sparams::SimpleVector, world::UInt)
452✔
775
    if (hasgenerator(method) && !(method.generator isa Core.GeneratedFunctionStub) &&
452✔
776
        may_invoke_generator(method, sig, sparams))
777
        mi = specialize_method(method, sig, sparams)
9✔
778
        cinfo = get_staged(mi, world)
9✔
779
        if isa(cinfo, CodeInfo)
9✔
780
            method2 = cinfo.method_for_inference_limit_heuristics
9✔
781
            if method2 isa Method
9✔
782
                return method2
×
783
            end
784
        end
785
    end
786
    return nothing
452✔
787
end
788

789
function matches_sv(parent::AbsIntState, sv::AbsIntState)
790
    # limit only if user token match
791
    return (frame_instance(parent).def === frame_instance(sv).def &&
14,198✔
792
            method_for_inference_limit_heuristics(sv) === method_for_inference_limit_heuristics(parent))
793
end
794

795
function is_edge_recursed(edge::CodeInstance, caller::AbsIntState)
796
    return any(AbsIntStackUnwind(caller)) do sv::AbsIntState
82,613✔
797
        return edge.def === frame_instance(sv)
77,795✔
798
    end
799
end
800

801
function is_method_recursed(method::Method, caller::AbsIntState)
×
802
    return any(AbsIntStackUnwind(caller)) do sv::AbsIntState
×
803
        return method === frame_instance(sv).def
×
804
    end
805
end
806

807
function is_constprop_edge_recursed(edge::MethodInstance, caller::AbsIntState)
808
    return any(AbsIntStackUnwind(caller)) do sv::AbsIntState
661✔
809
        return edge === frame_instance(sv) && is_constproped(sv)
1,240✔
810
    end
811
end
812

813
function is_constprop_method_recursed(method::Method, caller::AbsIntState)
814
    return any(AbsIntStackUnwind(caller)) do sv::AbsIntState
48✔
815
        return method === frame_instance(sv).def && is_constproped(sv)
78✔
816
    end
817
end
818

819
# keeps result and context information of abstract_method_call, which will later be used for
820
# backedge computation, and concrete evaluation or constant-propagation
821
struct MethodCallResult
822
    rt
823
    exct
824
    effects::Effects
825
    edge::Union{Nothing,CodeInstance}
826
    edgecycle::Bool
827
    edgelimited::Bool
828
    call_result::Union{Nothing,InferredCallResult}
829
    function MethodCallResult(@nospecialize(rt), @nospecialize(exct), effects::Effects,
830
                              edge::Union{Nothing,CodeInstance}, edgecycle::Bool, edgelimited::Bool,
831
                              call_result::Union{Nothing,InferredCallResult} = nothing)
832
        return new(rt, exct, effects, edge, edgecycle, edgelimited, call_result)
1,214,812✔
833
    end
834
end
835

836
struct InvokeCall
837
    types     # ::Type
838
    InvokeCall(@nospecialize(types)) = new(types)
464✔
839
end
840

841
struct ConstCallResult
842
    rt::Any
843
    exct::Any
844
    const_result::InferredCallResult
845
    effects::Effects
846
    const_edge::Union{Nothing,CodeInstance}
847
    function ConstCallResult(
848
        @nospecialize(rt), @nospecialize(exct),
849
        const_result::InferredCallResult, effects::Effects,
850
        const_edge::Union{Nothing,CodeInstance})
851
        return new(rt, exct, const_result, effects, const_edge)
432,203✔
852
    end
853
end
854

855
function abstract_call_method_with_const_args(interp::AbstractInterpreter,
1,047,756✔
856
    result::MethodCallResult, @nospecialize(f), arginfo::ArgInfo, si::StmtInfo,
857
    match::MethodMatch, sv::AbsIntState, invokecall::Union{Nothing,InvokeCall}=nothing)
858
    if bail_out_const_call(interp, result, si, match, sv)
3,139,312✔
859
        return nothing
9,753✔
860
    end
861
    eligibility = concrete_eval_eligible(interp, f, result, arginfo, sv)
1,952,455✔
862
    concrete_eval_result = nothing
1,038,003✔
863
    if eligibility === :concrete_eval
1,038,003✔
864
        concrete_eval_result = concrete_eval_call(interp, f, result, arginfo, sv, invokecall)
11,671✔
865
        if (concrete_eval_result !== nothing &&  # allow external abstract interpreters to disable concrete evaluation ad-hoc
11,680✔
866
            # if we don't inline the result of this concrete evaluation,
867
            # give const-prop' a chance to inline a better method body
868
            (!may_optimize(interp) ||
869
             may_inline_concrete_result(concrete_eval_result.const_result::ConcreteResult) ||
870
             concrete_eval_result.rt === Bottom)) # unless this call deterministically throws and thus is non-inlineable
871
            return concrete_eval_result
11,665✔
872
        end
873
        # TODO allow semi-concrete interp for this call?
874
    end
875
    mi = maybe_get_const_prop_profitable(interp, result, f, arginfo, si, match, sv)
1,026,338✔
876
    mi === nothing && return concrete_eval_result
1,026,338✔
877
    if is_constprop_recursed(result, mi, sv)
463,179✔
878
        add_remark!(interp, sv, "[constprop] Edge cycle encountered")
152✔
879
        return nothing
152✔
880
    end
881
    # try semi-concrete evaluation
882
    if eligibility === :semi_concrete_eval
463,027✔
883
        irinterp_result = semi_concrete_eval_call(interp, mi, result, arginfo, sv)
97✔
884
        if irinterp_result !== nothing
97✔
885
            return irinterp_result
85✔
886
        end
887
    end
888
    # try constant prop'
889
    return const_prop_call(interp, mi, result, arginfo, sv, concrete_eval_result)
462,942✔
890
end
891

892
function bail_out_const_call(interp::AbstractInterpreter, result::MethodCallResult,
3,678✔
893
                             si::StmtInfo, match::MethodMatch, sv::AbsIntState)
894
    if !InferenceParams(interp).ipo_constant_propagation
1,047,756✔
895
        add_remark!(interp, sv, "[constprop] Disabled by parameter")
×
896
        return true
×
897
    end
898
    if is_no_constprop(match.method)
1,047,756✔
899
        add_remark!(interp, sv, "[constprop] Disabled by method parameter")
2,902✔
900
        return true
2,902✔
901
    end
902
    if is_removable_if_unused(result.effects)
1,044,854✔
903
        if isa(result.rt, Const)
26,485✔
904
            add_remark!(interp, sv, "[constprop] No more information to be gained (const)")
6,779✔
905
            return true
6,792✔
906
        elseif call_result_unused(si)
19,693✔
907
            add_remark!(interp, sv, "[constprop] No more information to be gained (unused result)")
×
908
            return true
×
909
        end
910
    end
911
    if result.rt === Bottom
1,038,062✔
912
        if is_terminates(result.effects) && is_effect_free(result.effects)
13,892✔
913
            # In the future, we may want to add `&& isa(result.exct, Const)` to
914
            # the list of conditions here, but currently, our effect system isn't
915
            # precise enough to let us determine :consistency of `exct`, so we
916
            # would have to force constprop just to determine this, which is too
917
            # expensive.
918
            add_remark!(interp, sv, "[constprop] No more information to be gained (bottom)")
57✔
919
            return true
59✔
920
        end
921
    end
922
    return false
1,038,003✔
923
end
924

925
function concrete_eval_eligible(interp::AbstractInterpreter,
3,645✔
926
    @nospecialize(f), result::MethodCallResult, arginfo::ArgInfo, sv::AbsIntState)
927
    (;effects) = result
1,038,003✔
928
    if inbounds_option() === :off
1,854,784✔
929
        if !is_nothrow(effects)
×
930
            # Disable concrete evaluation in `--check-bounds=no` mode,
931
            # unless it is known to not throw.
932
            return :none
×
933
        end
934
    end
935
    if result.edge !== nothing && is_foldable(effects, #=check_rtcall=#true)
1,045,063✔
936
        if f !== nothing && is_all_const_arg(arginfo, #=start=#2)
18,887✔
937
            if (is_nonoverlayed(interp) || is_nonoverlayed(effects) ||
11,641✔
938
                # Even if overlay methods are involved, when `:consistent_overlay` is
939
                # explicitly applied, we can still perform concrete evaluation using the
940
                # original methods for executing them.
941
                # While there's a chance that the non-overlayed counterparts may raise
942
                # non-egal exceptions, it will not impact the compilation validity, since:
943
                # - the results of the concrete evaluation will not be inlined
944
                # - the exception types from the concrete evaluation will not be propagated
945
                is_consistent_overlay(effects))
946
                return :concrete_eval
11,671✔
947
            end
948
            # disable concrete-evaluation if this function call is tainted by some overlayed
949
            # method since currently there is no easy way to execute overlayed methods
950
            add_remark!(interp, sv, "[constprop] Concrete eval disabled for overlayed methods")
3✔
951
        end
952
        if !any_conditional(arginfo)
28,872✔
953
            if may_optimize(interp)
7,044✔
954
                return :semi_concrete_eval
526✔
955
            else
956
                # disable irinterp if optimization is disabled, since it requires optimized IR
957
                add_remark!(interp, sv, "[constprop] Semi-concrete interpretation disabled for non-optimizing interpreter")
6,670✔
958
            end
959
        end
960
    end
961
    return :none
1,025,806✔
962
end
963

964
is_all_const_arg(arginfo::ArgInfo, start::Int) = is_all_const_arg(arginfo.argtypes, start::Int)
18,887✔
965
function is_all_const_arg(argtypes::Vector{Any}, start::Int)
157,258✔
966
    for i = start:length(argtypes)
314,513✔
967
        argtype = widenslotwrapper(argtypes[i])
288,369✔
968
        is_const_argtype(argtype) || return false
329,273✔
969
    end
375,411✔
970
    return true
115,298✔
971
end
972

973
is_const_argtype(@nospecialize argtype) = isa(argtype, Const) || isconstType(argtype) || issingletontype(argtype)
329,387✔
974

975
any_conditional(argtypes::Vector{Any}) = any(@nospecialize(x)->isa(x, Conditional), argtypes)
50,548✔
976
any_conditional(arginfo::ArgInfo) = any_conditional(arginfo.argtypes)
28,872✔
977

978
collect_const_args(arginfo::ArgInfo, start::Int) = collect_const_args(arginfo.argtypes, start)
11,629✔
979
function collect_const_args(argtypes::Vector{Any}, start::Int)
115,298✔
980
    return Any[ let a = widenslotwrapper(argtypes[i])
115,322✔
981
                    isa(a, Const) ? a.val :
243,961✔
982
                    isconstType(a) ? a.parameters[1] :
983
                    (a::DataType).instance
984
                end for i = start:length(argtypes) ]
985
end
986

987
function concrete_eval_call(interp::AbstractInterpreter,
11,629✔
988
    @nospecialize(f), result::MethodCallResult, arginfo::ArgInfo, ::AbsIntState,
989
    invokecall::Union{InvokeCall,Nothing}=nothing)
990
    args = collect_const_args(arginfo, #=start=#2)
11,629✔
991
    if invokecall !== nothing
11,629✔
992
        # this call should be `invoke`d, rewrite `args` back now
993
        pushfirst!(args, f, invokecall.types)
×
994
        f = invoke
×
995
    end
996
    world = get_inference_world(interp)
11,629✔
997
    edge = result.edge::CodeInstance
11,629✔
998
    value = try
11,629✔
999
        Core._call_in_world_total(world, f, args...)
11,629✔
1000
    catch
1001
        # The evaluation threw. By :consistent-cy, we're guaranteed this would have happened at runtime.
1002
        # Howevever, at present, :consistency does not mandate the type of the exception
1003
        concrete_result = ConcreteResult(edge, result.effects)
3✔
1004
        return ConstCallResult(Bottom, Any, concrete_result, result.effects, #=const_edge=#nothing)
3✔
1005
    end
1006
    concrete_result = ConcreteResult(edge, EFFECTS_TOTAL, value)
11,626✔
1007
    return ConstCallResult(Const(value), Bottom, concrete_result, EFFECTS_TOTAL, #=const_edge=#nothing)
11,626✔
1008
end
1009

1010
# check if there is a cycle and duplicated inference of `mi`
1011
function is_constprop_recursed(result::MethodCallResult, mi::MethodInstance, sv::AbsIntState)
172,287✔
1012
    result.edgecycle || return false
344,536✔
1013
    if result.edgelimited
38✔
1014
        return is_constprop_method_recursed(mi.def::Method, sv)
6✔
1015
    else
1016
        # if the type complexity limiting didn't decide to limit the call signature (as
1017
        # indicated by `result.edgelimited === false`), we can relax the cycle detection
1018
        # by comparing `MethodInstance`s and allow inference to propagate different
1019
        # constant elements if the recursion is finite over the lattice
1020
        return is_constprop_edge_recursed(mi, sv)
32✔
1021
    end
1022
end
1023

1024
# if there's a possibility we could get a better result with these constant arguments
1025
# (hopefully without doing too much work), returns `MethodInstance`, or nothing otherwise
1026
function maybe_get_const_prop_profitable(interp::AbstractInterpreter,
1,025,763✔
1027
    result::MethodCallResult, @nospecialize(f), arginfo::ArgInfo, si::StmtInfo,
1028
    match::MethodMatch, sv::AbsIntState)
1029
    method = match.method
1,025,763✔
1030
    force = force_const_prop(interp, f, method)
1,025,763✔
1031
    if !const_prop_rettype_heuristic(interp, result, si, sv, force)
2,047,990✔
1032
        # N.B. remarks are emitted within `const_prop_rettype_heuristic`
1033
        return nothing
73,312✔
1034
    end
1035
    if !const_prop_argument_heuristic(interp, arginfo, sv)
952,757✔
1036
        add_remark!(interp, sv, "[constprop] Disabled by argument heuristics")
352,592✔
1037
        return nothing
352,592✔
1038
    end
1039
    all_overridden = is_all_overridden(interp, arginfo, sv)
599,859✔
1040
    if !force && !const_prop_function_heuristic(interp, f, arginfo, all_overridden, sv)
599,859✔
1041
        add_remark!(interp, sv, "[constprop] Disabled by function heuristic")
70,754✔
1042
        return nothing
70,754✔
1043
    end
1044
    force |= all_overridden
529,105✔
1045
    mi = specialize_method(match; preexisting=!force)
928,735✔
1046
    if mi === nothing
529,105✔
1047
        add_remark!(interp, sv, "[constprop] Failed to specialize")
×
1048
        return nothing
×
1049
    end
1050
    mi = mi::MethodInstance
529,105✔
1051
    inf_result = result.call_result
529,105✔
1052
    inf_result = inf_result isa InferenceResult ? inf_result : nothing
529,105✔
1053
    if !force && !const_prop_methodinstance_heuristic(interp, inf_result, mi, arginfo, sv)
606,344✔
1054
        add_remark!(interp, sv, "[constprop] Disabled by method instance heuristic")
66,082✔
1055
        return nothing
66,082✔
1056
    end
1057
    return mi
463,023✔
1058
end
1059

1060
function const_prop_rettype_heuristic(interp::AbstractInterpreter, result::MethodCallResult,
3,465✔
1061
                                      si::StmtInfo, sv::AbsIntState, force::Bool)
1062
    rt = result.rt
1,025,748✔
1063
    if rt isa LimitedAccuracy
1,025,748✔
1064
        # optimizations like inlining are disabled for limited frames,
1065
        # thus there won't be much benefit in constant-prop' here
1066
        # N.B. don't allow forced constprop' for safety (xref #52763)
1067
        add_remark!(interp, sv, "[constprop] Disabled by rettype heuristic (limited accuracy)")
56✔
1068
        return false
56✔
1069
    elseif force
1,025,692✔
1070
        return true
213,095✔
1071
    elseif call_result_unused(si) && result.edgecycle
812,597✔
1072
        add_remark!(interp, sv, "[constprop] Disabled by rettype heuristic (edgecycle with unused result)")
1,446✔
1073
        return false
1,446✔
1074
    end
1075
    # check if this return type is improvable (i.e. whether it's possible that with more
1076
    # information, we might get a more precise type)
1077
    if isa(rt, Type)
811,151✔
1078
        # could always be improved to `Const`, `PartialStruct` or just a more precise type,
1079
        # unless we're already at `Bottom`
1080
        if rt === Bottom
680,783✔
1081
            add_remark!(interp, sv, "[constprop] Disabled by rettype heuristic (erroneous result)")
12,357✔
1082
            return false
12,357✔
1083
        end
1084
        return true
668,426✔
1085
    elseif isa(rt, PartialStruct) || isa(rt, InterConditional) || isa(rt, InterMustAlias)
231,106✔
1086
        # could be improved to `Const` or a more precise wrapper
1087
        return true
44,377✔
1088
    elseif isa(rt, Const)
85,991✔
1089
        if is_nothrow(result.effects)
85,991✔
1090
            add_remark!(interp, sv, "[constprop] Disabled by rettype heuristic (nothrow const)")
59,453✔
1091
            return false
59,453✔
1092
        end
1093
        # Could still be improved to Bottom (or at least could see the effects improved)
1094
        return true
26,538✔
1095
    else
1096
        add_remark!(interp, sv, "[constprop] Disabled by rettype heuristic (unimprovable result)")
×
1097
        return false
×
1098
    end
1099
end
1100

1101
# determines heuristically whether if constant propagation can be worthwhile
1102
# by checking if any of given `argtypes` is "interesting" enough to be propagated
1103
function const_prop_argument_heuristic(interp::AbstractInterpreter, arginfo::ArgInfo, sv::AbsIntState)
834,573✔
1104
    ๐•ƒแตข = typeinf_lattice(interp)
834,573✔
1105
    argtypes = arginfo.argtypes
834,573✔
1106
    for i in 1:length(argtypes)
1,048,659✔
1107
        a = argtypes[i]
2,223,041✔
1108
        if has_conditional(๐•ƒแตข, sv) && isa(a, Conditional) && arginfo.fargs !== nothing
2,223,041✔
1109
            is_const_prop_profitable_conditional(a, arginfo.fargs, sv) && return true
8,924✔
1110
        else
1111
            a = widenslotwrapper(a)
2,216,959✔
1112
            has_nontrivial_extended_info(๐•ƒแตข, a) && is_const_prop_profitable_arg(๐•ƒแตข, a) && return true
2,216,959✔
1113
        end
1114
    end
3,129,528✔
1115
    return false
352,592✔
1116
end
1117

1118
function is_const_prop_profitable_conditional(cnd::Conditional, fargs::Vector{Any}, sv::InferenceState)
1119
    slotid = find_constrained_arg(cnd, fargs, sv)
27,821✔
1120
    if slotid !== nothing
9,115✔
1121
        return true
5,730✔
1122
    end
1123
    # as a minor optimization, we just check the result is a constant or not,
1124
    # since both `has_nontrivial_extended_info`/`is_const_prop_profitable_arg` return `true`
1125
    # for `Const(::Bool)`
1126
    return isa(widenconditional(cnd), Const)
3,385✔
1127
end
1128

1129
function find_constrained_arg(cnd::Conditional, fargs::Vector{Any}, sv::InferenceState)
1130
    slot = cnd.slot
9,306✔
1131
    for i in 1:length(fargs)
9,678✔
1132
        arg = ssa_def_slot(fargs[i], sv)
25,128✔
1133
        if isa(arg, SlotNumber) && slot_id(arg) == slot
25,128✔
1134
            return i
5,921✔
1135
        end
1136
    end
35,029✔
1137
    return nothing
3,385✔
1138
end
1139

1140
# checks if all argtypes has additional information other than what `Type` can provide
1141
function is_all_overridden(interp::AbstractInterpreter, (; fargs, argtypes)::ArgInfo, sv::AbsIntState)
599,859✔
1142
    ๐•ƒแตข = typeinf_lattice(interp)
599,859✔
1143
    for i in 1:length(argtypes)
781,502✔
1144
        a = argtypes[i]
1,470,213✔
1145
        if has_conditional(๐•ƒแตข, sv) && isa(a, Conditional) && fargs !== nothing
1,470,213✔
1146
            is_const_prop_profitable_conditional(a, fargs, sv) || return false
3,261✔
1147
        else
1148
            is_forwardable_argtype(๐•ƒแตข, widenslotwrapper(a)) || return false
1,467,180✔
1149
        end
1150
    end
1,996,534✔
1151
    return true
255,826✔
1152
end
1153

1154
function force_const_prop(interp::AbstractInterpreter, @nospecialize(f), method::Method)
1,025,763✔
1155
    return is_aggressive_constprop(method) ||
1,025,763✔
1156
           InferenceParams(interp).aggressive_constant_propagation ||
1157
           typename(typeof(f)).constprop_heuristic === Core.FORCE_CONST_PROP
1158
end
1159

1160
function const_prop_function_heuristic(interp::AbstractInterpreter, @nospecialize(f),
387,573✔
1161
    arginfo::ArgInfo, all_overridden::Bool, sv::AbsIntState)
1162
    argtypes = arginfo.argtypes
387,573✔
1163
    heuristic = typename(typeof(f)).constprop_heuristic
387,573✔
1164
    if length(argtypes) > 1
387,573✔
1165
        ๐•ƒแตข = typeinf_lattice(interp)
387,400✔
1166
        if heuristic === Core.ARRAY_INDEX_HEURISTIC
387,400✔
1167
            arrty = argtypes[2]
21,287✔
1168
            # don't propagate constant index into indexing of non-constant array
1169
            if arrty isa Type && arrty <: AbstractArray && !issingletontype(arrty)
21,287✔
1170
                # For static arrays, allow the constprop if we could possibly
1171
                # deduce nothrow as a result.
1172
                still_nothrow = isa(sv, InferenceState) ? is_nothrow(sv.ipo_effects) : false
4,612✔
1173
                if !still_nothrow || ismutabletype(arrty)
6,088✔
1174
                    return false
4,604✔
1175
                end
1176
            elseif โŠ‘(๐•ƒแตข, arrty, Array) || โŠ‘(๐•ƒแตข, arrty, GenericMemory)
33,332✔
1177
                return false
18✔
1178
            end
1179
        elseif heuristic === Core.ITERATE_HEURISTIC
366,113✔
1180
            itrty = argtypes[2]
40,130✔
1181
            if โŠ‘(๐•ƒแตข, itrty, Array) || โŠ‘(๐•ƒแตข, itrty, GenericMemory)
80,042✔
1182
                return false
224✔
1183
            end
1184
        end
1185
    end
1186
    if !all_overridden && heuristic === Core.SAMETYPE_HEURISTIC
382,727✔
1187
        # it is almost useless to inline the op when all the same type,
1188
        # but highly worthwhile to inline promote of a constant
1189
        length(argtypes) > 2 || return false
76,062✔
1190
        t1 = widenconst(argtypes[2])
76,062✔
1191
        for i in 3:length(argtypes)
79,308✔
1192
            at = argtypes[i]
76,430✔
1193
            ty = isvarargtype(at) ? unwraptv(at) : widenconst(at)
152,860✔
1194
            if ty !== t1
76,430✔
1195
                return true
10,154✔
1196
            end
1197
        end
66,644✔
1198
        return false
65,908✔
1199
    end
1200
    return true
306,665✔
1201
end
1202

1203
# This is a heuristic to avoid trying to const prop through complicated functions
1204
# where we would spend a lot of time, but are probably unlikely to get an improved
1205
# result anyway.
1206
function const_prop_methodinstance_heuristic(interp::AbstractInterpreter,
1207
    inf_result::Union{InferenceResult,Nothing}, mi::MethodInstance, arginfo::ArgInfo, sv::AbsIntState)
1208
    method = mi.def::Method
342,225✔
1209
    if method.is_for_opaque_closure
342,225✔
1210
        # Not inlining an opaque closure can be very expensive, so be generous
1211
        # with the const-prop-ability. It is quite possible that we can't infer
1212
        # anything at all without const-propping, so the inlining check below
1213
        # isn't particularly helpful here.
1214
        return true
×
1215
    end
1216
    # now check if the source of this method instance is inlineable, since the extended type
1217
    # information we have here would be discarded if it is not inlined into a callee context
1218
    # (modulo the inferred return type that can be potentially refined)
1219
    if is_declared_inline(method)
684,339✔
1220
        # this method is declared as `@inline` and will be inlined
1221
        return true
61,749✔
1222
    end
1223
    flag = get_curr_ssaflag(sv)
280,476✔
1224
    if is_stmt_inline(flag)
280,476✔
1225
        # force constant propagation for a call that is going to be inlined
1226
        # since the inliner will try to find this constant result
1227
        # if these constant arguments arrive there
1228
        return true
103✔
1229
    elseif is_stmt_noinline(flag)
280,373✔
1230
        # this call won't be inlined, thus this constant-prop' will most likely be unfruitful
1231
        return false
63✔
1232
    else
1233
        # Peek at the inferred result for the method to determine if the optimizer
1234
        # was able to cut it down to something simple (inlineable in particular).
1235
        # If so, there will be a good chance we might be able to const prop
1236
        # all the way through and learn something new.
1237
        if inf_result isa InferenceResult
280,199✔
1238
            inferred = inf_result.src
227,135✔
1239
            # TODO propagate a specific `CallInfo` that conveys information about this call
1240
            if src_inlining_policy(interp, mi, inferred, NoCallInfo(), IR_FLAG_NULL)
227,135✔
1241
                return true
209,002✔
1242
            end
1243
        end
1244
    end
1245
    return false # the cache isn't inlineable, so this constant-prop' will most likely be unfruitful
71,308✔
1246
end
1247

1248
function semi_concrete_eval_call(interp::AbstractInterpreter,
97✔
1249
    mi::MethodInstance, result::MethodCallResult, arginfo::ArgInfo, sv::AbsIntState)
1250
    call_result = result.call_result
97✔
1251
    call_result isa InferenceResult || return nothing
97✔
1252
    codeinst = call_result.ci
97✔
1253
    codeinst isa CodeInstance || return nothing
97✔
1254
    inferred = call_result.src
97✔
1255
    src_inlining_policy(interp, mi, inferred, NoCallInfo(), IR_FLAG_NULL) || return nothing # hack to work-around test failures caused by #58183 until both it and #48913 are fixed
97✔
1256
    irsv = IRInterpretationState(interp, codeinst, mi, arginfo.argtypes, inferred)
97✔
1257
    irsv === nothing && return nothing
97✔
1258
    assign_parentchild!(irsv, sv)
97✔
1259
    rt, (nothrow, noub) = ir_abstract_constant_propagation(interp, irsv)
97✔
1260
    @assert !(rt isa Conditional || rt isa MustAlias) "invalid lattice element returned from irinterp"
97✔
1261
    if !(isa(rt, Type) && hasintersect(rt, Bool))
97✔
1262
        ir = irsv.ir
85✔
1263
        # TODO (#48913) enable double inlining pass when there are any calls
1264
        # that are newly resolved by irinterp
1265
        # state = InliningState(interp)
1266
        # ir = ssa_inlining_pass!(irsv.ir, state, propagate_inbounds(irsv))
1267
        effects = result.effects
85✔
1268
        if nothrow
85✔
1269
            effects = Effects(effects; nothrow=true)
70✔
1270
        end
1271
        if noub
85✔
1272
            effects = Effects(effects; noub=ALWAYS_TRUE)
76✔
1273
        end
1274
        exct = refine_exception_type(result.exct, effects)
97✔
1275
        # TODO: SemiConcreteResult fails to preserve the ci_as_edge value
1276
        semi_concrete_result = SemiConcreteResult(codeinst, ir, effects, spec_info(irsv))
85✔
1277
        const_edge = nothing # TODO use the edges from irsv?
85✔
1278
        return ConstCallResult(rt, exct, semi_concrete_result, effects, const_edge)
85✔
1279
    end
1280
    nothing
12✔
1281
end
1282

1283
function const_prop_result(inf_result::InferenceResult)
1284
    @assert isdefined(inf_result, :ci_as_edge) "InferenceResult without ci_as_edge"
420,489✔
1285
    return ConstCallResult(inf_result.result, inf_result.exc_result, inf_result,
420,489✔
1286
                           inf_result.ipo_effects, inf_result.ci_as_edge)
1287
end
1288

1289
# return cached result of constant analysis
1290
return_localcache_result(::AbstractInterpreter, inf_result::InferenceResult, ::AbsIntState) =
229,196✔
1291
    const_prop_result(inf_result)
1292

1293
function compute_forwarded_argtypes(interp::AbstractInterpreter, arginfo::ArgInfo, sv::AbsIntState)
1294
    ๐•ƒแตข = typeinf_lattice(interp)
462,862✔
1295
    return has_conditional(๐•ƒแตข, sv) ? ConditionalSimpleArgtypes(arginfo, sv) : SimpleArgtypes(arginfo.argtypes)
462,942✔
1296
end
1297

1298
function const_prop_call(interp::AbstractInterpreter,
462,942✔
1299
    mi::MethodInstance, result::MethodCallResult, arginfo::ArgInfo, sv::AbsIntState,
1300
    concrete_eval_result::Union{Nothing,ConstCallResult}=nothing)
1301
    inf_cache = get_inference_cache(interp)
462,942✔
1302
    ๐•ƒแตข = typeinf_lattice(interp)
462,942✔
1303
    forwarded_argtypes = compute_forwarded_argtypes(interp, arginfo, sv)
462,942✔
1304
    # use `cache_argtypes` that has been constructed for fresh regular inference if available
1305
    call_result = result.call_result
462,942✔
1306
    if call_result isa InferenceResult
462,942✔
1307
        cache_argtypes = call_result.argtypes
215,233✔
1308
    else
1309
        cache_argtypes = matching_cache_argtypes(๐•ƒแตข, mi)
247,709✔
1310
    end
1311
    argtypes = matching_cache_argtypes(๐•ƒแตข, mi, forwarded_argtypes, cache_argtypes)
462,942✔
1312
    inf_result = constprop_cache_lookup(๐•ƒแตข, mi, argtypes, inf_cache)
462,942✔
1313
    if inf_result !== nothing
462,942✔
1314
        # found the cache for this constant prop'
1315
        if inf_result.result === nothing
229,196✔
1316
            add_remark!(interp, sv, "[constprop] Found cached constant inference in a cycle")
×
1317
            return nothing
×
1318
        end
1319
        @assert inf_result.linfo === mi "MethodInstance for cached inference result does not match"
229,196✔
1320
        return return_localcache_result(interp, inf_result, sv)
229,196✔
1321
    end
1322
    overridden_by_const = falses(length(argtypes))
233,746✔
1323
    for i = 1:length(argtypes)
338,712✔
1324
        if argtypes[i] !== argtype_by_index(cache_argtypes, i)
712,418✔
1325
            overridden_by_const[i] = true
298,521✔
1326
        end
1327
    end
1,191,090✔
1328
    if !any(overridden_by_const)
467,492✔
1329
        add_remark!(interp, sv, "[constprop] Could not handle constant info in matching_cache_argtypes")
42,453✔
1330
        return nothing
42,453✔
1331
    end
1332
    # perform fresh constant prop'
1333
    inf_result = InferenceResult(mi, argtypes, overridden_by_const)
191,293✔
1334
    frame = InferenceState(inf_result, #=cache_mode=#:local, interp) # TODO: this should also be converted to a stackless Future
382,586✔
1335
    if frame === nothing
191,293✔
1336
        add_remark!(interp, sv, "[constprop] Could not retrieve the source")
×
1337
        return nothing # this is probably a bad generated function (unsound), but just ignore it
×
1338
    end
1339
    assign_parentchild!(frame, sv)
191,293✔
1340
    if !typeinf(interp, frame)
191,293✔
1341
        sv.time_caches += frame.time_caches
×
1342
        sv.time_paused += frame.time_paused
×
1343
        add_remark!(interp, sv, "[constprop] Fresh constant inference hit a cycle")
×
1344
        @assert frame.frameid != 0 && frame.cycleid == frame.frameid
×
1345
        callstack = frame.callstack::Vector{AbsIntState}
×
1346
        @assert callstack[end] === frame && length(callstack) == frame.frameid
×
1347
        pop!(callstack)
×
1348
        # add to the cache to record that this will always fail
1349
        push!(get_inference_cache(interp), inf_result)
×
1350
        return nothing
×
1351
    end
1352
    existing_edge = result.edge
191,293✔
1353
    inf_result.ci_as_edge = codeinst_as_edge(interp, frame, existing_edge)
382,520✔
1354
    @assert frame.frameid != 0 && frame.cycleid == frame.frameid
191,293✔
1355
    @assert frame.parentid == sv.frameid
191,293✔
1356
    @assert inf_result.result !== nothing
191,293✔
1357
    # ConditionalSimpleArgtypes is allowed, because the only case in which it modifies
1358
    # the argtypes is when one of the argtypes is a `Conditional`, which case
1359
    # concrete_eval_result will not be available.
1360
    if concrete_eval_result !== nothing && isa(forwarded_argtypes, Union{SimpleArgtypes, ConditionalSimpleArgtypes})
191,293✔
1361
        # override return type and effects with concrete evaluation result if available
1362
        inf_result.result = concrete_eval_result.rt
×
1363
        inf_result.ipo_effects = concrete_eval_result.effects
×
1364
    end
1365
    return const_prop_result(inf_result)
191,293✔
1366
end
1367

1368
# TODO implement MustAlias forwarding
1369

1370
struct ConditionalSimpleArgtypes
1371
    arginfo::ArgInfo
462,942✔
1372
    sv::InferenceState
1373
end
1374

1375
function matching_cache_argtypes(๐•ƒ::AbstractLattice, mi::MethodInstance,
172,464✔
1376
                                 conditional_argtypes::ConditionalSimpleArgtypes,
1377
                                 cache_argtypes::Vector{Any})
1378
    (; arginfo, sv) = conditional_argtypes
172,464✔
1379
    (; fargs, argtypes) = arginfo
172,464✔
1380
    given_argtypes = Vector{Any}(undef, length(argtypes))
172,464✔
1381
    def = mi.def::Method
172,464✔
1382
    nargs = Int(def.nargs)
172,464✔
1383
    for i in 1:length(argtypes)
344,751✔
1384
        argtype = argtypes[i]
518,020✔
1385
        # forward `Conditional` if it conveys a constraint on any other argument
1386
        if isa(argtype, Conditional) && fargs !== nothing
518,020✔
1387
            cnd = argtype
191✔
1388
            slotid = find_constrained_arg(cnd, fargs, sv)
692✔
1389
            if slotid !== nothing
191✔
1390
                # using union-split signature, we may be able to narrow down `Conditional`
1391
                sigt = widenconst(slotid > nargs ? argtypes[slotid] : cache_argtypes[slotid])
191✔
1392
                โŠ“ = meet(๐•ƒ)
191✔
1393
                thentype = cnd.thentype โŠ“ sigt
191✔
1394
                elsetype = cnd.elsetype โŠ“ sigt
191✔
1395
                if thentype === Bottom && elsetype === Bottom
191✔
1396
                    # we accidentally proved this method match is impossible
1397
                    # TODO bail out here immediately rather than just propagating Bottom ?
1398
                    given_argtypes[i] = Bottom
×
1399
                else
1400
                    given_argtypes[i] = Conditional(slotid, thentype, elsetype)
191✔
1401
                end
1402
                continue
191✔
1403
            end
1404
        end
1405
        given_argtypes[i] = widenslotwrapper(argtype)
517,829✔
1406
    end
863,576✔
1407
    return pick_const_args!(๐•ƒ, given_argtypes, cache_argtypes)
172,464✔
1408
end
1409

1410
# This is only for use with `Conditional`.
1411
# In general, usage of this is wrong.
1412
function ssa_def_slot(@nospecialize(arg), sv::InferenceState)
148,049✔
1413
    code = sv.src.code
148,049✔
1414
    init = sv.currpc
148,049✔
1415
    while isa(arg, SSAValue)
237,109✔
1416
        init = arg.id
89,060✔
1417
        arg = code[init]
89,060✔
1418
    end
89,060✔
1419
    if arg isa SlotNumber
148,049✔
1420
        # found this kind of pattern:
1421
        # %init = SlotNumber(x)
1422
        # [...]
1423
        # goto if not isa(%init, T)
1424
        # now conservatively make sure there isn't potentially another conflicting assignment
1425
        # to the same slot between the def and usage
1426
        # we can assume the IR is sorted, since the front-end only creates SSA values in order
1427
        for i = init:(sv.currpc-1)
55,267✔
1428
            e = code[i]
11,454✔
1429
            if isexpr(e, :(=)) && e.args[1] === arg
11,454✔
1430
                return nothing
×
1431
            end
1432
        end
16,923✔
1433
    else
1434
        # there might still be the following kind of pattern (see #45499):
1435
        # %init = ...
1436
        # [...]
1437
        # SlotNumber(x) = %init
1438
        # [...]
1439
        # goto if not isa(%init, T)
1440
        # let's check if there is a slot assigned to the def SSA value but also there isn't
1441
        # any potentially conflicting assignment to the same slot
1442
        arg = nothing
98,767✔
1443
        def = SSAValue(init)
98,767✔
1444
        for i = (init+1):(sv.currpc-1)
111,571✔
1445
            e = code[i]
38,594✔
1446
            if isexpr(e, :(=))
38,594✔
1447
                lhs = e.args[1]
44✔
1448
                if isa(lhs, SlotNumber)
44✔
1449
                    lhs === arg && return nothing
44✔
1450
                    rhs = e.args[2]
44✔
1451
                    if rhs === def
44✔
1452
                        arg = lhs
6✔
1453
                    end
1454
                end
1455
            end
1456
        end
38,594✔
1457
    end
1458
    return arg
148,049✔
1459
end
1460

1461
# No slots in irinterp
1462
ssa_def_slot(@nospecialize(arg), ::IRInterpretationState) = nothing
×
1463

1464
struct AbstractIterationResult
1465
    cti::Vector{Any}
51,554✔
1466
    info::MaybeAbstractIterationInfo
1467
    ai_effects::Effects
1468
end
1469
AbstractIterationResult(cti::Vector{Any}, info::MaybeAbstractIterationInfo) =
51,545✔
1470
    AbstractIterationResult(cti, info, EFFECTS_TOTAL)
1471

1472
# `typ` is the inferred type for expression `arg`.
1473
# if the expression constructs a container (e.g. `svec(x,y,z)`),
1474
# refine its type to an array of element types.
1475
# Union of Tuples of the same length is converted to Tuple of Unions.
1476
# returns an array of types
1477
function precise_container_type(interp::AbstractInterpreter, @nospecialize(itft), @nospecialize(typ),
41,609✔
1478
                                sv::AbsIntState)
1479
    if isa(typ, PartialStruct)
41,609✔
1480
        widet = typ.typ
7,042✔
1481
        if isa(widet, DataType)
7,042✔
1482
            if widet.name === Tuple.name
7,042✔
1483
                return Future(AbstractIterationResult(typ.fields, nothing))
1,922✔
1484
            elseif widet.name === _NAMEDTUPLE_NAME
5,120✔
1485
                return Future(AbstractIterationResult(typ.fields, nothing))
×
1486
            end
1487
        end
1488
    end
1489

1490
    if isa(typ, Const)
39,687✔
1491
        val = typ.val
15,497✔
1492
        if isa(val, SimpleVector) || isa(val, Tuple) || isa(val, NamedTuple)
30,988✔
1493
            return Future(AbstractIterationResult(Any[ Const(val[i]) for i in 1:length(val) ], nothing)) # avoid making a tuple Generator here!
10,374✔
1494
        end
1495
    end
1496

1497
    tti0 = widenconst(typ)
29,313✔
1498
    tti = unwrap_unionall(tti0)
29,313✔
1499
    if isa(tti, DataType) && tti.name === _NAMEDTUPLE_NAME
29,313✔
1500
        # A NamedTuple iteration is the same as the iteration of its Tuple parameter:
1501
        # compute a new `tti == unwrap_unionall(tti0)` based on that Tuple type
1502
        tti = unwraptv(tti.parameters[2])
18✔
1503
        tti0 = rewrap_unionall(tti, tti0)
18✔
1504
    end
1505
    if isa(tti, Union)
29,313✔
1506
        utis = uniontypes(tti)
×
1507
        # refine the Union to remove elements that are not valid tags for objects
1508
        filter!(@nospecialize(x) -> valid_as_lattice(x, true), utis)
×
1509
        if length(utis) == 0
×
1510
            return Future(AbstractIterationResult(Any[], nothing)) # oops, this statement was actually unreachable
×
1511
        elseif length(utis) == 1
×
1512
            tti = utis[1]
×
1513
            tti0 = rewrap_unionall(tti, tti0)
×
1514
        else
1515
            if any(@nospecialize(t) -> !isa(t, DataType) || !(t <: Tuple) || !isknownlength(t), utis)
×
1516
                return Future(AbstractIterationResult(Any[Vararg{Any}], nothing, Effects()))
×
1517
            end
1518
            ltp = length((utis[1]::DataType).parameters)
×
1519
            for t in utis
×
1520
                if length((t::DataType).parameters) != ltp
×
1521
                    return Future(AbstractIterationResult(Any[Vararg{Any}], nothing))
×
1522
                end
1523
            end
×
1524
            result = Any[ Union{} for _ in 1:ltp ]
×
1525
            for t in utis
×
1526
                tps = (t::DataType).parameters
×
1527
                for j in 1:ltp
×
1528
                    @assert valid_as_lattice(tps[j], true)
×
1529
                    result[j] = tmerge(result[j], rewrap_unionall(tps[j], tti0))
×
1530
                end
×
1531
            end
×
1532
            return Future(AbstractIterationResult(result, nothing))
×
1533
        end
1534
    end
1535
    if tti0 <: Tuple
29,313✔
1536
        if isa(tti0, DataType)
18,550✔
1537
            return Future(AbstractIterationResult(Any[ p for p in tti0.parameters ], nothing))
18,550✔
1538
        elseif !isa(tti, DataType)
×
1539
            return Future(AbstractIterationResult(Any[Vararg{Any}], nothing))
×
1540
        else
1541
            len = length(tti.parameters)
×
1542
            last = tti.parameters[len]
×
1543
            va = isvarargtype(last)
×
1544
            elts = Any[ fieldtype(tti0, i) for i = 1:len ]
×
1545
            if va
×
1546
                if elts[len] === Union{}
×
1547
                    pop!(elts)
×
1548
                else
1549
                    elts[len] = Vararg{elts[len]}
×
1550
                end
1551
            end
1552
            return Future(AbstractIterationResult(elts, nothing))
×
1553
        end
1554
    elseif tti0 === SimpleVector
10,763✔
1555
        return Future(AbstractIterationResult(Any[Vararg{Any}], nothing))
72✔
1556
    elseif tti0 === Any
10,691✔
1557
        return Future(AbstractIterationResult(Any[Vararg{Any}], nothing, Effects()))
6✔
1558
    elseif tti0 <: Array || tti0 <: GenericMemory
21,007✔
1559
        if eltype(tti0) === Union{}
369✔
1560
            return Future(AbstractIterationResult(Any[], nothing))
6✔
1561
        end
1562
        return Future(AbstractIterationResult(Any[Vararg{eltype(tti0)}], nothing))
363✔
1563
    else
1564
        return abstract_iteration(interp, itft, typ, sv)
10,316✔
1565
    end
1566
end
1567

1568
# simulate iteration protocol on container type up to fixpoint
1569
function abstract_iteration(interp::AbstractInterpreter, @nospecialize(itft), @nospecialize(itertype), sv::AbsIntState)
10,316✔
1570
    if isa(itft, Const)
10,316✔
1571
        iteratef = itft.val
10,316✔
1572
    else
1573
        return Future(AbstractIterationResult(Any[Vararg{Any}], nothing, Effects()))
×
1574
    end
1575
    @assert !isvarargtype(itertype)
10,316✔
1576

1577
    iterateresult = Future{AbstractIterationResult}()
10,316✔
1578
    call1future = abstract_call_known(interp, iteratef, ArgInfo(nothing, Any[itft, itertype]), StmtInfo(true, false), sv)::Future
20,632✔
1579
    function inferiterate(interp, sv)
20,632✔
1580
        call1 = call1future[]
20,632✔
1581
        stateordonet = call1.rt
10,316✔
1582
        # Return Bottom if this is not an iterator.
1583
        # WARNING: Changes to the iteration protocol must be reflected here,
1584
        # this is not just an optimization.
1585
        # TODO: this doesn't realize that Array, GenericMemory, SimpleVector, Tuple, and NamedTuple do not use the iterate protocol
1586
        if stateordonet === Bottom
10,316✔
1587
            iterateresult[] = AbstractIterationResult(Any[Bottom], AbstractIterationInfo(CallMeta[CallMeta(Bottom, Any, call1.effects, call1.info)], true))
×
1588
            return true
×
1589
        end
1590
        stateordonet_widened = widenconst(stateordonet)
10,316✔
1591
        calls = CallMeta[call1]
10,316✔
1592
        valtype = statetype = Bottom
10,316✔
1593
        ret = Any[]
10,316✔
1594
        ๐•ƒแตข = typeinf_lattice(interp)
10,316✔
1595
        may_have_terminated = false
10,316✔
1596
        local call2future::Future{CallMeta}
1597

1598
        nextstate::UInt8 = 0x0
10,316✔
1599
        function inferiterate_2arg(interp, sv)
41,133✔
1600
            if nextstate === 0x1
20,501✔
1601
                nextstate = 0xff
187✔
1602
                @goto state1
187✔
1603
            elseif nextstate === 0x2
20,314✔
1604
                nextstate = 0xff
53✔
1605
                @goto state2
53✔
1606
            else
1607
                @assert nextstate === 0x0
20,261✔
1608
                nextstate = 0xff
20,261✔
1609
            end
1610

1611
            # Try to unroll the iteration up to max_tuple_splat, which covers any finite
1612
            # length iterators, or interesting prefix
1613
            while true
58,310✔
1614
                if stateordonet_widened === Nothing
58,310✔
1615
                    iterateresult[] = AbstractIterationResult(ret, AbstractIterationInfo(calls, true))
19,394✔
1616
                    return true
19,394✔
1617
                end
1618
                if Nothing <: stateordonet_widened || length(ret) >= InferenceParams(interp).max_tuple_splat
76,990✔
1619
                    break
864✔
1620
                end
1621
                if !isa(stateordonet_widened, DataType) || !(stateordonet_widened <: Tuple) || isvatuple(stateordonet_widened) || length(stateordonet_widened.parameters) != 2
76,104✔
1622
                    break
×
1623
                end
1624
                nstatetype = getfield_tfunc(๐•ƒแตข, stateordonet, Const(2))
76,104✔
1625
                # If there's no new information in this statetype, don't bother continuing,
1626
                # the iterator won't be finite.
1627
                if โŠ‘(๐•ƒแตข, nstatetype, statetype)
38,052✔
1628
                    iterateresult[] = AbstractIterationResult(Any[Bottom], AbstractIterationInfo(calls, false), EFFECTS_THROWS)
3✔
1629
                    return true
3✔
1630
                end
1631
                valtype = getfield_tfunc(๐•ƒแตข, stateordonet, Const(1))
76,098✔
1632
                push!(ret, valtype)
38,049✔
1633
                statetype = nstatetype
38,049✔
1634
                call2future = abstract_call_known(interp, iteratef, ArgInfo(nothing, Any[Const(iteratef), itertype, statetype]), StmtInfo(true, false), sv)::Future
76,098✔
1635
                if !isready(call2future)
76,098✔
1636
                    nextstate = 0x1
187✔
1637
                    return false
187✔
1638
                    @label state1
1639
                end
1640
                let call = call2future[]
76,098✔
1641
                    push!(calls, call)
38,049✔
1642
                    stateordonet = call.rt
38,049✔
1643
                    stateordonet_widened = widenconst(stateordonet)
38,049✔
1644
                end
1645
            end
38,049✔
1646
            # From here on, we start asking for results on the widened types, rather than
1647
            # the precise (potentially const) state type
1648
            # statetype and valtype are reinitialized in the first iteration below from the
1649
            # (widened) stateordonet, which has not yet been fully analyzed in the loop above
1650
            valtype = statetype = Bottom
864✔
1651
            may_have_terminated = Nothing <: stateordonet_widened
864✔
1652
            while valtype !== Any
1,730✔
1653
                nounion = typeintersect(stateordonet_widened, Tuple{Any,Any})
1,053✔
1654
                if nounion !== Union{} && !isa(nounion, DataType)
1,053✔
1655
                    # nounion is of a type we cannot handle
1656
                    valtype = Any
×
1657
                    break
×
1658
                end
1659
                if nounion === Union{} || (nounion.parameters[1] <: valtype && nounion.parameters[2] <: statetype)
2,104✔
1660
                    # reached a fixpoint or iterator failed/gave invalid answer
1661
                    if !hasintersect(stateordonet_widened, Nothing)
187✔
1662
                        # ... but cannot terminate
1663
                        if may_have_terminated
4✔
1664
                            # ... and iterator may have terminated prior to this loop, but not during it
1665
                            valtype = Bottom
4✔
1666
                        else
1667
                            #  ... or cannot have terminated prior to this loop
1668
                            iterateresult[] = AbstractIterationResult(Any[Bottom], AbstractIterationInfo(calls, false), Effects())
×
1669
                            return true
×
1670
                        end
1671
                    end
1672
                    break
187✔
1673
                end
1674
                valtype = tmerge(valtype, nounion.parameters[1])
866✔
1675
                statetype = tmerge(statetype, nounion.parameters[2])
866✔
1676
                call2future = abstract_call_known(interp, iteratef, ArgInfo(nothing, Any[Const(iteratef), itertype, statetype]), StmtInfo(true, false), sv)::Future
1,732✔
1677
                if !isready(call2future)
1,069✔
1678
                    nextstate = 0x2
53✔
1679
                    return false
53✔
1680
                    @label state2
1681
                end
1682
                let call = call2future[]
1,069✔
1683
                    push!(calls, call)
866✔
1684
                    stateordonet = call.rt
866✔
1685
                    stateordonet_widened = widenconst(stateordonet)
866✔
1686
                end
1687
            end
866✔
1688
            if valtype !== Union{}
864✔
1689
                push!(ret, Vararg{valtype})
860✔
1690
            end
1691
            iterateresult[] = AbstractIterationResult(ret, AbstractIterationInfo(calls, false))
864✔
1692
            return true
864✔
1693
        end # function inferiterate_2arg
1694
        # continue making progress as much as possible, on iterate(arg, state)
1695
        inferiterate_2arg(interp, sv) || push!(sv.tasks, inferiterate_2arg)
10,322✔
1696
        return true
10,316✔
1697
    end # inferiterate
1698
    # continue making progress as soon as possible, on iterate(arg)
1699
    if !(isready(call1future) && inferiterate(interp, sv))
20,632✔
1700
        push!(sv.tasks, inferiterate)
25✔
1701
    end
1702
    return iterateresult
10,316✔
1703
end
1704

1705
# do apply(af, fargs...), where af is a function value
1706
function abstract_apply(interp::AbstractInterpreter, argtypes::Vector{Any}, si::StmtInfo,
23,345✔
1707
                        sv::AbsIntState, max_methods::Int=get_max_methods(interp, sv))
1708
    itft = Core.Box(argtype_by_index(argtypes, 2))
23,345✔
1709
    aft = argtype_by_index(argtypes, 3)
23,345✔
1710
    (itft.contents === Bottom || aft === Bottom) && return Future(CallMeta(Bottom, Any, EFFECTS_THROWS, NoCallInfo()))
23,345✔
1711
    aargtypes = argtype_tail(argtypes, 4)
46,690✔
1712
    aftw = widenconst(aft)
23,345✔
1713
    if !isa(aft, Const) && !isa(aft, PartialOpaque) && (!isType(aftw) || has_free_typevars(aftw))
23,345✔
1714
        if !isconcretetype(aftw) || (aftw <: Builtin)
314✔
1715
            add_remark!(interp, sv, "Core._apply_iterate called on a function of a non-concrete type")
6✔
1716
            # bail now, since it seems unlikely that abstract_call will be able to do any better after splitting
1717
            # this also ensures we don't call abstract_call_gf_by_type below on an IntrinsicFunction or Builtin
1718
            return Future(CallMeta(Any, Any, Effects(), NoCallInfo()))
6✔
1719
        end
1720
    end
1721
    res = Union{}
23,339✔
1722
    splitunions = 1 < unionsplitcost(typeinf_lattice(interp), aargtypes) <= InferenceParams(interp).max_apply_union_enum
23,339✔
1723
    ctypes::Vector{Vector{Any}} = [Any[aft]]
23,339✔
1724
    infos::Vector{Vector{MaybeAbstractIterationInfo}} = Vector{MaybeAbstractIterationInfo}[MaybeAbstractIterationInfo[]]
23,339✔
1725
    all_effects::Effects = EFFECTS_TOTAL
23,339✔
1726
    retinfos = ApplyCallInfo[]
23,339✔
1727
    retinfo = UnionSplitApplyCallInfo(retinfos)
23,339✔
1728
    exctype = Union{}
23,339✔
1729
    ctypesยด::Vector{Vector{Any}} = Vector{Any}[]
23,339✔
1730
    infosยด::Vector{Vector{MaybeAbstractIterationInfo}} = Vector{MaybeAbstractIterationInfo}[]
23,339✔
1731
    local ti, argtypesi
1732
    local ctfuture::Future{AbstractIterationResult}
1733
    local callfuture::Future{CallMeta}
1734

1735
    applyresult = Future{CallMeta}()
23,339✔
1736
    # split the rest into a resumable state machine
1737
    i::Int = 1
23,339✔
1738
    j::Int = 1
23,339✔
1739
    nextstate::UInt8 = 0x0
23,339✔
1740
    function infercalls(interp, sv)
52,840✔
1741
        # n.b. Remember that variables will lose their values across restarts,
1742
        # so be sure to manually hoist any values that must be preserved and do
1743
        # not rely on program order.
1744
        # This is a little more complex than the closure continuations often used elsewhere, but avoids needing to manage all of that indentation
1745
        if nextstate === 0x1
29,501✔
1746
            nextstate = 0xff
25✔
1747
            @goto state1
25✔
1748
        elseif nextstate === 0x2
29,476✔
1749
            nextstate = 0xff
×
1750
            @goto state2
×
1751
        elseif nextstate === 0x3
29,476✔
1752
            nextstate = 0xff
6,137✔
1753
            @goto state3
6,137✔
1754
        else
1755
            @assert nextstate === 0x0
23,339✔
1756
            nextstate = 0xff
23,339✔
1757
        end
1758
        while i <= length(aargtypes)
64,744✔
1759
            argtypesi = (splitunions ? uniontypes(aargtypes[i]) : Any[aargtypes[i]])
41,511✔
1760
            i += 1
41,405✔
1761
            j = 1
41,405✔
1762
            while j <= length(argtypesi)
83,014✔
1763
                ti = argtypesi[j]
41,609✔
1764
                j += 1
41,609✔
1765
                if !isvarargtype(ti)
41,609✔
1766
                    ctfuture = precise_container_type(interp, itft.contents, ti, sv)::Future
41,609✔
1767
                    if !isready(ctfuture)
51,925✔
1768
                        nextstate = 0x1
25✔
1769
                        return false
25✔
1770
                        @label state1
1771
                    end
1772
                    (;cti, info, ai_effects) = ctfuture[]
51,925✔
1773
                else
1774
                    ctfuture = precise_container_type(interp, itft.contents, unwrapva(ti), sv)::Future
×
1775
                    if !isready(ctfuture)
×
1776
                        nextstate = 0x2
×
1777
                        return false
×
1778
                        @label state2
1779
                    end
1780
                    (;cti, info, ai_effects) = ctfuture[]
×
1781
                    # We can't represent a repeating sequence of the same types,
1782
                    # so tmerge everything together to get one type that represents
1783
                    # everything.
1784
                    argt = cti[end]
×
1785
                    if isvarargtype(argt)
×
1786
                        argt = unwrapva(argt)
×
1787
                    end
1788
                    for k in 1:(length(cti)-1)
×
1789
                        argt = tmerge(argt, cti[k])
×
1790
                    end
×
1791
                    cti = Any[Vararg{argt}]
×
1792
                end
1793
                all_effects = merge_effects(all_effects, ai_effects)
83,212✔
1794
                if info !== nothing
41,609✔
1795
                    for call in info.each
10,316✔
1796
                        all_effects = merge_effects(all_effects, call.effects)
61,878✔
1797
                    end
30,942✔
1798
                end
1799
                if any(@nospecialize(t) -> t === Bottom, cti)
187,193✔
1800
                    continue
×
1801
                end
1802
                for k = 1:length(ctypes)
63,067✔
1803
                    ct = ctypes[k]
41,609✔
1804
                    if isvarargtype(ct[end])
41,609✔
1805
                        # This is vararg, we're not gonna be able to do any inlining,
1806
                        # drop the info
1807
                        info = nothing
27✔
1808
                        tail = tuple_tail_elem(typeinf_lattice(interp), unwrapva(ct[end]), cti)
27✔
1809
                        push!(ctypesยด, push!(ct[1:(end - 1)], tail))
54✔
1810
                    else
1811
                        push!(ctypesยด, append!(ct[:], cti))
41,582✔
1812
                    end
1813
                    push!(infosยด, push!(copy(infos[k]), info))
51,925✔
1814
                end
41,609✔
1815
            end
41,609✔
1816
            # swap for the new array and empty the temporary one
1817
            ctypesยด, ctypes = ctypes, ctypesยด
41,405✔
1818
            infosยด, infos = infos, infosยด
41,405✔
1819
            empty!(ctypesยด)
41,405✔
1820
            empty!(infosยด)
41,405✔
1821
        end
41,405✔
1822
        all_effects.nothrow || (exctype = Any)
23,351✔
1823

1824
        i = 1
23,339✔
1825
        while i <= length(ctypes)
46,828✔
1826
            ct = ctypes[i]
23,519✔
1827
            if bail_out_apply(interp, InferenceLoopState(res, all_effects), sv)
23,519✔
1828
                add_remark!(interp, sv, "_apply_iterate inference reached maximally imprecise information: bailing on analysis of more methods.")
30✔
1829
                # there is unanalyzed candidate, widen type and effects to the top
1830
                let retinfo = NoCallInfo() # NOTE this is necessary to prevent the inlining processing
30✔
1831
                    applyresult[] = CallMeta(Any, Any, Effects(), retinfo)
30✔
1832
                    return true
30✔
1833
                end
1834
            end
1835
            lct = length(ct)
23,489✔
1836
            # truncate argument list at the first Vararg
1837
            for k = 1:lct-1
34,561✔
1838
                cti = ct[k]
72,805✔
1839
                if isvarargtype(cti)
72,805✔
1840
                    ct[k] = tuple_tail_elem(typeinf_lattice(interp), unwrapva(cti), ct[(k+1):lct])
×
1841
                    resize!(ct, k)
×
1842
                    break
×
1843
                end
1844
            end
72,805✔
1845
            callfuture = abstract_call(interp, ArgInfo(nothing, ct), si, sv, max_methods)::Future
23,489✔
1846
            if !isready(callfuture)
44,314✔
1847
                nextstate = 0x3
6,137✔
1848
                return false
6,137✔
1849
                @label state3
1850
            end
1851
            let (; info, rt, exct, effects) = callfuture[]
44,314✔
1852
                push!(retinfos, ApplyCallInfo(info, infos[i]))
23,489✔
1853
                res = tmerge(typeinf_lattice(interp), res, rt)
46,978✔
1854
                exctype = tmerge(typeinf_lattice(interp), exctype, exct)
46,978✔
1855
                all_effects = merge_effects(all_effects, effects)
46,966✔
1856
            end
1857
            i += 1
23,489✔
1858
        end
23,489✔
1859
        # TODO: Add a special info type to capture all the iteration info.
1860
        # For now, only propagate info if we don't also union-split the iteration
1861
        applyresult[] = CallMeta(res, exctype, all_effects, retinfo)
23,309✔
1862
        return true
23,309✔
1863
    end # function infercalls
1864
    # start making progress on the first call
1865
    infercalls(interp, sv) || push!(sv.tasks, infercalls)
29,482✔
1866
    return applyresult
23,339✔
1867
end
1868

1869
function argtype_by_index(argtypes::Vector{Any}, i::Int)
1870
    n = length(argtypes)
1,279,280✔
1871
    na = argtypes[n]
1,279,280✔
1872
    if isvarargtype(na)
1,279,280✔
1873
        return i >= n ? unwrapva(na) : argtypes[i]
12✔
1874
    else
1875
        return i > n ? Bottom : argtypes[i]
1,279,268✔
1876
    end
1877
end
1878

1879
function argtype_tail(argtypes::Vector{Any}, i::Int)
1880
    n = length(argtypes)
23,809✔
1881
    if isvarargtype(argtypes[n]) && i > n
23,809✔
1882
        i = n
×
1883
    end
1884
    return argtypes[i:n]
47,618✔
1885
end
1886

1887
struct ConditionalTypes
1888
    thentype
1889
    elsetype
1890
    ConditionalTypes(thentype, elsetype) = (@nospecialize; new(thentype, elsetype))
24,658✔
1891
end
1892

1893
@inline function isa_condition(@nospecialize(xt), @nospecialize(ty), max_union_splitting::Int,
1894
    @nospecialize(rt))
1895
    if isa(rt, Const)
68,476✔
1896
        xt = widenslotwrapper(xt)
59,649✔
1897
        if rt.val === false
58,909✔
1898
            return ConditionalTypes(Bottom, xt)
10,272✔
1899
        elseif rt.val === true
48,637✔
1900
            return ConditionalTypes(xt, Bottom)
48,637✔
1901
        end
1902
    end
1903
    return isa_condition(xt, ty, max_union_splitting)
9,567✔
1904
end
1905
@inline function isa_condition(@nospecialize(xt), @nospecialize(ty), max_union_splitting::Int)
1906
    tty_ub, isexact_tty = instanceof_tfunc(ty, true)
9,624✔
1907
    tty = widenconst(xt)
9,624✔
1908
    if isexact_tty && !isa(tty_ub, TypeVar)
9,624✔
1909
        tty_lb = tty_ub # TODO: this would be wrong if !isexact_tty, but instanceof_tfunc doesn't preserve this info
1,600✔
1910
        if !has_free_typevars(tty_lb) && !has_free_typevars(tty_ub)
7,231✔
1911
            thentype = typeintersect(tty, tty_ub)
7,231✔
1912
            if iskindtype(tty_ub) && thentype !== Bottom
14,292✔
1913
                # `typeintersect` may be unable narrow down `Type`-type
1914
                thentype = tty_ub
949✔
1915
            end
1916
            valid_as_lattice(thentype, true) || (thentype = Bottom)
7,231✔
1917
            elsetype = typesubtract(tty, tty_lb, max_union_splitting)
7,231✔
1918
            return ConditionalTypes(thentype, elsetype)
7,231✔
1919
        end
1920
    end
1921
    return nothing
2,393✔
1922
end
1923

1924
@inline function egal_condition(c::Const, @nospecialize(xt), max_union_splitting::Int,
1925
    @nospecialize(rt))
1926
    thentype = c
3,681✔
1927
    elsetype = widenslotwrapper(xt)
39,397✔
1928
    if rt === Const(false)
39,241✔
1929
        thentype = Bottom
2,660✔
1930
    elseif rt === Const(true)
30,135✔
1931
        elsetype = Bottom
696✔
1932
    elseif elsetype isa Type && issingletontype(typeof(c.val)) # can only widen a if it is a singleton
29,207✔
1933
        elsetype = typesubtract(elsetype, typeof(c.val), max_union_splitting)
23,024✔
1934
    end
1935
    return ConditionalTypes(thentype, elsetype)
48,347✔
1936
end
1937
@inline function egal_condition(c::Const, @nospecialize(xt), max_union_splitting::Int)
1938
    thentype = c
×
1939
    elsetype = widenslotwrapper(xt)
6✔
1940
    if elsetype isa Type && issingletontype(typeof(c.val)) # can only widen a if it is a singleton
6✔
1941
        elsetype = typesubtract(elsetype, typeof(c.val), max_union_splitting)
×
1942
    end
1943
    return ConditionalTypes(thentype, elsetype)
6✔
1944
end
1945

1946
function abstract_call_builtin(interp::AbstractInterpreter, f::Builtin, (; fargs, argtypes)::ArgInfo,
623,901✔
1947
                               sv::AbsIntState)
1948
    @nospecialize f
623,901✔
1949
    la = length(argtypes)
623,901✔
1950
    ๐•ƒแตข = typeinf_lattice(interp)
623,901✔
1951
    โŠ‘, โŠ, โŠ”, โŠ“ = partialorder(๐•ƒแตข), strictpartialorder(๐•ƒแตข), join(๐•ƒแตข), meet(๐•ƒแตข)
623,901✔
1952
    if has_conditional(๐•ƒแตข, sv) && f === Core.ifelse && fargs isa Vector{Any} && la == 4
623,901✔
1953
        cnd = argtypes[2]
2,614✔
1954
        if isa(cnd, Conditional)
2,614✔
1955
            newcnd = widenconditional(cnd)
980✔
1956
            tx = argtypes[3]
490✔
1957
            ty = argtypes[4]
490✔
1958
            if isa(newcnd, Const)
490✔
1959
                # if `cnd` is constant, we should just respect its constantness to keep inference accuracy
1960
                return newcnd.val::Bool ? tx : ty
×
1961
            else
1962
                # try to simulate this as a real conditional (`cnd ? x : y`), so that the penalty for using `ifelse` instead isn't too high
1963
                a = ssa_def_slot(fargs[3], sv)
490✔
1964
                b = ssa_def_slot(fargs[4], sv)
490✔
1965
                if isa(a, SlotNumber) && cnd.slot == slot_id(a)
490✔
1966
                    tx = (cnd.thentype โŠ‘ tx ? cnd.thentype : tx โŠ“ widenconst(cnd.thentype))
×
1967
                end
1968
                if isa(b, SlotNumber) && cnd.slot == slot_id(b)
490✔
1969
                    ty = (cnd.elsetype โŠ‘ ty ? cnd.elsetype : ty โŠ“ widenconst(cnd.elsetype))
×
1970
                end
1971
                return tx โŠ” ty
490✔
1972
            end
1973
        end
1974
    end
1975
    ft = popfirst!(argtypes)
623,411✔
1976
    rt = builtin_tfunction(interp, f, argtypes, sv)
623,411✔
1977
    pushfirst!(argtypes, ft)
626,069✔
1978
    if has_mustalias(๐•ƒแตข) && f === getfield && isa(fargs, Vector{Any}) && la โ‰ฅ 3
623,411✔
1979
        a3 = argtypes[3]
252✔
1980
        if isa(a3, Const)
252✔
1981
            if rt !== Bottom && !isalreadyconst(rt)
432✔
1982
                var = ssa_def_slot(fargs[2], sv)
210✔
1983
                if isa(var, SlotNumber)
210✔
1984
                    vartyp = widenslotwrapper(argtypes[2])
210✔
1985
                    fldidx = maybe_const_fldidx(vartyp, a3.val)
210✔
1986
                    if fldidx !== nothing
210✔
1987
                        # wrap this aliasable field into `MustAlias` for possible constraint propagations
1988
                        return MustAlias(var, vartyp, fldidx, rt)
195✔
1989
                    end
1990
                end
1991
            end
1992
        end
1993
    elseif has_conditional(๐•ƒแตข, sv) && (rt === Bool || (isa(rt, Const) && isa(rt.val, Bool))) && isa(fargs, Vector{Any})
1,193,136✔
1994
        # perform very limited back-propagation of type information for `is` and `isa`
1995
        if f === isa
162,896✔
1996
            # try splitting value argument, based on types
1997
            a = ssa_def_slot(fargs[2], sv)
73,430✔
1998
            a2 = argtypes[2]
73,430✔
1999
            a3 = argtypes[3]
73,430✔
2000
            if isa(a, SlotNumber)
73,430✔
2001
                cndt = isa_condition(a2, a3, InferenceParams(interp).max_union_splitting, rt)
117,113✔
2002
                if cndt !== nothing
68,476✔
2003
                    return Conditional(a, cndt.thentype, cndt.elsetype)
66,083✔
2004
                end
2005
            end
2006
            if isa(a2, MustAlias)
7,347✔
2007
                if !isa(rt, Const) # skip refinement when the field is known precisely (just optimization)
60✔
2008
                    cndt = isa_condition(a2, a3, InferenceParams(interp).max_union_splitting)
114✔
2009
                    if cndt !== nothing
57✔
2010
                        return form_mustalias_conditional(a2, cndt.thentype, cndt.elsetype)
57✔
2011
                    end
2012
                end
2013
            end
2014
            # try splitting type argument, based on value
2015
            if isdispatchelem(widenconst(a2)) && a3 isa Union && !has_free_typevars(a3) && !isa(rt, Const)
14,580✔
2016
                b = ssa_def_slot(fargs[3], sv)
330✔
2017
                if isa(b, SlotNumber)
330✔
2018
                    # !(x isa T) implies !(Type{a2} <: T)
2019
                    # TODO: complete splitting, based on which portions of the Union a3 for which isa_tfunc returns Const(true) or Const(false) instead of Bool
2020
                    elsetype = typesubtract(a3, Type{widenconst(a2)}, InferenceParams(interp).max_union_splitting)
330✔
2021
                    return Conditional(b, a3, elsetype)
330✔
2022
                end
2023
            end
2024
        elseif f === (===)
89,466✔
2025
            a = ssa_def_slot(fargs[2], sv)
55,079✔
2026
            b = ssa_def_slot(fargs[3], sv)
55,079✔
2027
            aty = argtypes[2]
55,079✔
2028
            bty = argtypes[3]
55,079✔
2029
            # if doing a comparison to a singleton, consider returning a `Conditional` instead
2030
            if isa(aty, Const)
55,079✔
2031
                if isa(b, SlotNumber)
12,652✔
2032
                    cndt = egal_condition(aty, bty, InferenceParams(interp).max_union_splitting, rt)
2,802✔
2033
                    return Conditional(b, cndt.thentype, cndt.elsetype)
2,060✔
2034
                elseif isa(bty, MustAlias) && !isa(rt, Const) # skip refinement when the field is known precisely (just optimization)
10,592✔
2035
                    cndt = egal_condition(aty, bty.fldtyp, InferenceParams(interp).max_union_splitting)
3✔
2036
                    return form_mustalias_conditional(bty, cndt.thentype, cndt.elsetype)
3✔
2037
                end
2038
            elseif isa(bty, Const)
42,427✔
2039
                if isa(a, SlotNumber)
38,793✔
2040
                    cndt = egal_condition(bty, aty, InferenceParams(interp).max_union_splitting, rt)
45,545✔
2041
                    return Conditional(a, cndt.thentype, cndt.elsetype)
37,181✔
2042
                elseif isa(aty, MustAlias) && !isa(rt, Const) # skip refinement when the field is known precisely (just optimization)
1,612✔
2043
                    cndt = egal_condition(bty, aty.fldtyp, InferenceParams(interp).max_union_splitting)
3✔
2044
                    return form_mustalias_conditional(aty, cndt.thentype, cndt.elsetype)
3✔
2045
                end
2046
            end
2047
            # TODO enable multiple constraints propagation here, there are two possible improvements:
2048
            # 1. propagate constraints for both lhs and rhs
2049
            # 2. we can propagate both constraints on aliased fields and slots
2050
            # As for 2, for now, we prioritize constraints on aliased fields, since currently
2051
            # different slots that represent the same object can't share same field constraint,
2052
            # and thus binding `MustAlias` to the other slot is less likely useful
2053
            if !isa(rt, Const) # skip refinement when the field is known precisely (just optimization)
15,832✔
2054
                if isa(bty, MustAlias)
4,757✔
2055
                    thentype = widenslotwrapper(aty)
3✔
2056
                    elsetype = bty.fldtyp
3✔
2057
                    if thentype โŠ elsetype
3✔
2058
                        return form_mustalias_conditional(bty, thentype, elsetype)
3✔
2059
                    end
2060
                elseif isa(aty, MustAlias)
4,754✔
2061
                    thentype = widenslotwrapper(bty)
3✔
2062
                    elsetype = aty.fldtyp
3✔
2063
                    if thentype โŠ elsetype
3✔
2064
                        return form_mustalias_conditional(aty, thentype, elsetype)
3✔
2065
                    end
2066
                end
2067
            end
2068
            # narrow the lattice slightly (noting the dependency on one of the slots), to promote more effective smerge
2069
            if isa(b, SlotNumber)
15,826✔
2070
                thentype = rt === Const(false) ? Bottom : widenslotwrapper(bty)
5,122✔
2071
                elsetype = rt === Const(true)  ? Bottom : widenslotwrapper(bty)
5,590✔
2072
                return Conditional(b, thentype, elsetype)
2,795✔
2073
            elseif isa(a, SlotNumber)
13,031✔
2074
                thentype = rt === Const(false) ? Bottom : widenslotwrapper(aty)
16,377✔
2075
                elsetype = rt === Const(true)  ? Bottom : widenslotwrapper(aty)
15,032✔
2076
                return Conditional(a, thentype, elsetype)
10,264✔
2077
            end
2078
        elseif f === Core.Intrinsics.not_int
34,387✔
2079
            aty = argtypes[2]
6,991✔
2080
            if isa(aty, Conditional)
6,991✔
2081
                thentype = rt === Const(false) ? Bottom : aty.elsetype
12,928✔
2082
                elsetype = rt === Const(true)  ? Bottom : aty.thentype
7,790✔
2083
                return Conditional(aty.slot, thentype, elsetype)
6,906✔
2084
            end
2085
        elseif f === isdefined
27,396✔
2086
            a = ssa_def_slot(fargs[2], sv)
8,531✔
2087
            if isa(a, SlotNumber)
8,531✔
2088
                argtype2 = argtypes[2]
8,201✔
2089
                if isa(argtype2, Union)
8,201✔
2090
                    fld = argtypes[3]
×
2091
                    thentype = Bottom
×
2092
                    elsetype = Bottom
×
2093
                    for ty in uniontypes(argtype2)
×
2094
                        cnd = isdefined_tfunc(๐•ƒแตข, ty, fld)
×
2095
                        if isa(cnd, Const)
×
2096
                            if cnd.val::Bool
×
2097
                                thentype = thentype โŠ” ty
×
2098
                            else
2099
                                elsetype = elsetype โŠ” ty
×
2100
                            end
2101
                        else
2102
                            thentype = thentype โŠ” ty
×
2103
                            elsetype = elsetype โŠ” ty
×
2104
                        end
2105
                    end
×
2106
                    return Conditional(a, thentype, elsetype)
×
2107
                else
2108
                    thentype = form_partially_defined_struct(๐•ƒแตข, argtype2, argtypes[3])
8,201✔
2109
                    if thentype !== nothing
8,201✔
2110
                        elsetype = widenslotwrapper(argtype2)
426✔
2111
                        if rt === Const(false)
426✔
2112
                            thentype = Bottom
×
2113
                        elseif rt === Const(true)
426✔
2114
                            elsetype = Bottom
×
2115
                        end
2116
                        return Conditional(a, thentype, elsetype)
426✔
2117
                    end
2118
                end
2119
            end
2120
        end
2121
    end
2122
    @assert !isa(rt, TypeVar) "unhandled TypeVar"
497,102✔
2123
    return rt
497,102✔
2124
end
2125

2126
function form_partially_defined_struct(๐•ƒแตข::AbstractLattice, @nospecialize(obj), @nospecialize(name))
1,492✔
2127
    obj isa Const && return nothing # nothing to refine
1,492✔
2128
    name isa Const || return nothing
756✔
2129
    objt0 = widenconst(obj)
756✔
2130
    objt = unwrap_unionall(objt0)
756✔
2131
    objt isa DataType || return nothing
756✔
2132
    isabstracttype(objt) && return nothing
756✔
2133
    objt <: Tuple && return nothing
756✔
2134
    fldidx = try_compute_fieldidx(objt, name.val)
756✔
2135
    fldidx === nothing && return nothing
756✔
2136
    if isa(obj, PartialStruct)
740✔
2137
        _getundefs(obj)[fldidx] === false && return nothing
×
2138
        newundefs = copy(_getundefs(obj))
×
2139
        newundefs[fldidx] = false
×
2140
        return PartialStruct(๐•ƒแตข, obj.typ, newundefs, copy(obj.fields))
×
2141
    end
2142
    nminfld = datatype_min_ninitialized(objt)
1,480✔
2143
    fldidx โ‰ค nminfld && return nothing
740✔
2144
    fldcnt = fieldcount_noerror(objt)::Int
31✔
2145
    fields = Any[fieldtype(objt0, i) for i = 1:fldcnt]
378✔
2146
    if fields[fldidx] === Union{}
31✔
2147
        return nothing # `Union{}` field never transitions to be defined
×
2148
    end
2149
    undefs = partialstruct_init_undefs(objt, fields)
31✔
2150
    if undefs === nothing
31✔
2151
        # this object never exists at runtime, avoid creating unprofitable `PartialStruct`
2152
        return nothing
×
2153
    end
2154
    undefs[fldidx] = false
31✔
2155
    return PartialStruct(๐•ƒแตข, objt0, undefs, fields)
31✔
2156
end
2157

2158
function abstract_call_unionall(interp::AbstractInterpreter, argtypes::Vector{Any}, call::CallMeta)
1,860✔
2159
    na = length(argtypes)
1,860✔
2160
    if isvarargtype(argtypes[end])
1,860✔
2161
        if na โ‰ค 2
×
2162
            return CallMeta(Any, Any, EFFECTS_THROWS, call.info)
×
2163
        elseif na > 4
×
2164
            return CallMeta(Bottom, Any, EFFECTS_THROWS, NoCallInfo())
×
2165
        end
2166
        a2 = argtypes[2]
×
2167
        a3 = unwrapva(argtypes[3])
×
2168
        nothrow = false
×
2169
    elseif na == 3
1,860✔
2170
        a2 = argtypes[2]
1,860✔
2171
        a3 = argtypes[3]
1,860✔
2172
        โŠ‘ = partialorder(typeinf_lattice(interp))
1,860✔
2173
        nothrow = a2 โŠ‘ TypeVar && (a3 โŠ‘ Type || a3 โŠ‘ TypeVar)
1,860✔
2174
    else
2175
        return CallMeta(Bottom, Any, EFFECTS_THROWS, NoCallInfo())
×
2176
    end
2177
    canconst = true
1,860✔
2178
    if isa(a3, Const)
1,860✔
2179
        body = a3.val
×
2180
    elseif isType(a3)
1,860✔
2181
        body = a3.parameters[1]
1,595✔
2182
        canconst = false
1,595✔
2183
    else
2184
        return CallMeta(Any, Any, Effects(EFFECTS_TOTAL; nothrow), call.info)
265✔
2185
    end
2186
    if !(isa(body, Type) || isa(body, TypeVar))
1,595✔
2187
        return CallMeta(Any, Any, EFFECTS_THROWS, call.info)
×
2188
    end
2189
    if has_free_typevars(body)
3,190✔
2190
        if isa(a2, Const)
1,595✔
2191
            tv = a2.val
×
2192
        elseif isa(a2, PartialTypeVar)
1,595✔
2193
            tv = a2.tv
1,595✔
2194
            canconst = false
1,595✔
2195
        else
2196
            return CallMeta(Any, Any, EFFECTS_THROWS, call.info)
×
2197
        end
2198
        isa(tv, TypeVar) || return CallMeta(Any, Any, EFFECTS_THROWS, call.info)
1,595✔
2199
        body = UnionAll(tv, body)
1,595✔
2200
    end
2201
    ret = canconst ? Const(body) : Type{body}
3,190✔
2202
    return CallMeta(ret, Any, Effects(EFFECTS_TOTAL; nothrow), call.info)
1,595✔
2203
end
2204

2205
function get_ci_abi(ci::CodeInstance)
2206
    def = ci.def
3✔
2207
    isa(def, ABIOverride) && return def.abi
3✔
2208
    (def::MethodInstance).specTypes
3✔
2209
end
2210

2211
function abstract_invoke(interp::AbstractInterpreter, arginfo::ArgInfo, si::StmtInfo, sv::AbsIntState)
464✔
2212
    argtypes = arginfo.argtypes
464✔
2213
    ftโ€ฒ = argtype_by_index(argtypes, 2)
464✔
2214
    ft = widenconst(ftโ€ฒ)
464✔
2215
    ft === Bottom && return Future(CallMeta(Bottom, Any, EFFECTS_THROWS, NoCallInfo()))
464✔
2216
    types = argtype_by_index(argtypes, 3)
464✔
2217
    our_world = get_inference_world(interp)
464✔
2218
    if types isa Const && types.val isa Union{Method, CodeInstance}
464✔
2219
        method_or_ci = types.val
×
2220
        if isa(method_or_ci, CodeInstance)
×
2221
            argtype = argtypes_to_type(pushfirst!(argtype_tail(argtypes, 4), ft))
×
2222
            specsig = get_ci_abi(method_or_ci)
×
2223
            defdef = get_ci_mi(method_or_ci).def
×
2224
            exct = method_or_ci.exctype
×
2225
            if !hasintersect(argtype, specsig)
×
2226
                return Future(CallMeta(Bottom, TypeError, EFFECTS_THROWS, NoCallInfo()))
×
2227
            elseif !(argtype <: specsig) || ((!isa(method_or_ci.def, ABIOverride) && isa(defdef, Method)) && !(argtype <: defdef.sig))
×
2228
                exct = Union{exct, TypeError}
×
2229
            end
2230
            callee_valid_range = WorldRange(method_or_ci.min_world, method_or_ci.max_world)
×
2231
            if !(our_world in callee_valid_range)
×
2232
                if our_world < first(callee_valid_range)
×
2233
                    update_valid_age!(sv, our_world, WorldRange(first(sv.valid_worlds), first(callee_valid_range)-1))
×
2234
                else
2235
                    update_valid_age!(sv, our_world, WorldRange(last(callee_valid_range)+1, last(sv.valid_worlds)))
×
2236
                end
2237
                return Future(CallMeta(Bottom, ErrorException, EFFECTS_THROWS, NoCallInfo()))
×
2238
            end
2239
            # TODO: When we add curing, we may want to assume this is nothrow
2240
            if (method_or_ci.owner === Nothing && method_ir_ci.def.def isa Method)
×
2241
                exct = Union{exct, ErrorException}
×
2242
            end
2243
            update_valid_age!(sv, our_world, callee_valid_range)
×
2244
            return Future(CallMeta(method_or_ci.rettype, exct, Effects(decode_effects(method_or_ci.ipo_purity_bits), nothrow=(exct===Bottom)),
×
2245
                InvokeCICallInfo(method_or_ci)))
2246
        else
2247
            method = method_or_ci::Method
×
2248
            types = method # argument value
×
2249
            lookupsig = method.sig # edge kind
×
2250
            argtype = argtypes_to_type(pushfirst!(argtype_tail(argtypes, 4), ft))
×
2251
            nargtype = typeintersect(lookupsig, argtype)
×
2252
            nargtype === Bottom && return Future(CallMeta(Bottom, TypeError, EFFECTS_THROWS, NoCallInfo()))
×
2253
            nargtype isa DataType || return Future(CallMeta(Any, Any, Effects(), NoCallInfo())) # other cases are not implemented below
×
2254
            # Fall through to generic invoke handling
2255
        end
2256
    else
2257
        hasintersect(widenconst(types), Union{Method, CodeInstance}) && return Future(CallMeta(Any, Any, Effects(), NoCallInfo()))
464✔
2258
        types, isexact, _, _ = instanceof_tfunc(argtype_by_index(argtypes, 3), false)
464✔
2259
        isexact || return Future(CallMeta(Any, Any, Effects(), NoCallInfo()))
464✔
2260
        unwrapped = unwrap_unionall(types)
464✔
2261
        types === Bottom && return Future(CallMeta(Bottom, Any, EFFECTS_THROWS, NoCallInfo()))
464✔
2262
        if !(unwrapped isa DataType && unwrapped.name === Tuple.name)
464✔
2263
            return Future(CallMeta(Bottom, TypeError, EFFECTS_THROWS, NoCallInfo()))
×
2264
        end
2265
        argtype = argtypes_to_type(argtype_tail(argtypes, 4))
928✔
2266
        nargtype = typeintersect(types, argtype)
464✔
2267
        nargtype === Bottom && return Future(CallMeta(Bottom, TypeError, EFFECTS_THROWS, NoCallInfo()))
464✔
2268
        nargtype isa DataType || return Future(CallMeta(Any, Any, Effects(), NoCallInfo())) # other cases are not implemented below
464✔
2269
        isdispatchelem(ft) || return Future(CallMeta(Any, Any, Effects(), NoCallInfo())) # check that we might not have a subtype of `ft` at runtime, before doing supertype lookup below
464✔
2270
        ft = ft::DataType
464✔
2271
        lookupsig = rewrap_unionall(Tuple{ft, unwrapped.parameters...}, types)::Type
464✔
2272
        nargtype = Tuple{ft, nargtype.parameters...}
464✔
2273
        argtype = Tuple{ft, argtype.parameters...}
464✔
2274
        matched, valid_worlds = findsup(lookupsig, method_table(interp))
509✔
2275
        matched === nothing && return Future(CallMeta(Any, Any, Effects(), NoCallInfo()))
464✔
2276
        update_valid_age!(sv, our_world, valid_worlds)
464✔
2277
        method = matched.method
464✔
2278
    end
2279
    tienv = ccall(:jl_type_intersection_with_env, Any, (Any, Any), nargtype, method.sig)::SimpleVector
464✔
2280
    ti = tienv[1]
464✔
2281
    env = tienv[2]::SimpleVector
464✔
2282
    mresult = abstract_call_method(interp, method, ti, env, false, si, sv)::Future
464✔
2283
    match = MethodMatch(ti, env, method, argtype <: method.sig)
464✔
2284
    ftโ€ฒ_box = Core.Box(ftโ€ฒ)
464✔
2285
    lookupsig_box = Core.Box(lookupsig)
464✔
2286
    invokecall = InvokeCall(types)
464✔
2287
    return Future{CallMeta}(mresult, interp, sv) do result, interp, sv
464✔
2288
        (; rt, exct, effects, edge, call_result) = result
464✔
2289
        local ftโ€ฒ = ftโ€ฒ_box.contents
464✔
2290
        sig = match.spec_types
464✔
2291
        argtypesโ€ฒ = invoke_rewrite(arginfo.argtypes)
464✔
2292
        fargs = arginfo.fargs
464✔
2293
        fargsโ€ฒ = fargs === nothing ? nothing : invoke_rewrite(fargs)
928✔
2294
        arginfoโ€ฒ = ArgInfo(fargsโ€ฒ, argtypesโ€ฒ)
928✔
2295
        # # typeintersect might have narrowed signature, but the accuracy gain doesn't seem worth the cost involved with the lattice comparisons
2296
        # for i in 1:length(argtypesโ€ฒ)
2297
        #     t, a = ti.parameters[i], argtypesโ€ฒ[i]
2298
        #     argtypesโ€ฒ[i] = t โŠ‘ a ? t : a
2299
        # end
2300
        ๐•ƒโ‚š = ipo_lattice(interp)
464✔
2301
        โŠ‘, โ‹ค, โŠ” = partialorder(๐•ƒโ‚š), strictneqpartialorder(๐•ƒโ‚š), join(๐•ƒโ‚š)
464✔
2302
        f = singleton_type(ftโ€ฒ)
464✔
2303
        const_call_result = abstract_call_method_with_const_args(interp,
464✔
2304
            result, f, arginfoโ€ฒ, si, match, sv, invokecall)
2305
        if const_call_result !== nothing
464✔
2306
            const_result = const_edge = nothing
314✔
2307
            if const_call_result.rt โŠ‘ rt
314✔
2308
                (; rt, effects, const_result, const_edge) = const_call_result
314✔
2309
            end
2310
            if const_call_result.exct โ‹ค exct
314✔
2311
                (; exct, const_result, const_edge) = const_call_result
174✔
2312
            end
2313
            if const_edge !== nothing
314✔
2314
                edge = const_edge
314✔
2315
                update_valid_age!(sv, get_inference_world(interp), world_range(const_edge))
314✔
2316
            end
2317
            if const_result !== nothing
314✔
2318
                call_result = const_result
314✔
2319
            end
2320
        end
2321
        rt = from_interprocedural!(interp, rt, sv, arginfoโ€ฒ, sig)
464✔
2322
        info = InvokeCallInfo(edge, match, call_result, lookupsig_box.contents)
928✔
2323
        if !match.fully_covers
464✔
2324
            effects = Effects(effects; nothrow=false)
9✔
2325
            exct = exct โŠ” TypeError
9✔
2326
        end
2327
        return CallMeta(rt, exct, effects, info)
464✔
2328
    end
2329
end
2330

2331
function invoke_rewrite(xs::Vector{Any})
2332
    x0 = xs[2]
1,359✔
2333
    newxs = xs[3:end]
2,718✔
2334
    newxs[1] = x0
1,359✔
2335
    return newxs
1,194✔
2336
end
2337

2338
function abstract_finalizer(interp::AbstractInterpreter, argtypes::Vector{Any}, sv::AbsIntState)
24✔
2339
    if length(argtypes) == 3
24✔
2340
        finalizer_argvec = Any[argtypes[2], argtypes[3]]
48✔
2341
        call = abstract_call(interp, ArgInfo(nothing, finalizer_argvec), StmtInfo(false, false), sv, #=max_methods=#1)::Future
24✔
2342
        return Future{CallMeta}(call, interp, sv) do call, _, _
24✔
2343
            return CallMeta(Nothing, Any, Effects(), FinalizerInfo(call.info, call.effects))
24✔
2344
        end
2345
    end
2346
    return Future(CallMeta(Nothing, Any, Effects(), NoCallInfo()))
×
2347
end
2348

2349
function abstract_throw(interp::AbstractInterpreter, argtypes::Vector{Any}, ::AbsIntState)
18✔
2350
    na = length(argtypes)
10,348✔
2351
    โŠ” = join(typeinf_lattice(interp))
10,331✔
2352
    if na == 2
10,348✔
2353
        argtype2 = argtypes[2]
10,339✔
2354
        if isvarargtype(argtype2)
10,339✔
2355
            exct = unwrapva(argtype2) โŠ” ArgumentError
×
2356
        else
2357
            exct = argtype2
10,322✔
2358
        end
2359
    elseif na == 3 && isvarargtype(argtypes[3])
9✔
2360
        exct = argtypes[2] โŠ” ArgumentError
×
2361
    else
2362
        exct = ArgumentError
9✔
2363
    end
2364
    return Future(CallMeta(Union{}, exct, EFFECTS_THROWS, NoCallInfo()))
10,348✔
2365
end
2366

2367
function abstract_throw_methoderror(::AbstractInterpreter, argtypes::Vector{Any}, ::AbsIntState)
2368
    exct = if length(argtypes) == 1
×
2369
        ArgumentError
×
2370
    elseif !isvarargtype(argtypes[2])
×
2371
        MethodError
×
2372
    else
2373
        Union{MethodError, ArgumentError}
×
2374
    end
2375
    return Future(CallMeta(Union{}, exct, EFFECTS_THROWS, NoCallInfo()))
×
2376
end
2377

2378
const generic_getglobal_effects = Effects(EFFECTS_THROWS, effect_free=ALWAYS_FALSE, consistent=ALWAYS_FALSE, inaccessiblememonly=ALWAYS_FALSE) #= effect_free for depwarn =#
2379
const generic_getglobal_exct = Union{ArgumentError, TypeError, ConcurrencyViolationError, UndefVarError}
2380
function abstract_eval_getglobal(interp::AbstractInterpreter, sv::AbsIntState, saw_latestworld::Bool, @nospecialize(M), @nospecialize(s))
5,934✔
2381
    โŠ‘ = partialorder(typeinf_lattice(interp))
5,934✔
2382
    if M isa Const && s isa Const
5,934✔
2383
        M, s = M.val, s.val
5,809✔
2384
        if M isa Module && s isa Symbol
5,809✔
2385
            gr = GlobalRef(M, s)
5,809✔
2386
            ret = abstract_eval_globalref(interp, gr, saw_latestworld, sv)
10,728✔
2387
            return CallMeta(ret, GlobalAccessInfo(convert(Core.Binding, gr)))
5,809✔
2388
        end
2389
        return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
×
2390
    elseif !hasintersect(widenconst(M), Module) || !hasintersect(widenconst(s), Symbol)
250✔
2391
        return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
×
2392
    elseif M โŠ‘ Module && s โŠ‘ Symbol
125✔
2393
        return CallMeta(Any, UndefVarError, generic_getglobal_effects, NoCallInfo())
125✔
2394
    end
2395
    return CallMeta(Any, Union{UndefVarError, TypeError}, generic_getglobal_effects, NoCallInfo())
×
2396
end
2397

2398
function merge_exct(cm::CallMeta, @nospecialize(exct))
2399
    if exct !== Bottom
93✔
2400
        cm = CallMeta(cm.rt, Union{cm.exct, exct}, Effects(cm.effects; nothrow=false), cm.info)
12✔
2401
    end
2402
    return cm
93✔
2403
end
2404

2405
function abstract_eval_getglobal(interp::AbstractInterpreter, sv::AbsIntState, saw_latestworld::Bool, @nospecialize(M), @nospecialize(s), @nospecialize(order))
2406
    goe = global_order_exct(order, #=loading=#true, #=storing=#false)
×
2407
    cm = abstract_eval_getglobal(interp, sv, saw_latestworld, M, s)
×
2408
    return merge_exct(cm, goe)
×
2409
end
2410

2411
function abstract_eval_getglobal(interp::AbstractInterpreter, sv::AbsIntState, saw_latestworld::Bool, argtypes::Vector{Any})
5,928✔
2412
    if !isvarargtype(argtypes[end])
5,928✔
2413
        if length(argtypes) == 3
5,928✔
2414
            return abstract_eval_getglobal(interp, sv, saw_latestworld, argtypes[2], argtypes[3])
5,928✔
2415
        elseif length(argtypes) == 4
×
2416
            return abstract_eval_getglobal(interp, sv, saw_latestworld, argtypes[2], argtypes[3], argtypes[4])
×
2417
        else
2418
            return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
×
2419
        end
2420
    elseif length(argtypes) > 5
×
2421
        return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
×
2422
    else
2423
        return CallMeta(Any, generic_getglobal_exct, generic_getglobal_effects, NoCallInfo())
×
2424
    end
2425
end
2426

2427
# The binding lookup code uses the current world to bound its scan to only those worlds that are currently valid
2428
binding_world_hints(world::UInt, sv::AbsIntState) = WorldWithRange(world, sv.valid_worlds)
1,880,742✔
2429

2430
@nospecs function abstract_eval_get_binding_type(interp::AbstractInterpreter, sv::AbsIntState, M, s)
120✔
2431
    @nospecialize M s
120✔
2432
    โŠ‘ = partialorder(typeinf_lattice(interp))
120✔
2433
    if isa(M, Const) && isa(s, Const)
120✔
2434
        (M, s) = (M.val, s.val)
96✔
2435
        if !isa(M, Module) || !isa(s, Symbol)
192✔
2436
            return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
×
2437
        end
2438
        gr = GlobalRef(M, s)
96✔
2439
        world = get_inference_world(interp)
96✔
2440
        (valid_worlds, rt) = scan_leaf_partitions(interp, gr, binding_world_hints(world, sv)) do interp::AbstractInterpreter, ::Core.Binding, partition::Core.BindingPartition
96✔
2441
            local rt
165✔
2442
            kind = binding_kind(partition)
165✔
2443
            if is_some_guard(kind) || kind == PARTITION_KIND_DECLARED
471✔
2444
                # We do not currently assume an invalidation for guard -> defined transitions
2445
                # rt = Const(nothing)
2446
                rt = Type
69✔
2447
            elseif is_some_const_binding(kind)
192✔
2448
                rt = Const(Any)
×
2449
            else
2450
                rt = Const(partition_restriction(partition))
96✔
2451
            end
2452
            rt
165✔
2453
        end
2454
        update_valid_age!(sv, world, valid_worlds)
96✔
2455
        return CallMeta(rt, Union{}, EFFECTS_TOTAL, GlobalAccessInfo(convert(Core.Binding, gr)))
96✔
2456
    elseif !hasintersect(widenconst(M), Module) || !hasintersect(widenconst(s), Symbol)
48✔
2457
        return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
×
2458
    elseif M โŠ‘ Module && s โŠ‘ Symbol
24✔
2459
        return CallMeta(Type, Union{}, EFFECTS_TOTAL, NoCallInfo())
24✔
2460
    end
2461
    return CallMeta(Type, TypeError, EFFECTS_THROWS, NoCallInfo())
×
2462
end
2463

2464
function abstract_eval_get_binding_type(interp::AbstractInterpreter, sv::AbsIntState, argtypes::Vector{Any})
2465
    if !isvarargtype(argtypes[end])
120✔
2466
        if length(argtypes) == 3
120✔
2467
            return abstract_eval_get_binding_type(interp, sv, argtypes[2], argtypes[3])
120✔
2468
        else
2469
            return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
×
2470
        end
2471
    elseif length(argtypes) > 4
×
2472
        return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
×
2473
    else
2474
        return CallMeta(Type, Union{TypeError, ArgumentError}, EFFECTS_THROWS, NoCallInfo())
×
2475
    end
2476
end
2477

2478
const setglobal!_effects = Effects(EFFECTS_TOTAL; effect_free=ALWAYS_FALSE, nothrow=false, inaccessiblememonly=ALWAYS_FALSE)
2479

2480
function abstract_eval_setglobal!(interp::AbstractInterpreter, sv::AbsIntState, saw_latestworld::Bool, @nospecialize(M), @nospecialize(s), @nospecialize(v))
126✔
2481
    if isa(M, Const) && isa(s, Const)
126✔
2482
        M, s = M.val, s.val
102✔
2483
        if M isa Module && s isa Symbol
102✔
2484
            gr = GlobalRef(M, s)
102✔
2485
            (rt, exct) = global_assignment_rt_exct(interp, sv, saw_latestworld, gr, v)
204✔
2486
            return CallMeta(rt, exct, Effects(setglobal!_effects, nothrow=exct===Bottom), GlobalAccessInfo(convert(Core.Binding, gr)))
102✔
2487
        end
2488
        return CallMeta(Union{}, Union{TypeError, ErrorException}, EFFECTS_THROWS, NoCallInfo())
×
2489
    end
2490
    โŠ‘ = partialorder(typeinf_lattice(interp))
24✔
2491
    if !(hasintersect(widenconst(M), Module) && hasintersect(widenconst(s), Symbol))
24✔
2492
        return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
×
2493
    elseif M โŠ‘ Module && s โŠ‘ Symbol
24✔
2494
        return CallMeta(v, ErrorException, setglobal!_effects, NoCallInfo())
24✔
2495
    end
2496
    return CallMeta(v, Union{TypeError, ErrorException}, setglobal!_effects, NoCallInfo())
×
2497
end
2498

2499
function abstract_eval_setglobal!(interp::AbstractInterpreter, sv::AbsIntState, saw_latestworld::Bool, @nospecialize(M), @nospecialize(s), @nospecialize(v), @nospecialize(order))
2500
    goe = global_order_exct(order, #=loading=#false, #=storing=#true)
36✔
2501
    cm = abstract_eval_setglobal!(interp, sv, saw_latestworld, M, s, v)
36✔
2502
    return merge_exct(cm, goe)
36✔
2503
end
2504

2505
const generic_setglobal!_exct = Union{ArgumentError, TypeError, ErrorException, ConcurrencyViolationError}
2506

2507
function abstract_eval_setglobal!(interp::AbstractInterpreter, sv::AbsIntState, saw_latestworld::Bool, argtypes::Vector{Any})
120✔
2508
    if !isvarargtype(argtypes[end])
120✔
2509
        if length(argtypes) == 4
120✔
2510
            return abstract_eval_setglobal!(interp, sv, saw_latestworld, argtypes[2], argtypes[3], argtypes[4])
84✔
2511
        elseif length(argtypes) == 5
36✔
2512
            return abstract_eval_setglobal!(interp, sv, saw_latestworld, argtypes[2], argtypes[3], argtypes[4], argtypes[5])
36✔
2513
        else
2514
            return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
×
2515
        end
2516
    elseif length(argtypes) > 6
×
2517
        return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
×
2518
    else
2519
        return CallMeta(Any, generic_setglobal!_exct, setglobal!_effects, NoCallInfo())
×
2520
    end
2521
end
2522

2523
function abstract_eval_swapglobal!(interp::AbstractInterpreter, sv::AbsIntState, saw_latestworld::Bool,
2524
                                   @nospecialize(M), @nospecialize(s), @nospecialize(v))
2525
    scm = abstract_eval_setglobal!(interp, sv, saw_latestworld, M, s, v)
6✔
2526
    scm.rt === Bottom && return scm
6✔
2527
    gcm = abstract_eval_getglobal(interp, sv, saw_latestworld, M, s)
6✔
2528
    return CallMeta(gcm.rt, Union{scm.exct,gcm.exct}, merge_effects(scm.effects, gcm.effects), scm.info)
6✔
2529
end
2530

2531
function abstract_eval_swapglobal!(interp::AbstractInterpreter, sv::AbsIntState, saw_latestworld::Bool,
×
2532
                                   @nospecialize(M), @nospecialize(s), @nospecialize(v), @nospecialize(order))
2533
    scm = abstract_eval_setglobal!(interp, sv, saw_latestworld, M, s, v, order)
×
2534
    scm.rt === Bottom && return scm
×
2535
    gcm = abstract_eval_getglobal(interp, sv, saw_latestworld, M, s, order)
×
2536
    return CallMeta(gcm.rt, Union{scm.exct,gcm.exct}, merge_effects(scm.effects, gcm.effects), scm.info)
×
2537
end
2538

2539
function abstract_eval_swapglobal!(interp::AbstractInterpreter, sv::AbsIntState, saw_latestworld::Bool, argtypes::Vector{Any})
6✔
2540
    if !isvarargtype(argtypes[end])
6✔
2541
        if length(argtypes) == 4
6✔
2542
            return abstract_eval_swapglobal!(interp, sv, saw_latestworld, argtypes[2], argtypes[3], argtypes[4])
6✔
2543
        elseif length(argtypes) == 5
×
2544
            return abstract_eval_swapglobal!(interp, sv, saw_latestworld, argtypes[2], argtypes[3], argtypes[4], argtypes[5])
×
2545
        else
2546
            return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
×
2547
        end
2548
    elseif length(argtypes) > 6
×
2549
        return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
×
2550
    else
2551
        return CallMeta(Any, Union{generic_getglobal_exct,generic_setglobal!_exct}, setglobal!_effects, NoCallInfo())
×
2552
    end
2553
end
2554

2555
function abstract_eval_setglobalonce!(interp::AbstractInterpreter, sv::AbsIntState, saw_latestworld::Bool, argtypes::Vector{Any})
×
2556
    if !isvarargtype(argtypes[end])
×
2557
        if length(argtypes) in (4, 5, 6)
×
2558
            cm = abstract_eval_setglobal!(interp, sv, saw_latestworld, argtypes[2], argtypes[3], argtypes[4])
×
2559
            if length(argtypes) >= 5
×
2560
                goe = global_order_exct(argtypes[5], #=loading=#true, #=storing=#true)
×
2561
                cm = merge_exct(cm, goe)
×
2562
            end
2563
            if length(argtypes) == 6
×
2564
                goe = global_order_exct(argtypes[6], #=loading=#true, #=storing=#false)
×
2565
                cm = merge_exct(cm, goe)
×
2566
            end
2567
            return CallMeta(Bool, cm.exct, cm.effects, cm.info)
×
2568
        else
2569
            return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
×
2570
        end
2571
    elseif length(argtypes) > 7
×
2572
        return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
×
2573
    else
2574
        return CallMeta(Bool, generic_setglobal!_exct, setglobal!_effects, NoCallInfo())
×
2575
    end
2576
end
2577

2578
function abstract_eval_replaceglobal!(interp::AbstractInterpreter, sv::AbsIntState, saw_latestworld::Bool, argtypes::Vector{Any})
×
2579
    if !isvarargtype(argtypes[end])
×
2580
        if length(argtypes) in (5, 6, 7)
×
2581
            (M, s, v) = argtypes[2], argtypes[3], argtypes[5]
×
2582
            T = nothing
×
2583
            if isa(M, Const) && isa(s, Const)
×
2584
                M, s = M.val, s.val
×
2585
                M isa Module || return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
×
2586
                s isa Symbol || return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
×
2587
                gr = GlobalRef(M, s)
×
2588
                vโ€ฒ = RefValue{Any}(v)
×
2589
                world = get_inference_world(interp)
×
2590
                (valid_worlds, (rte, T)) = scan_leaf_partitions(interp, gr, binding_world_hints(world, sv)) do interp::AbstractInterpreter, binding::Core.Binding, partition::Core.BindingPartition
×
2591
                    partition_T = nothing
×
2592
                    partition_rte = abstract_eval_partition_load(interp, binding, partition)
×
2593
                    if binding_kind(partition) == PARTITION_KIND_GLOBAL
×
2594
                        partition_T = partition_restriction(partition)
×
2595
                    end
2596
                    partition_exct = Union{partition_rte.exct, global_assignment_binding_rt_exct(interp, partition, vโ€ฒ[])[2]}
×
2597
                    partition_rte = RTEffects(partition_rte.rt, partition_exct, partition_rte.effects)
×
2598
                    Pair{RTEffects, Any}(partition_rte, partition_T)
×
2599
                end
2600
                update_valid_age!(sv, world, valid_worlds)
×
2601
                effects = merge_effects(rte.effects, Effects(setglobal!_effects, nothrow=rte.exct===Bottom))
×
2602
                sg = CallMeta(Any, rte.exct, effects, GlobalAccessInfo(convert(Core.Binding, gr)))
×
2603
            else
2604
                sg = abstract_eval_setglobal!(interp, sv, saw_latestworld, M, s, v)
×
2605
            end
2606
            if length(argtypes) >= 6
×
2607
                goe = global_order_exct(argtypes[6], #=loading=#true, #=storing=#true)
×
2608
                sg = merge_exct(sg, goe)
×
2609
            end
2610
            if length(argtypes) == 7
×
2611
                goe = global_order_exct(argtypes[7], #=loading=#true, #=storing=#false)
×
2612
                sg = merge_exct(sg, goe)
×
2613
            end
2614
            rt = T === nothing ?
×
2615
                ccall(:jl_apply_cmpswap_type, Any, (Any,), S) where S :
2616
                ccall(:jl_apply_cmpswap_type, Any, (Any,), T)
2617
            return CallMeta(rt, sg.exct, sg.effects, sg.info)
×
2618
        else
2619
            return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
×
2620
        end
2621
    elseif length(argtypes) > 8
×
2622
        return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
×
2623
    else
2624
        return CallMeta(Any, Union{generic_getglobal_exct,generic_setglobal!_exct}, setglobal!_effects, NoCallInfo())
×
2625
    end
2626
end
2627

2628
function argtypes_are_actually_getglobal(argtypes::Vector{Any})
2629
    length(argtypes) in (3, 4) || return false
154,840✔
2630
    M = argtypes[2]
154,840✔
2631
    s = argtypes[3]
154,840✔
2632
    isa(M, Const) || return false
276,192✔
2633
    isa(s, Const) || return false
35,081✔
2634
    return isa(M.val, Module) && isa(s.val, Symbol)
63,733✔
2635
end
2636

2637
# call where the function is known exactly
2638
function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f),
1,689,464✔
2639
        arginfo::ArgInfo, si::StmtInfo, sv::AbsIntState,
2640
        max_methods::Int = get_max_methods(interp, f, sv))
2641
    (; fargs, argtypes) = arginfo
1,787,920✔
2642
    argtypes::Vector{Any} = arginfo.argtypes  # declare type because the closure below captures `argtypes`
1,689,461✔
2643
    fargs = arginfo.fargs
1,689,461✔
2644
    la = length(argtypes)
1,689,461✔
2645
    ๐•ƒแตข = typeinf_lattice(interp)
1,689,461✔
2646
    if isa(f, Builtin)
1,689,461✔
2647
        if f === _apply_iterate
665,308✔
2648
            return abstract_apply(interp, argtypes, si, sv, max_methods)
23,345✔
2649
        elseif f === invoke
641,963✔
2650
            return abstract_invoke(interp, arginfo, si, sv)
464✔
2651
        elseif f === modifyfield! || f === Core.modifyglobal! ||
1,282,929✔
2652
               f === Core.memoryrefmodify! || f === atomic_pointermodify
2653
            return abstract_modifyop!(interp, f, argtypes, si, sv)
69✔
2654
        elseif f === Core.finalizer
641,430✔
2655
            return abstract_finalizer(interp, argtypes, sv)
24✔
2656
        elseif f === applicable
641,406✔
2657
            return abstract_applicable(interp, argtypes, sv, max_methods)
57✔
2658
        elseif f === throw
641,349✔
2659
            return abstract_throw(interp, argtypes, sv)
10,348✔
2660
        elseif f === Core.throw_methoderror
631,001✔
2661
            return abstract_throw_methoderror(interp, argtypes, sv)
×
2662
        elseif f === Core.getglobal
631,001✔
2663
            return Future(abstract_eval_getglobal(interp, sv, si.saw_latestworld, argtypes))
5,930✔
2664
        elseif f === Core.setglobal!
625,071✔
2665
            return Future(abstract_eval_setglobal!(interp, sv, si.saw_latestworld, argtypes))
120✔
2666
        elseif f === Core.swapglobal!
624,951✔
2667
            return Future(abstract_eval_swapglobal!(interp, sv, si.saw_latestworld, argtypes))
6✔
2668
        elseif f === Core.setglobalonce!
624,945✔
2669
            return Future(abstract_eval_setglobalonce!(interp, sv, si.saw_latestworld, argtypes))
×
2670
        elseif f === Core.replaceglobal!
624,945✔
2671
            return Future(abstract_eval_replaceglobal!(interp, sv, si.saw_latestworld, argtypes))
×
2672
        elseif f === Core.getfield && argtypes_are_actually_getglobal(argtypes)
655,164✔
2673
            return Future(abstract_eval_getglobal(interp, sv, si.saw_latestworld, argtypes))
30✔
2674
        elseif f === Core.isdefined && argtypes_are_actually_getglobal(argtypes)
626,534✔
2675
            return Future(abstract_eval_isdefinedglobal(interp, argtypes[2], argtypes[3], Const(true),
27✔
2676
                length(argtypes) == 4 ? argtypes[4] : Const(:unordered),
2677
                si.saw_latestworld, sv))
2678
        elseif f === Core.isdefinedglobal
624,888✔
2679
            return Future(abstract_eval_isdefinedglobal(interp, sv, si.saw_latestworld, argtypes))
129✔
2680
        elseif f === Core.get_binding_type
624,759✔
2681
            return Future(abstract_eval_get_binding_type(interp, sv, argtypes))
120✔
2682
        end
2683
        rt = abstract_call_builtin(interp, f, arginfo, sv)
624,639✔
2684
        ft = popfirst!(argtypes)
624,639✔
2685
        effects = builtin_effects(๐•ƒแตข, f, argtypes, rt)
624,639✔
2686
        if effects.nothrow
624,639✔
2687
            exct = Union{}
590,268✔
2688
        else
2689
            exct = builtin_exct(๐•ƒแตข, f, argtypes, rt)
34,371✔
2690
        end
2691
        pushfirst!(argtypes, ft)
624,639✔
2692
        refinements = nothing
624,639✔
2693
        if sv isa InferenceState
624,639✔
2694
            if f === typeassert
624,338✔
2695
                # perform very limited back-propagation of invariants after this type assertion
2696
                if rt !== Bottom && isa(fargs, Vector{Any})
27,296✔
2697
                    farg2 = ssa_def_slot(fargs[2], sv)
27,282✔
2698
                    if farg2 isa SlotNumber
27,282✔
2699
                        refinements = SlotRefinement(farg2, rt)
3,405✔
2700
                    end
2701
                end
2702
            elseif f === setfield! && length(argtypes) == 4 && isa(argtypes[3], Const)
597,042✔
2703
                # from there on we know that the struct field will never be undefined,
2704
                # so we try to encode that information with a `PartialStruct`
2705
                if rt !== Bottom && isa(fargs, Vector{Any})
6,541✔
2706
                    farg2 = ssa_def_slot(fargs[2], sv)
6,541✔
2707
                    if farg2 isa SlotNumber
6,541✔
2708
                        refined = form_partially_defined_struct(๐•ƒแตข, argtypes[2], argtypes[3])
6,412✔
2709
                        if refined !== nothing
6,412✔
2710
                            refinements = SlotRefinement(farg2, refined)
372✔
2711
                        end
2712
                    end
2713
                end
2714
            end
2715
        end
2716
        return Future(CallMeta(rt, exct, effects, NoCallInfo(), refinements))
624,639✔
2717
    elseif isa(f, Core.OpaqueClosure)
1,024,153✔
2718
        # calling an OpaqueClosure about which we have no information returns no information
2719
        return Future(CallMeta(typeof(f).parameters[2], Any, Effects(), NoCallInfo()))
×
2720
    elseif f === TypeVar && !isvarargtype(argtypes[end])
1,024,153✔
2721
        # Manually look through the definition of TypeVar to
2722
        # make sure to be able to get `PartialTypeVar`s out.
2723
        2 โ‰ค la โ‰ค 4 || return Future(CallMeta(Bottom, Any, EFFECTS_THROWS, NoCallInfo()))
226✔
2724
        # make sure generic code is prepared for inlining if needed later
2725
        let T = Any[Type{TypeVar}, Any, Any, Any]
904✔
2726
            resize!(T, la)
226✔
2727
            atype = Tuple{T...}
226✔
2728
            T[1] = Const(TypeVar)
226✔
2729
            let call = abstract_call_gf_by_type(interp, f, ArgInfo(nothing, T), si, atype, sv, max_methods)::Future
226✔
2730
                return Future{CallMeta}(call, interp, sv) do call, interp, sv
226✔
2731
                    n = argtypes[2]
226✔
2732
                    ub_var = Const(Any)
226✔
2733
                    lb_var = Const(Union{})
226✔
2734
                    if la == 4
226✔
2735
                        ub_var = argtypes[4]
30✔
2736
                        lb_var = argtypes[3]
30✔
2737
                    elseif la == 3
196✔
2738
                        ub_var = argtypes[3]
184✔
2739
                    end
2740
                    pT = typevar_tfunc(๐•ƒแตข, n, lb_var, ub_var)
226✔
2741
                    typevar_argtypes = Any[n, lb_var, ub_var]
678✔
2742
                    effects = builtin_effects(๐•ƒแตข, Core._typevar, typevar_argtypes, pT)
262✔
2743
                    if effects.nothrow
226✔
2744
                        exct = Union{}
190✔
2745
                    else
2746
                        exct = builtin_exct(๐•ƒแตข, Core._typevar, typevar_argtypes, pT)
36✔
2747
                    end
2748
                    return CallMeta(pT, exct, effects, call.info)
226✔
2749
                end
2750
            end
2751
        end
2752
    elseif f === UnionAll
1,023,927✔
2753
        let call = abstract_call_gf_by_type(interp, f, ArgInfo(nothing, Any[Const(UnionAll), Any, Any]), si, Tuple{Type{UnionAll}, Any, Any}, sv, max_methods)::Future
1,110✔
2754
            return Future{CallMeta}(call, interp, sv) do call, interp, sv
370✔
2755
                return abstract_call_unionall(interp, argtypes, call)
1,860✔
2756
            end
2757
        end
2758
    elseif f === Tuple && la == 2
1,023,557✔
2759
        aty = argtypes[2]
95✔
2760
        ty = isvarargtype(aty) ? unwrapva(aty) : widenconst(aty)
95✔
2761
        if !isconcretetype(ty)
95✔
2762
            return Future(CallMeta(Tuple, Any, EFFECTS_UNKNOWN, NoCallInfo()))
50✔
2763
        end
2764
    elseif is_return_type(f)
2,046,586✔
2765
        return return_type_tfunc(interp, argtypes, si, sv)
338✔
2766
    elseif la == 3 && f === Core.:(!==)
1,023,124✔
2767
        # mark !== as exactly a negated call to ===
2768
        let callfuture = abstract_call_gf_by_type(interp, f, ArgInfo(fargs, Any[Const(f), Any, Any]), si, Tuple{typeof(f), Any, Any}, sv, max_methods)::Future,
8,830✔
2769
            rtfuture = abstract_call_known(interp, (===), arginfo, si, sv, max_methods)::Future
2770
            return Future{CallMeta}(isready(callfuture) && isready(rtfuture), interp, sv) do interp, sv
4,415✔
2771
                local rty = rtfuture[].rt
5,796✔
2772
                if isa(rty, Conditional)
5,796✔
2773
                    return CallMeta(Conditional(rty.slot, rty.elsetype, rty.thentype), Bottom, EFFECTS_TOTAL, NoCallInfo()) # swap if-else
5,344✔
2774
                elseif isa(rty, Const)
452✔
2775
                    return CallMeta(Const(rty.val === false), Bottom, EFFECTS_TOTAL, MethodResultPure())
156✔
2776
                end
2777
                return callfuture[]
296✔
2778
            end
2779
        end
2780
    elseif la == 3 && f === Core.:(>:)
1,018,709✔
2781
        # mark issupertype as a exact alias for issubtype
2782
        # swap T1 and T2 arguments and call <:
2783
        if fargs !== nothing && length(fargs) == 3
450✔
2784
            fargs = Any[<:, fargs[3], fargs[2]]
1,350✔
2785
        else
2786
            fargs = nothing
×
2787
        end
2788
        argtypes = Any[typeof(<:), argtypes[3], argtypes[2]]
1,350✔
2789
        return abstract_call_known(interp, <:, ArgInfo(fargs, argtypes), si, sv, max_methods)
450✔
2790
    elseif la == 2 && f === Core.typename
1,018,259✔
2791
        return Future(CallMeta(typename_static(argtypes[2]), Bottom, EFFECTS_TOTAL, MethodResultPure()))
36✔
2792
    elseif f === Core._hasmethod
1,018,223✔
2793
        return Future(_hasmethod_tfunc(interp, argtypes, sv))
12✔
2794
    end
2795
    atype = argtypes_to_type(argtypes)
1,018,256✔
2796
    return abstract_call_gf_by_type(interp, f, arginfo, si, atype, sv, max_methods)::Future
1,018,256✔
2797
end
2798

2799
function abstract_call_opaque_closure(interp::AbstractInterpreter,
×
2800
    closure::PartialOpaque, arginfo::ArgInfo, si::StmtInfo, sv::AbsIntState, check::Bool=true)
2801
    sig = argtypes_to_type(arginfo.argtypes)
×
2802
    tt = closure.typ
×
2803
    ocargsig = rewrap_unionall((unwrap_unionall(tt)::DataType).parameters[1], tt)
×
2804
    ocargsigโ€ฒ = unwrap_unionall(ocargsig)
×
2805
    ocargsigโ€ฒ isa DataType || return Future(CallMeta(Any, Any, Effects(), NoCallInfo()))
×
2806
    ocsig = rewrap_unionall(Tuple{Tuple, ocargsigโ€ฒ.parameters...}, ocargsig)
×
2807
    hasintersect(sig, ocsig) || return Future(CallMeta(Union{}, Union{MethodError,TypeError}, EFFECTS_THROWS, NoCallInfo()))
×
2808
    ocmethod = closure.source::Method
×
2809
    if !isdefined(ocmethod, :source)
×
2810
        # This opaque closure was created from optimized source. We cannot infer it further.
2811
        ocrt = rewrap_unionall((unwrap_unionall(tt)::DataType).parameters[2], tt)
×
2812
        if isa(ocrt, DataType)
×
2813
            return Future(CallMeta(ocrt, Any, Effects(), NoCallInfo()))
×
2814
        end
2815
        return Future(CallMeta(Any, Any, Effects(), NoCallInfo()))
×
2816
    end
2817
    match = MethodMatch(sig, Core.svec(), ocmethod, sig <: ocsig)
×
2818
    mresult = abstract_call_method(interp, ocmethod, sig, Core.svec(), false, si, sv)
×
2819
    ocsig_box = Core.Box(ocsig)
×
2820
    return Future{CallMeta}(mresult, interp, sv) do result, interp, sv
×
2821
        (; rt, exct, effects, call_result, edge, edgecycle) = result
186✔
2822
        ๐•ƒโ‚š = ipo_lattice(interp)
186✔
2823
        โŠ‘, โ‹ค, โŠ” = partialorder(๐•ƒโ‚š), strictneqpartialorder(๐•ƒโ‚š), join(๐•ƒโ‚š)
186✔
2824
        if !edgecycle
186✔
2825
            const_call_result = abstract_call_method_with_const_args(interp, result,
186✔
2826
                #=f=#nothing, arginfo, si, match, sv)
2827
            if const_call_result !== nothing
186✔
2828
                const_result = const_edge = nothing
57✔
2829
                if const_call_result.rt โŠ‘ rt
57✔
2830
                    (; rt, effects, const_result, const_edge) = const_call_result
57✔
2831
                end
2832
                if const_call_result.exct โ‹ค exct
57✔
2833
                    (; exct, const_result, const_edge) = const_call_result
21✔
2834
                end
2835
                if const_edge !== nothing
57✔
2836
                    edge = const_edge
57✔
2837
                    update_valid_age!(sv, get_inference_world(interp), world_range(const_edge))
57✔
2838
                end
2839
                if const_result !== nothing
57✔
2840
                    call_result = const_result
57✔
2841
                end
2842
            end
2843
        end
2844
        if check # analyze implicit type asserts on argument and return type
186✔
2845
            ftt = closure.typ
69✔
2846
            rty = (unwrap_unionall(ftt)::DataType).parameters[2]
69✔
2847
            rty = rewrap_unionall(rty isa TypeVar ? rty.ub : rty, ftt)
138✔
2848
            if !(rt โŠ‘ rty && sig โŠ‘ ocsig_box.contents)
69✔
2849
                effects = Effects(effects; nothrow=false)
6✔
2850
                exct = exct โŠ” TypeError
6✔
2851
            end
2852
        end
2853
        rt = from_interprocedural!(interp, rt, sv, arginfo, match.spec_types)
186✔
2854
        info = OpaqueClosureCallInfo(edge, match, call_result)
372✔
2855
        return CallMeta(rt, exct, effects, info)
186✔
2856
    end
2857
end
2858

2859
function most_general_argtypes(closure::PartialOpaque)
2860
    cc = widenconst(closure)
×
2861
    argt = (unwrap_unionall(cc)::DataType).parameters[1]
×
2862
    if !isa(argt, DataType) || argt.name !== typename(Tuple)
×
2863
        argt = Tuple
×
2864
    end
2865
    return Any[argt.parameters...]
×
2866
end
2867

2868
function abstract_call_unknown(interp::AbstractInterpreter, @nospecialize(ft),
5,026✔
2869
                               arginfo::ArgInfo, si::StmtInfo, sv::AbsIntState,
2870
                               max_methods::Int)
2871
    if isa(ft, PartialOpaque)
5,026✔
2872
        newargtypes = copy(arginfo.argtypes)
×
2873
        newargtypes[1] = ft.env
×
2874
        return abstract_call_opaque_closure(interp,
×
2875
            ft, ArgInfo(arginfo.fargs, newargtypes), si, sv, #=check=#true)
2876
    end
2877
    wft = widenconst(ft)
5,026✔
2878
    if hasintersect(wft, Builtin)
5,026✔
2879
        add_remark!(interp, sv, "Could not identify method table for call")
75✔
2880
        return Future(CallMeta(Any, Any, Effects(), NoCallInfo()))
75✔
2881
    elseif hasintersect(wft, Core.OpaqueClosure)
4,951✔
2882
        uft = unwrap_unionall(wft)
×
2883
        if isa(uft, DataType)
×
2884
            return Future(CallMeta(rewrap_unionall(uft.parameters[2], wft), Any, Effects(), NoCallInfo()))
×
2885
        end
2886
        return Future(CallMeta(Any, Any, Effects(), NoCallInfo()))
×
2887
    end
2888
    # non-constant function, but the number of arguments is known and the `f` is not a builtin or intrinsic
2889
    atype = argtypes_to_type(arginfo.argtypes)
4,951✔
2890
    atype === Bottom && return Future(CallMeta(Union{}, Union{}, EFFECTS_THROWS, NoCallInfo())) # accidentally unreachable
4,951✔
2891
    return abstract_call_gf_by_type(interp, nothing, arginfo, si, atype, sv, max_methods)::Future
4,951✔
2892
end
2893

2894
# call where the function is any lattice element
2895
function abstract_call(interp::AbstractInterpreter, arginfo::ArgInfo, si::StmtInfo,
1,658,815✔
2896
                       sv::AbsIntState, max_methods::Int=typemin(Int))
2897
    ft = widenslotwrapper(arginfo.argtypes[1])
3,293,464✔
2898
    f = singleton_type(ft)
1,663,638✔
2899
    if f === nothing
1,658,680✔
2900
        max_methods = max_methods == typemin(Int) ? get_max_methods(interp, sv) : max_methods
9,898✔
2901
        return abstract_call_unknown(interp, ft, arginfo, si, sv, max_methods)
5,026✔
2902
    end
2903
    max_methods = max_methods == typemin(Int) ? get_max_methods(interp, f, sv) : max_methods
3,276,313✔
2904
    return abstract_call_known(interp, f, arginfo, si, sv, max_methods)
1,653,654✔
2905
end
2906

2907
function sp_type_rewrap(@nospecialize(T), mi::MethodInstance, isreturn::Bool)
661✔
2908
    isref = false
661✔
2909
    if unwrapva(T) === Bottom
661✔
2910
        return Bottom
×
2911
    elseif isa(T, Type)
661✔
2912
        if isa(T, DataType) && (T::DataType).name === Ref.body.name
661✔
2913
            isref = true
75✔
2914
            T = T.parameters[1]
75✔
2915
            if isreturn && T === Any
75✔
2916
                return Bottom # a return type of Ref{Any} is invalid
×
2917
            end
2918
        end
2919
    else
2920
        return Any
×
2921
    end
2922
    if isa(mi.def, Method)
661✔
2923
        spsig = mi.def.sig
661✔
2924
        if isa(spsig, UnionAll)
661✔
2925
            if !isempty(mi.sparam_vals)
102✔
2926
                sparam_vals = Any[isvarargtype(v) ? TypeVar(:N, Union{}, Any) :
198✔
2927
                                  v for v in  mi.sparam_vals]
2928
                T = ccall(:jl_instantiate_type_in_env, Any, (Any, Any, Ptr{Any}), T, spsig, sparam_vals)
102✔
2929
                isref && isreturn && T === Any && return Bottom # catch invalid return Ref{T} where T = Any
102✔
2930
                for v in sparam_vals
102✔
2931
                    if isa(v, TypeVar)
198✔
2932
                        T = UnionAll(v, T)
64✔
2933
                    end
2934
                end
198✔
2935
                if has_free_typevars(T)
102✔
2936
                    fv = ccall(:jl_find_free_typevars, Vector{Any}, (Any,), T)
×
2937
                    for v in fv
×
2938
                        T = UnionAll(v, T)
×
2939
                    end
×
2940
                end
2941
            else
2942
                T = rewrap_unionall(T, spsig)
×
2943
            end
2944
        end
2945
    end
2946
    return unwraptv(T)
661✔
2947
end
2948

2949
function abstract_eval_cfunction(interp::AbstractInterpreter, e::Expr, sstate::StatementState, sv::AbsIntState)
84✔
2950
    f = abstract_eval_value(interp, e.args[2], sstate, sv)
168✔
2951
    # rt = sp_type_rewrap(e.args[3], sv.linfo, true) # verify that the result type make sense?
2952
    # rt === Bottom && return RTEffects(Union{}, Any, EFFECTS_UNKNOWN)
2953
    atv = e.args[4]::SimpleVector
84✔
2954
    at = Vector{Any}(undef, length(atv) + 1)
84✔
2955
    at[1] = f
84✔
2956
    for i = 1:length(atv)
132✔
2957
        atแตข = at[i + 1] = sp_type_rewrap(atv[i], frame_instance(sv), false)
108✔
2958
        atแตข === Bottom && return RTEffects(Union{}, Any, EFFECTS_UNKNOWN)
108✔
2959
    end
132✔
2960
    # this may be the wrong world for the call,
2961
    # but some of the result is likely to be valid anyways
2962
    # and that may help generate better codegen
2963
    abstract_call(interp, ArgInfo(nothing, at), StmtInfo(false, false), sv)::Future
84✔
2964
    rt = e.args[1]
84✔
2965
    isconcretetype(rt) || (rt = Any)
84✔
2966
    return RTEffects(rt, Any, EFFECTS_UNKNOWN)
84✔
2967
end
2968

2969
function abstract_eval_special_value(interp::AbstractInterpreter, @nospecialize(e), sstate::StatementState, sv::AbsIntState)
7,836,459✔
2970
    if isa(e, SSAValue)
7,836,684✔
2971
        return RTEffects(abstract_eval_ssavalue(e, sv), Union{}, EFFECTS_TOTAL)
3,426,829✔
2972
    elseif isa(e, SlotNumber)
4,409,855✔
2973
        if sstate.vtypes !== nothing
1,709,247✔
2974
            vtyp = sstate.vtypes[slot_id(e)]
1,709,247✔
2975
            if !vtyp.undef
1,709,247✔
2976
                return RTEffects(vtyp.typ, Union{}, EFFECTS_TOTAL)
1,708,518✔
2977
            end
2978
            return RTEffects(vtyp.typ, UndefVarError, EFFECTS_THROWS)
729✔
2979
        end
2980
        return RTEffects(Any, UndefVarError, EFFECTS_THROWS)
×
2981
    elseif isa(e, Argument)
2,700,608✔
2982
        if sstate.vtypes !== nothing
84✔
2983
            return RTEffects(sstate.vtypes[slot_id(e)].typ, Union{}, EFFECTS_TOTAL)
×
2984
        else
2985
            @assert isa(sv, IRInterpretationState)
84✔
2986
            return RTEffects(sv.ir.argtypes[e.n], Union{}, EFFECTS_TOTAL) # TODO frame_argtypes(sv)[e.n] and remove the assertion
84✔
2987
        end
2988
    elseif isa(e, GlobalRef)
2,700,524✔
2989
        # No need for an edge since an explicit GlobalRef will be picked up by the source scan
2990
        return abstract_eval_globalref(interp, e, sstate.saw_latestworld, sv)
1,892,848✔
2991
    end
2992
    if isa(e, QuoteNode)
807,676✔
2993
        e = e.value
168,914✔
2994
    end
2995
    effects = Effects(EFFECTS_TOTAL;
807,676✔
2996
        inaccessiblememonly = is_mutation_free_argtype(typeof(e)) ? ALWAYS_TRUE : ALWAYS_FALSE)
2997
    return RTEffects(Const(e), Union{}, effects)
807,676✔
2998
end
2999

3000
function abstract_eval_value_expr(interp::AbstractInterpreter, e::Expr, sv::AbsIntState)
12✔
3001
    if e.head === :call && length(e.args) โ‰ฅ 1
12✔
3002
        # TODO: We still have non-linearized cglobal
3003
        @assert e.args[1] === Core.tuple || e.args[1] === GlobalRef(Core, :tuple)
24✔
3004
    else
3005
        @assert e.head !== :(=)
×
3006
        # Some of our tests expect us to handle invalid IR here and error later
3007
        # - permit that for now.
3008
        # @assert false "Unexpected EXPR head in value position"
3009
        merge_effects!(interp, sv, EFFECTS_UNKNOWN)
×
3010
    end
3011
    return Any
12✔
3012
end
3013

3014
function abstract_eval_value(interp::AbstractInterpreter, @nospecialize(e), sstate::StatementState, sv::AbsIntState)
222✔
3015
    if isa(e, Expr)
5,596,203✔
3016
        return abstract_eval_value_expr(interp, e, sv)
12✔
3017
    else
3018
        (;rt, effects) = abstract_eval_special_value(interp, e, sstate, sv)
5,596,191✔
3019
        merge_effects!(interp, sv, effects)
10,566,304✔
3020
        return collect_limitations!(rt, sv)
5,596,191✔
3021
    end
3022
end
3023

3024
function collect_argtypes(interp::AbstractInterpreter, ea::Vector{Any}, sstate::StatementState, sv::AbsIntState)
1,633,254✔
3025
    n = length(ea)
1,633,570✔
3026
    argtypes = Vector{Any}(undef, n)
1,633,570✔
3027
    @inbounds for i = 1:n
1,998,722✔
3028
        ai = abstract_eval_value(interp, ea[i], sstate, sv)
9,648,495✔
3029
        if ai === Bottom
4,824,725✔
3030
            return nothing
×
3031
        end
3032
        argtypes[i] = ai
4,824,725✔
3033
    end
8,015,880✔
3034
    return argtypes
1,633,570✔
3035
end
3036

3037
struct RTEffects
3038
    rt::Any
3039
    exct::Any
3040
    effects::Effects
3041
    refinements # ::Union{Nothing,SlotRefinement,Vector{Any}}
3042
    function RTEffects(rt, exct, effects::Effects, refinements=nothing)
3043
        @nospecialize rt exct refinements
13,015,109✔
3044
        return new(rt, exct, effects, refinements)
27,459,572✔
3045
    end
3046
end
3047

3048
CallMeta(rte::RTEffects, info::CallInfo) =
5,866✔
3049
    CallMeta(rte.rt, rte.exct, rte.effects, info, rte.refinements)
3050

3051
function abstract_call(interp::AbstractInterpreter, arginfo::ArgInfo, sstate::StatementState, sv::InferenceState)
1,634,399✔
3052
    unused = call_result_unused(sv, sv.currpc)
1,634,399✔
3053
    if unused
1,634,399✔
3054
        add_curr_ssaflag!(sv, IR_FLAG_UNUSED)
89,975✔
3055
    end
3056
    si = StmtInfo(!unused, sstate.saw_latestworld)
1,634,399✔
3057
    call = abstract_call(interp, arginfo, si, sv)::Future
1,634,399✔
3058
    Future{Any}(call, interp, sv) do call, _, sv
1,634,399✔
3059
        # this only is needed for the side-effect, sequenced before any task tries to consume the return value,
3060
        # which this will do even without returning this Future
3061
        sv.stmt_info[sv.currpc] = call.info
3,314,755✔
3062
        nothing
3,314,755✔
3063
    end
3064
    return call
1,634,399✔
3065
end
3066

3067
function abstract_eval_call(interp::AbstractInterpreter, e::Expr, sstate::StatementState,
305✔
3068
                            sv::AbsIntState)
3069
    ea = e.args
1,634,700✔
3070
    argtypes = collect_argtypes(interp, ea, sstate, sv)
1,635,601✔
3071
    if argtypes === nothing
1,634,700✔
3072
        return Future(RTEffects(Bottom, Any, Effects()))
×
3073
    end
3074
    arginfo = ArgInfo(ea, argtypes)
1,634,700✔
3075
    call = abstract_call(interp, arginfo, sstate, sv)::Future
1,634,700✔
3076
    return Future{RTEffects}(call, interp, sv) do call, _, _
1,634,700✔
3077
        (; rt, exct, effects, refinements) = call
3,315,894✔
3078
        return RTEffects(rt, exct, effects, refinements)
3,315,894✔
3079
    end
3080
end
3081

3082
function is_field_pointerfree(dt::DataType, fidx::Int)
3083
    dt.layout::Ptr{Cvoid} == C_NULL && return false
146✔
3084
    DataTypeFieldDesc(dt)[fidx].isptr && return false
146✔
3085
    ft = fieldtype(dt, fidx)
50✔
3086
    return ft isa DataType && datatype_pointerfree(ft)
50✔
3087
end
3088

3089
function abstract_eval_new(interp::AbstractInterpreter, e::Expr, sstate::StatementState,
25,406✔
3090
                           sv::AbsIntState)
3091
    ๐•ƒแตข = typeinf_lattice(interp)
25,406✔
3092
    rt, _... = instanceof_tfunc(abstract_eval_value(interp, e.args[1], sstate, sv), true)
50,812✔
3093
    ut = unwrap_unionall(rt)
25,406✔
3094
    exct = Union{ErrorException,TypeError}
25,406✔
3095
    if isa(ut, DataType) && !isabstracttype(ut)
25,406✔
3096
        ismutable = ismutabletype(ut)
25,367✔
3097
        fcount = datatype_fieldcount(ut)
25,367✔
3098
        nargs = length(e.args) - 1
25,367✔
3099
        has_any_uninitialized = fcount === nothing || (fcount > nargs &&
50,734✔
3100
            any(i::Int->is_field_pointerfree(ut, i), (nargs+1):fcount))
292✔
3101
        if has_any_uninitialized
25,367✔
3102
            # allocation with undefined field is inconsistent always
3103
            consistent = ALWAYS_FALSE
50✔
3104
        elseif ismutable
25,317✔
3105
            # mutable allocation isn't `:consistent`, but we still have a chance that
3106
            # return type information later refines the `:consistent`-cy of the method
3107
            consistent = CONSISTENT_IF_NOTRETURNED
4,963✔
3108
        else
3109
            consistent = ALWAYS_TRUE # immutable allocation is consistent
20,354✔
3110
        end
3111
        if isconcretedispatch(rt)
50,242✔
3112
            nothrow = true
24,875✔
3113
            @assert fcount !== nothing && fcount โ‰ฅ nargs "malformed :new expression" # syntactically enforced by the front-end
24,875✔
3114
            ats = Vector{Any}(undef, nargs)
24,875✔
3115
            local anyrefine = false
24,875✔
3116
            local allconst = true
24,875✔
3117
            for i = 1:nargs
38,179✔
3118
                at = widenslotwrapper(abstract_eval_value(interp, e.args[i+1], sstate, sv))
49,637✔
3119
                ft = fieldtype(rt, i)
49,250✔
3120
                nothrow && (nothrow = โŠ‘(๐•ƒแตข, at, ft))
49,250✔
3121
                at = tmeet(๐•ƒแตข, at, ft)
49,250✔
3122
                at === Bottom && return RTEffects(Bottom, TypeError, EFFECTS_THROWS)
49,250✔
3123
                if ismutable && !isconst(rt, i)
53,746✔
3124
                    ats[i] = ft # can't constrain this field (as it may be modified later)
9,232✔
3125
                    continue
9,232✔
3126
                end
3127
                allconst &= isa(at, Const)
40,018✔
3128
                if !anyrefine
40,018✔
3129
                    anyrefine = has_nontrivial_extended_info(๐•ƒแตข, at) || # extended lattice information
42,291✔
3130
                                โ‹ค(๐•ƒแตข, at, ft) # just a type-level information, but more precise than the declared type
3131
                end
3132
                ats[i] = at
40,018✔
3133
            end
74,891✔
3134
            if fcount == nargs && consistent === ALWAYS_TRUE && allconst
24,875✔
3135
                argvals = Vector{Any}(undef, nargs)
10,052✔
3136
                for j in 1:nargs
17,368✔
3137
                    argvals[j] = (ats[j]::Const).val
16,517✔
3138
                end
24,170✔
3139
                rt = Const(ccall(:jl_new_structv, Any, (Any, Ptr{Cvoid}, UInt32), rt, argvals, nargs))
10,052✔
3140
            elseif anyrefine || nargs > datatype_min_ninitialized(rt)
22,861✔
3141
                # propagate partially initialized struct as `PartialStruct` when:
3142
                # - any refinement information is available (`anyrefine`), or when
3143
                # - `nargs` is greater than `n_initialized` derived from the struct type
3144
                #   information alone
3145
                undefs = Union{Nothing,Bool}[false for _ in 1:nargs]
15,176✔
3146
                if nargs < fcount # fill in uninitialized fields
7,004✔
3147
                    for i = (nargs+1):fcount
12✔
3148
                        ft = fieldtype(rt, i)
6✔
3149
                        push!(ats, ft)
6✔
3150
                        if ft === Union{} # `Union{}`-typed field is never initialized
6✔
3151
                            push!(undefs, true)
×
3152
                        elseif isconcretetype(ft) && datatype_pointerfree(ft) # this check is probably incomplete
6✔
3153
                            push!(undefs, false)
×
3154
                        # TODO If we can implement the query such that it accurately
3155
                        #      identifies fields that never be `#undef'd, we can make the
3156
                        #      following improvements:
3157
                        # elseif is_field_pointerfree(rt, i)
3158
                        #     push!(undefs, false)
3159
                        # elseif ismutable && !isconst(rt, i) # can't constrain this field (as it may be modified later)
3160
                        #     push!(undefs, nothing)
3161
                        # else
3162
                        #     push!(undefs, true)
3163
                        else
3164
                            push!(undefs, nothing)
6✔
3165
                        end
3166
                    end
6✔
3167
                end
3168
                rt = PartialStruct(๐•ƒแตข, rt, undefs, ats)
7,004✔
3169
            end
3170
        else
3171
            rt = refine_partial_type(rt)
984✔
3172
            nothrow = false
492✔
3173
        end
3174
    else
3175
        consistent = ALWAYS_FALSE
39✔
3176
        nothrow = false
39✔
3177
    end
3178
    nothrow && (exct = Union{})
25,406✔
3179
    effects = Effects(EFFECTS_TOTAL; consistent, nothrow)
25,406✔
3180
    return RTEffects(rt, exct, effects)
25,406✔
3181
end
3182

3183
function abstract_eval_splatnew(interp::AbstractInterpreter, e::Expr, sstate::StatementState,
2,476✔
3184
                                sv::AbsIntState)
3185
    ๐•ƒแตข = typeinf_lattice(interp)
2,476✔
3186
    rt, isexact = instanceof_tfunc(abstract_eval_value(interp, e.args[1], sstate, sv), true)
4,952✔
3187
    nothrow = false
2,476✔
3188
    if length(e.args) == 2 && isconcretedispatch(rt) && !ismutabletype(rt)
4,820✔
3189
        at = abstract_eval_value(interp, e.args[2], sstate, sv)
4,688✔
3190
        n = fieldcount(rt)
2,344✔
3191
        if (isa(at, Const) && isa(at.val, Tuple) && n == length(at.val::Tuple) &&
2,344✔
3192
            (let t = rt, at = at
3193
                all(i::Int -> getfield(at.val::Tuple, i) isa fieldtype(t, i), 1:n)
2,717✔
3194
            end))
3195
            nothrow = isexact
1,185✔
3196
            rt = Const(ccall(:jl_new_structt, Any, (Any, Any), rt, at.val))
1,185✔
3197
        elseif at isa PartialStruct
1,159✔
3198
            if โŠ‘(๐•ƒแตข, at, Tuple) && n > 0
152✔
3199
                fields = at.fields
152✔
3200
                if (n == length(fields) && !isvarargtype(fields[end]) &&
152✔
3201
                    (let t = rt
3202
                        all(i::Int -> โŠ‘(๐•ƒแตข, fields[i], fieldtype(t, i)), 1:n)
621✔
3203
                    end))
3204
                    nothrow = isexact
152✔
3205
                    undefs = Union{Nothing,Bool}[false for _ in 1:n]
469✔
3206
                    rt = PartialStruct(๐•ƒแตข, rt, undefs, fields)
152✔
3207
                end
3208
            end
3209
        end
3210
    else
3211
        rt = refine_partial_type(rt)
132✔
3212
    end
3213
    consistent = !ismutabletype(rt) ? ALWAYS_TRUE : CONSISTENT_IF_NOTRETURNED
3,813✔
3214
    effects = Effects(EFFECTS_TOTAL; consistent, nothrow)
2,476✔
3215
    return RTEffects(rt, Any, effects)
2,476✔
3216
end
3217

3218
function abstract_eval_new_opaque_closure(interp::AbstractInterpreter, e::Expr, sstate::StatementState,
×
3219
                                          sv::AbsIntState)
3220
    ๐•ƒแตข = typeinf_lattice(interp)
×
3221
    rt = Union{}
×
3222
    effects = Effects() # TODO
×
3223
    if length(e.args) >= 5
×
3224
        ea = e.args
×
3225
        argtypes = collect_argtypes(interp, ea, sstate, sv)
×
3226
        if argtypes === nothing
×
3227
            rt = Bottom
×
3228
            effects = EFFECTS_THROWS
×
3229
        else
3230
            mi = frame_instance(sv)
×
3231
            rt = opaque_closure_tfunc(๐•ƒแตข, argtypes[1], argtypes[2], argtypes[3],
×
3232
                argtypes[5], argtypes[6:end], mi)
3233
            if ea[4] !== true && isa(rt, PartialOpaque)
×
3234
                rt = widenconst(rt)
×
3235
                # Propagation of PartialOpaque disabled
3236
            end
3237
            if isa(rt, PartialOpaque) && isa(sv, InferenceState) && !call_result_unused(sv, sv.currpc)
×
3238
                # Infer this now so that the specialization is available to
3239
                # optimization.
3240
                argtypes = most_general_argtypes(rt)
×
3241
                pushfirst!(argtypes, rt.env)
×
3242
                callinfo = abstract_call_opaque_closure(interp, rt,
×
3243
                    ArgInfo(nothing, argtypes), StmtInfo(true, false), sv, #=check=#false)::Future
3244
                Future{Any}(callinfo, interp, sv) do callinfo, _, sv
×
3245
                    sv.stmt_info[sv.currpc] = OpaqueClosureCreateInfo(callinfo)
114✔
3246
                    nothing
3✔
3247
                end
3248
            end
3249
        end
3250
    end
3251
    return Future(RTEffects(rt, Any, effects))
×
3252
end
3253

3254
function abstract_eval_copyast(interp::AbstractInterpreter, e::Expr, sstate::StatementState,
3255
                               sv::AbsIntState)
3256
    effects = EFFECTS_UNKNOWN
51✔
3257
    rt = abstract_eval_value(interp, e.args[1], sstate, sv)
102✔
3258
    if rt isa Const && rt.val isa Expr
51✔
3259
        # `copyast` makes copies of Exprs
3260
        rt = Expr
51✔
3261
    end
3262
    return RTEffects(rt, Any, effects)
51✔
3263
end
3264

3265
function abstract_eval_isdefined_expr(::AbstractInterpreter, e::Expr, sstate::StatementState,
×
3266
                                      sv::AbsIntState)
3267
    sym = e.args[1]
2,133✔
3268
    if isa(sym, SlotNumber) && sstate.vtypes !== nothing
2,133✔
3269
        vtyp = sstate.vtypes[slot_id(sym)]
1,710✔
3270
        if vtyp.typ === Bottom
1,710✔
3271
            rt = Const(false) # never assigned previously
21✔
3272
        elseif !vtyp.undef
1,689✔
3273
            rt = Const(true) # definitely assigned previously
603✔
3274
        else # form `Conditional` to refine `vtyp.undef` in the then branch
3275
            rt = Conditional(sym, widenslotwrapper(vtyp.typ), widenslotwrapper(vtyp.typ); isdefined=true)
1,086✔
3276
        end
3277
        return RTEffects(rt, Union{}, EFFECTS_TOTAL)
2,334✔
3278
    end
3279
    rt = Bool
423✔
3280
    effects = EFFECTS_TOTAL
423✔
3281
    exct = Union{}
423✔
3282
    if isexpr(sym, :static_parameter)
423✔
3283
        n = sym.args[1]::Int
423✔
3284
        if 1 <= n <= length(sv.sptypes)
423✔
3285
            sp = sv.sptypes[n]
423✔
3286
            if !sp.undef
423✔
3287
                rt = Const(true)
387✔
3288
            elseif sp.typ === Bottom
36✔
3289
                rt = Const(false)
×
3290
            end
3291
        end
3292
    else
3293
        effects = EFFECTS_UNKNOWN
×
3294
        exct = Any
×
3295
    end
3296
    return RTEffects(rt, exct, effects)
423✔
3297
end
3298

3299
const generic_isdefinedglobal_effects = Effects(EFFECTS_TOTAL, consistent=ALWAYS_FALSE, nothrow=false)
3300
function abstract_eval_isdefinedglobal(interp::AbstractInterpreter, mod::Module, sym::Symbol, allow_import::Union{Bool, Nothing}, saw_latestworld::Bool, sv::AbsIntState)
57✔
3301
    rt = Bool
57✔
3302
    if saw_latestworld
57✔
3303
        return CallMeta(RTEffects(rt, Union{}, Effects(generic_isdefinedglobal_effects, nothrow=true)), NoCallInfo())
×
3304
    end
3305

3306
    effects = EFFECTS_TOTAL
57✔
3307
    gr = GlobalRef(mod, sym)
57✔
3308
    if allow_import !== true
57✔
3309
        gr = GlobalRef(mod, sym)
×
3310
        partition = lookup_binding_partition!(interp, gr, sv)
×
3311
        if allow_import !== true && is_some_binding_imported(binding_kind(partition))
×
3312
            if allow_import === false
×
3313
                rt = Const(false)
×
3314
            else
3315
                effects = Effects(generic_isdefinedglobal_effects, nothrow=true)
×
3316
            end
3317
            @goto done
×
3318
        end
3319
    end
3320

3321
    world = get_inference_world(interp)
57✔
3322
    (valid_worlds, rte) = abstract_load_all_consistent_leaf_partitions(interp, gr, binding_world_hints(world, sv))
57✔
3323
    # XXX: it is unsound to ignore valid_worlds here
3324
    if rte.exct == Union{}
57✔
3325
        rt = Const(true)
33✔
3326
    elseif rte.rt === Union{} && rte.exct === UndefVarError
24✔
3327
        rt = Const(false)
×
3328
    else
3329
        effects = Effects(generic_isdefinedglobal_effects, nothrow=true)
24✔
3330
    end
3331
@label done
3332
    return CallMeta(RTEffects(rt, Union{}, effects), GlobalAccessInfo(convert(Core.Binding, gr)))
57✔
3333
end
3334

3335
function abstract_eval_isdefinedglobal(interp::AbstractInterpreter, @nospecialize(M), @nospecialize(s), @nospecialize(allow_import_arg), @nospecialize(order_arg), saw_latestworld::Bool, sv::AbsIntState)
156✔
3336
    exct = Bottom
156✔
3337
    allow_import = true
156✔
3338
    if allow_import_arg !== nothing
156✔
3339
        if !isa(allow_import_arg, Const)
156✔
3340
            allow_import = nothing
×
3341
            if widenconst(allow_import_arg) != Bool
×
3342
                exct = Union{exct, TypeError}
×
3343
            end
3344
        else
3345
            allow_import = allow_import_arg.val
156✔
3346
        end
3347
    end
3348
    if order_arg !== nothing
156✔
3349
        exct = global_order_exct(order_arg, #=loading=#true, #=storing=#false)
156✔
3350
        if !(isa(order_arg, Const) && get_atomic_order(order_arg.val, #=loading=#true, #=storing=#false).x >= MEMORY_ORDER_UNORDERED.x)
312✔
3351
            exct = Union{exct, ConcurrencyViolationError}
×
3352
        end
3353
    end
3354
    โŠ‘ = partialorder(typeinf_lattice(interp))
156✔
3355
    if M isa Const && s isa Const
156✔
3356
        M, s = M.val, s.val
57✔
3357
        if M isa Module && s isa Symbol
57✔
3358
            return merge_exct(abstract_eval_isdefinedglobal(interp, M, s, allow_import, saw_latestworld, sv), exct)
57✔
3359
        end
3360
        return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
×
3361
    elseif !hasintersect(widenconst(M), Module) || !hasintersect(widenconst(s), Symbol)
198✔
3362
        return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
×
3363
    elseif M โŠ‘ Module && s โŠ‘ Symbol
99✔
3364
        return CallMeta(Bool, Union{exct, UndefVarError}, generic_isdefinedglobal_effects, NoCallInfo())
99✔
3365
    end
3366
    return CallMeta(Bool, Union{exct, TypeError, UndefVarError}, generic_isdefinedglobal_effects, NoCallInfo())
×
3367
end
3368

3369
function abstract_eval_isdefinedglobal(interp::AbstractInterpreter, sv::AbsIntState, saw_latestworld::Bool, argtypes::Vector{Any})
3370
    if !isvarargtype(argtypes[end])
129✔
3371
        if 3 <= length(argtypes) <= 5
129✔
3372
            return abstract_eval_isdefinedglobal(interp, argtypes[2], argtypes[3],
129✔
3373
                length(argtypes) >= 4 ? argtypes[4] : Const(true),
3374
                length(argtypes) >= 5 ? argtypes[5] : Const(:unordered),
3375
                saw_latestworld, sv)
3376
        else
3377
            return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
×
3378
        end
3379
    elseif length(argtypes) > 6
×
3380
        return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
×
3381
    else
3382
        return CallMeta(Bool, Union{ConcurrencyViolationError, TypeError, UndefVarError}, generic_isdefinedglobal_effects, NoCallInfo())
×
3383
    end
3384
end
3385

3386
function abstract_eval_throw_undef_if_not(interp::AbstractInterpreter, e::Expr, sstate::StatementState, sv::AbsIntState)
×
3387
    condt = abstract_eval_value(interp, e.args[2], sstate, sv)
×
3388
    condval = maybe_extract_const_bool(condt)
×
3389
    rt = Nothing
×
3390
    exct = UndefVarError
×
3391
    effects = EFFECTS_THROWS
×
3392
    if condval isa Bool
×
3393
        if condval
×
3394
            effects = EFFECTS_TOTAL
×
3395
            exct = Union{}
×
3396
        else
3397
            rt = Union{}
×
3398
        end
3399
    elseif !hasintersect(widenconst(condt), Bool)
×
3400
        rt = Union{}
×
3401
    end
3402
    return RTEffects(rt, exct, effects)
×
3403
end
3404

3405
function abstract_eval_the_exception(::AbstractInterpreter, sv::InferenceState)
3406
    (;handler_info) = sv
1,205✔
3407
    if handler_info === nothing
1,205✔
3408
        return the_exception_info(Any)
×
3409
    end
3410
    (;handlers, handler_at) = handler_info
1,205✔
3411
    handler_id = handler_at[sv.currpc][2]
1,205✔
3412
    if handler_id === 0
1,205✔
3413
        return the_exception_info(Any)
×
3414
    end
3415
    return the_exception_info(handlers[handler_id].exct)
1,205✔
3416
end
3417
abstract_eval_the_exception(::AbstractInterpreter, ::IRInterpretationState) = the_exception_info(Any)
×
3418
the_exception_info(@nospecialize t) = RTEffects(t, Union{}, Effects(EFFECTS_TOTAL; consistent=ALWAYS_FALSE))
1,205✔
3419

3420
function abstract_eval_static_parameter(::AbstractInterpreter, e::Expr, sv::AbsIntState)
3421
    n = e.args[1]::Int
105,170✔
3422
    nothrow = false
105,160✔
3423
    if 1 <= n <= length(sv.sptypes)
105,170✔
3424
        sp = sv.sptypes[n]
105,170✔
3425
        rt = sp.typ
105,170✔
3426
        nothrow = !sp.undef
105,170✔
3427
    else
3428
        rt = Any
×
3429
    end
3430
    exct = nothrow ? Union{} : UndefVarError
105,170✔
3431
    effects = Effects(EFFECTS_TOTAL; nothrow)
105,170✔
3432
    return RTEffects(rt, exct, effects)
106,070✔
3433
end
3434

3435
function abstract_eval_statement_expr(interp::AbstractInterpreter, e::Expr, sstate::StatementState,
1,790,050✔
3436
                                      sv::AbsIntState)::Future{RTEffects}
3437
    ehead = e.head
1,790,050✔
3438
    if ehead === :call
1,790,050✔
3439
        return abstract_eval_call(interp, e, sstate, sv)
1,634,700✔
3440
    elseif ehead === :new
155,350✔
3441
        return abstract_eval_new(interp, e, sstate, sv)
25,463✔
3442
    elseif ehead === :splatnew
129,887✔
3443
        return abstract_eval_splatnew(interp, e, sstate, sv)
2,476✔
3444
    elseif ehead === :new_opaque_closure
127,411✔
3445
        return abstract_eval_new_opaque_closure(interp, e, sstate, sv)
×
3446
    elseif ehead === :foreigncall
127,411✔
3447
        return abstract_eval_foreigncall(interp, e, sstate, sv)
4,767✔
3448
    elseif ehead === :cfunction
122,644✔
3449
        return abstract_eval_cfunction(interp, e, sstate, sv)
84✔
3450
    elseif ehead === :method
122,560✔
3451
        rt = (length(e.args) == 1) ? Any : Method
×
3452
        return RTEffects(rt, Any, EFFECTS_UNKNOWN)
×
3453
    elseif ehead === :copyast
122,560✔
3454
        return abstract_eval_copyast(interp, e, sstate, sv)
51✔
3455
    elseif ehead === :invoke || ehead === :invoke_modify
245,018✔
3456
        error("type inference data-flow error: tried to double infer a function")
×
3457
    elseif ehead === :isdefined
122,509✔
3458
        return abstract_eval_isdefined_expr(interp, e, sstate, sv)
2,133✔
3459
    elseif ehead === :throw_undef_if_not
120,376✔
3460
        return abstract_eval_throw_undef_if_not(interp, e, sstate, sv)
×
3461
    elseif ehead === :boundscheck
120,376✔
3462
        return RTEffects(Bool, Union{}, Effects(EFFECTS_TOTAL; consistent=ALWAYS_FALSE))
9,952✔
3463
    elseif ehead === :the_exception
110,424✔
3464
        return abstract_eval_the_exception(interp, sv)
1,205✔
3465
    elseif ehead === :static_parameter
109,219✔
3466
        return abstract_eval_static_parameter(interp, e, sv)
105,170✔
3467
    elseif ehead === :gc_preserve_begin || ehead === :aliasscope
6,686✔
3468
        return RTEffects(Any, Union{}, Effects(EFFECTS_TOTAL; consistent=ALWAYS_FALSE, effect_free=EFFECT_FREE_GLOBALLY))
1,412✔
3469
    elseif ehead === :gc_preserve_end || ehead === :leave || ehead === :pop_exception || ehead === :popaliasscope
3,865✔
3470
        return RTEffects(Nothing, Union{}, Effects(EFFECTS_TOTAL; effect_free=EFFECT_FREE_GLOBALLY))
2,631✔
3471
    elseif ehead === :thunk
6✔
3472
        return RTEffects(Any, Any, Effects())
6✔
3473
    end
3474
    # N.B.: abstract_eval_value_expr can modify the global effects, but
3475
    # we move out any arguments with effects during SSA construction later
3476
    # and recompute the effects.
3477
    rt = abstract_eval_value_expr(interp, e, sv)
×
3478
    return RTEffects(rt, Any, EFFECTS_TOTAL)
×
3479
end
3480

3481
# refine the result of instantiation of partially-known type `t` if some invariant can be assumed
3482
function refine_partial_type(@nospecialize t)
3483
    tโ€ฒ = unwrap_unionall(t)
1,447✔
3484
    if isa(tโ€ฒ, DataType) && tโ€ฒ.name === _NAMEDTUPLE_NAME && length(tโ€ฒ.parameters) == 2 &&
756✔
3485
        (tโ€ฒ.parameters[1] === () || tโ€ฒ.parameters[2] === Tuple{})
3486
        # if the first/second parameter of `NamedTuple` is known to be empty,
3487
        # the second/first argument should also be empty tuple type,
3488
        # so refine it here
3489
        return Const((;))
×
3490
    end
3491
    return t
624✔
3492
end
3493

3494
function abstract_eval_foreigncall(interp::AbstractInterpreter, e::Expr, sstate::StatementState, sv::AbsIntState)
4,763✔
3495
    callee = e.args[1]
4,763✔
3496
    if isexpr(callee, :tuple)
4,763✔
3497
        if length(callee.args) >= 1
4,712✔
3498
            # Evaluate the arguments to constrain the world, effects, and other info for codegen,
3499
            # but note there is an implied `if !=(C_NULL)` branch here that might read data
3500
            # in a different world (the exact cache behavior is unspecified), so we do not use
3501
            # these results to refine reachability of the subsequent foreigncall.
3502
            abstract_eval_value(interp, callee.args[1], sstate, sv)
9,424✔
3503
            if length(callee.args) >= 2
4,712✔
3504
                abstract_eval_value(interp, callee.args[2], sstate, sv)
1,276✔
3505
                #TODO: implement abstract_eval_nonlinearized_foreigncall_name correctly?
3506
                # lib_effects = abstract_call(interp, ArgInfo(e.args, Any[typeof(Libdl.dlopen), lib]), sstate, sv)::Future
3507
            end
3508
        end
3509
    else
3510
        abstract_eval_value(interp, callee, sstate, sv)
51✔
3511
    end
3512
    mi = frame_instance(sv)
4,763✔
3513
    t = sp_type_rewrap(e.args[2], mi, true)
4,763✔
3514
    let fptr = e.args[1]
4,763✔
3515
        if !isexpr(fptr, :tuple)
4,763✔
3516
            if !hasintersect(widenconst(abstract_eval_value(interp, fptr, sstate, sv)), Ptr)
102✔
3517
                return RTEffects(Bottom, Any, EFFECTS_THROWS)
×
3518
            end
3519
        end
3520
    end
3521
    for i = 3:length(e.args)
5,376✔
3522
        if abstract_eval_value(interp, e.args[i], sstate, sv) === Bottom
58,888✔
3523
            return RTEffects(Bottom, Any, EFFECTS_THROWS)
×
3524
        end
3525
    end
54,125✔
3526
    effects = foreigncall_effects(e) do @nospecialize x
4,763✔
3527
        abstract_eval_value(interp, x, sstate, sv)
3528
    end
3529
    cconv = e.args[5]
4,763✔
3530
    if isa(cconv, QuoteNode) && (v = cconv.value; isa(v, Tuple{Symbol, UInt16, Bool}))
4,763✔
3531
        override = decode_effects_override(v[2])
152✔
3532
        effects = override_effects(effects, override)
179✔
3533
    end
3534
    return RTEffects(t, Any, effects)
4,763✔
3535
end
3536

3537
function abstract_eval_phi(interp::AbstractInterpreter, phi::PhiNode, sstate::StatementState, sv::AbsIntState)
3✔
3538
    rt = Union{}
3✔
3539
    for i in 1:length(phi.values)
3✔
3540
        isassigned(phi.values, i) || continue
3✔
3541
        val = phi.values[i]
3✔
3542
        # N.B.: Phi arguments are restricted to not have effects, so we can drop
3543
        # them here safely.
3544
        thisval = abstract_eval_special_value(interp, val, sstate, sv).rt
3✔
3545
        rt = tmerge(typeinf_lattice(interp), rt, thisval)
6✔
3546
    end
3✔
3547
    return rt
3✔
3548
end
3549

3550
function stmt_taints_inbounds_consistency(sv::AbsIntState)
×
3551
    propagate_inbounds(sv) && return true
×
3552
    return has_curr_ssaflag(sv, IR_FLAG_INBOUNDS)
×
3553
end
3554

3555
function merge_override_effects!(interp::AbstractInterpreter, effects::Effects, sv::InferenceState)
3556
    # N.B.: This only applies to the effects of the statement itself.
3557
    # It is possible for arguments (GlobalRef/:static_parameter) to throw,
3558
    # but these will be recomputed during SSA construction later.
3559
    override = decode_statement_effects_override(sv)
4,031,592✔
3560
    effects = override_effects(effects, override)
8,063,184✔
3561
    set_curr_ssaflag!(sv, flags_for_effects(effects), IR_FLAGS_EFFECTS)
4,031,592✔
3562
    merge_effects!(interp, sv, effects)
7,592,849✔
3563
    return effects
4,031,592✔
3564
end
3565

3566
function override_effects(effects::Effects, override::EffectsOverride)
3567
    return Effects(effects;
8,063,363✔
3568
        consistent = override.consistent ? ALWAYS_TRUE : effects.consistent,
3569
        effect_free = override.effect_free ? ALWAYS_TRUE : effects.effect_free,
3570
        nothrow = override.nothrow ? true : effects.nothrow,
3571
        terminates = override.terminates_globally ? true : effects.terminates,
3572
        notaskstate = override.notaskstate ? true : effects.notaskstate,
3573
        inaccessiblememonly = override.inaccessiblememonly ? ALWAYS_TRUE : effects.inaccessiblememonly,
3574
        noub = override.noub ? ALWAYS_TRUE :
3575
            (override.noub_if_noinbounds && effects.noub !== ALWAYS_TRUE) ? NOUB_IF_NOINBOUNDS :
3576
            effects.noub,
3577
        nortcall = override.nortcall ? true : effects.nortcall)
3578
end
3579

3580
world_range(ir::IRCode) = ir.valid_worlds
3,421,724✔
3581
world_range(ci::CodeInfo) = WorldRange(ci.min_world, ci.max_world)
182,100✔
3582
world_range(ci::CodeInstance) = WorldRange(ci.min_world, ci.max_world)
420,540✔
3583
world_range(compact::IncrementalCompact) = world_range(compact.ir)
2,498,817✔
3584

3585
# n.b. this function is not part of abstract eval (where it would be unsound) but rather for the optimizer to observe the result of abstract eval
3586
function abstract_eval_globalref_type(g::GlobalRef, src::Union{CodeInfo, IRCode, IncrementalCompact})
3587
    worlds = world_range(src)
3,422,008✔
3588
    (valid_worlds, rte) = abstract_load_all_consistent_leaf_partitions(nothing, g, WorldWithRange(min_world(worlds), worlds))
3,422,008✔
3589
    if min_world(valid_worlds) > min_world(worlds) || max_world(valid_worlds) < max_world(worlds)
6,844,016✔
3590
        return Any
×
3591
    end
3592
    return rte.rt
3,422,008✔
3593
end
3594

3595
function lookup_binding_partition!(interp::AbstractInterpreter, g::Union{GlobalRef, Core.Binding}, sv::AbsIntState)
3596
    world = get_inference_world(interp)
18,170✔
3597
    partition = lookup_binding_partition(world, g)
18,170✔
3598
    update_valid_age!(sv, world, WorldRange(partition.min_world, partition.max_world))
18,170✔
3599
    partition
18,170✔
3600
end
3601

3602
function walk_binding_partition(imported_binding::Core.Binding, partition::Core.BindingPartition, world::UInt)
4,094,680✔
3603
    valid_worlds = WorldRange(partition.min_world, partition.max_world)
4,094,680✔
3604
    while is_some_binding_imported(binding_kind(partition))
9,018,733✔
3605
        imported_binding = partition_restriction(partition)::Core.Binding
827,255✔
3606
        partition = lookup_binding_partition(world, imported_binding)
827,255✔
3607
        valid_worlds = intersect(valid_worlds, WorldRange(partition.min_world, partition.max_world))
827,255✔
3608
    end
827,255✔
3609
    return Pair{WorldRange, Pair{Core.Binding, Core.BindingPartition}}(valid_worlds, imported_binding=>partition)
4,094,680✔
3610
end
3611

3612
function abstract_eval_binding_partition!(interp::AbstractInterpreter, g::GlobalRef, sv::AbsIntState)
3613
    b = convert(Core.Binding, g)
18,170✔
3614
    partition = lookup_binding_partition!(interp, b, sv)
18,170✔
3615
    world = get_inference_world(interp)
18,170✔
3616
    valid_worlds, (_, partition) = walk_binding_partition(b, partition, world)
18,170✔
3617
    update_valid_age!(sv, world, valid_worlds)
18,170✔
3618
    return partition
18,170✔
3619
end
3620

3621
function abstract_eval_partition_load(interp::Union{AbstractInterpreter,Nothing}, binding::Core.Binding, partition::Core.BindingPartition)
3622
    kind = binding_kind(partition)
5,967,752✔
3623
    isdepwarn = (partition.kind & PARTITION_FLAG_DEPWARN) != 0
5,967,752✔
3624
    local_getglobal_effects = Effects(generic_getglobal_effects, effect_free=isdepwarn ? ALWAYS_FALSE : ALWAYS_TRUE)
5,967,752✔
3625
    if is_some_guard(kind)
11,785,252✔
3626
        if interp !== nothing && InferenceParams(interp).assume_bindings_static
150,258✔
3627
            return RTEffects(Union{}, UndefVarError, EFFECTS_THROWS)
21✔
3628
        else
3629
            # We do not currently assume an invalidation for guard -> defined transitions
3630
            # return RTEffects(Union{}, UndefVarError, EFFECTS_THROWS)
3631
            return RTEffects(Any, UndefVarError, local_getglobal_effects)
150,237✔
3632
        end
3633
    end
3634

3635
    if is_defined_const_binding(kind)
8,286,116✔
3636
        if kind == PARTITION_KIND_BACKDATED_CONST
5,816,825✔
3637
            # Infer this as guard. We do not want a later const definition to retroactively improve
3638
            # inference results in an earlier world.
3639
            return RTEffects(Any, UndefVarError, local_getglobal_effects)
262,180✔
3640
        end
3641
        rt = Const(partition_restriction(partition))
5,554,645✔
3642
        return RTEffects(rt, Union{}, Effects(EFFECTS_TOTAL,
5,554,645✔
3643
            inaccessiblememonly=is_mutation_free_argtype(rt) ? ALWAYS_TRUE : ALWAYS_FALSE,
3644
            effect_free=isdepwarn ? ALWAYS_FALSE : ALWAYS_TRUE))
3645
    end
3646

3647
    if kind == PARTITION_KIND_DECLARED
669✔
3648
        # Could be replaced by a backdated const which has an effect, so we can't assume it won't.
3649
        # Besides, we would prefer not to merge the world range for this into the world range for
3650
        # _GLOBAL, because that would pessimize codegen.
3651
        effects = Effects(local_getglobal_effects, effect_free=ALWAYS_FALSE)
72✔
3652
        rt = Any
72✔
3653
    else
3654
        rt = partition_restriction(partition)
597✔
3655
        effects = local_getglobal_effects
597✔
3656
    end
3657
    if (interp !== nothing && InferenceParams(interp).assume_bindings_static &&
675✔
3658
        kind in (PARTITION_KIND_GLOBAL, PARTITION_KIND_DECLARED) &&
3659
        isdefined(binding, :value))
3660
        exct = Union{}
12✔
3661
        effects = Effects(generic_getglobal_effects; nothrow=true)
12✔
3662
    else
3663
        # We do not assume in general that assigned global bindings remain assigned.
3664
        # The existence of pkgimages allows them to revert in practice.
3665
        exct = UndefVarError
657✔
3666
    end
3667
    return RTEffects(rt, exct, effects)
669✔
3668
end
3669

3670
function scan_specified_partitions(query::F1, walk_binding_partition::F2,
5,302,918✔
3671
    interp::Union{AbstractInterpreter,Nothing}, g::GlobalRef, wwr::WorldWithRange) where {F1,F2}
3672
    local total_validity, rte, binding_partition
5,302,918✔
3673
    binding = convert(Core.Binding, g)
5,302,918✔
3674
    lookup_world = max_world(wwr.valid_worlds)
5,302,918✔
3675
    while true
5,968,037✔
3676
        # Partitions are ordered newest-to-oldest so start at the top
3677
        binding_partition = @isdefined(binding_partition) ?
11,270,955✔
3678
            lookup_binding_partition(lookup_world, binding, binding_partition) :
3679
            lookup_binding_partition(lookup_world, binding)
3680
        while lookup_world >= binding_partition.min_world && (!@isdefined(total_validity) || min_world(total_validity) > min_world(wwr.valid_worlds))
12,568,060✔
3681
            partition_validity, (leaf_binding, leaf_partition) = walk_binding_partition(binding, binding_partition, lookup_world)
5,968,037✔
3682
            @assert lookup_world in partition_validity
5,968,037✔
3683
            this_rte = query(interp, leaf_binding, leaf_partition)
9,572,684✔
3684
            if @isdefined(rte)
5,968,037✔
3685
                if this_rte === rte
665,119✔
3686
                    total_validity = union(total_validity, partition_validity)
252,214✔
3687
                    lookup_world = min_world(total_validity) - 1
252,214✔
3688
                    continue
252,214✔
3689
                end
3690
                if min_world(total_validity) <= wwr.this
412,905✔
3691
                    @goto out
412,905✔
3692
                end
3693
            end
3694
            total_validity = partition_validity
5,302,918✔
3695
            lookup_world = min_world(total_validity) - 1
5,302,918✔
3696
            rte = this_rte
5,302,918✔
3697
        end
5,555,132✔
3698
        min_world(total_validity) > min_world(wwr.valid_worlds) || break
5,555,132✔
3699
    end
665,119✔
3700
@label out
3701
    return Pair{WorldRange, typeof(rte)}(total_validity, rte)
5,302,918✔
3702
end
3703

3704
scan_leaf_partitions(query::F, ::Nothing, g::GlobalRef, wwr::WorldWithRange) where F =
3,422,008✔
3705
    scan_specified_partitions(query, walk_binding_partition, nothing, g, wwr)
3706
scan_leaf_partitions(query::F, interp::AbstractInterpreter, g::GlobalRef, wwr::WorldWithRange) where F =
1,880,640✔
3707
    scan_specified_partitions(query, walk_binding_partition, interp, g, wwr)
3708

3709
function scan_partitions(query::F, interp::AbstractInterpreter, g::GlobalRef, wwr::WorldWithRange) where F
3710
    walk_binding_partition = function (b::Core.Binding, partition::Core.BindingPartition, ::UInt)
102✔
3711
        Pair{WorldRange, Pair{Core.Binding, Core.BindingPartition}}(
120✔
3712
            WorldRange(partition.min_world, partition.max_world), b=>partition)
3713
    end
3714
    return scan_specified_partitions(query, walk_binding_partition, interp, g, wwr)
102✔
3715
end
3716

3717
abstract_load_all_consistent_leaf_partitions(interp::AbstractInterpreter, g::GlobalRef, wwr::WorldWithRange) =
57✔
3718
    scan_leaf_partitions(abstract_eval_partition_load, interp, g, wwr)
3719
abstract_load_all_consistent_leaf_partitions(::Nothing, g::GlobalRef, wwr::WorldWithRange) =
3,422,008✔
3720
    scan_leaf_partitions(abstract_eval_partition_load, nothing, g, wwr)
3721

3722
function abstract_eval_globalref(interp::AbstractInterpreter, g::GlobalRef, saw_latestworld::Bool, sv::AbsIntState)
3723
    if saw_latestworld
1,880,487✔
3724
        return RTEffects(Any, Any, generic_getglobal_effects)
×
3725
    end
3726
    # For inference purposes, we don't particularly care which global binding we end up loading, we only
3727
    # care about its type. However, we would still like to terminate the world range for the particular
3728
    # binding we end up reaching such that codegen can emit a simpler pointer load.
3729
    world = get_inference_world(interp)
1,880,487✔
3730
    (valid_worlds, ret) = scan_leaf_partitions(abstract_eval_partition_load, interp, g, binding_world_hints(world, sv))
1,880,487✔
3731
    update_valid_age!(sv, world, valid_worlds)
1,880,487✔
3732
    return ret
1,880,487✔
3733
end
3734

3735
function global_assignment_rt_exct(interp::AbstractInterpreter, sv::AbsIntState, saw_latestworld::Bool, g::GlobalRef, @nospecialize(newty))
3736
    if saw_latestworld
102✔
3737
        return Pair{Any,Any}(newty, Union{TypeError, ErrorException})
×
3738
    end
3739
    newtyโ€ฒ = RefValue{Any}(newty)
102✔
3740
    world = get_inference_world(interp)
102✔
3741
    (valid_worlds, ret) = scan_partitions(interp, g, binding_world_hints(world, sv)) do interp::AbstractInterpreter, ::Core.Binding, partition::Core.BindingPartition
102✔
3742
        global_assignment_binding_rt_exct(interp, partition, newtyโ€ฒ[])
120✔
3743
    end
3744
    update_valid_age!(sv, world, valid_worlds)
102✔
3745
    return ret
102✔
3746
end
3747

3748
function global_assignment_binding_rt_exct(interp::AbstractInterpreter, partition::Core.BindingPartition, @nospecialize(newty))
120✔
3749
    kind = binding_kind(partition)
120✔
3750
    if is_some_guard(kind)
222✔
3751
        return Pair{Any,Any}(newty, ErrorException)
24✔
3752
    elseif is_some_const_binding(kind) || is_some_imported(kind)
288✔
3753
        # N.B.: Backdating should not improve inference in an earlier world
3754
        return Pair{Any,Any}(kind == PARTITION_KIND_BACKDATED_CONST ? newty : Bottom, ErrorException)
×
3755
    end
3756
    ty = kind == PARTITION_KIND_DECLARED ? Any : partition_restriction(partition)
192✔
3757
    wnewty = widenconst(newty)
96✔
3758
    if !hasintersect(wnewty, ty)
96✔
3759
        return Pair{Any,Any}(Bottom, TypeError)
×
3760
    elseif !(wnewty <: ty)
96✔
3761
        retty = tmeet(typeinf_lattice(interp), newty, ty)
×
3762
        return Pair{Any,Any}(retty, TypeError)
×
3763
    end
3764
    return Pair{Any,Any}(newty, Bottom)
96✔
3765
end
3766

3767
abstract_eval_ssavalue(s::SSAValue, sv::InferenceState) = abstract_eval_ssavalue(s, sv.ssavaluetypes)
6,853,550✔
3768

3769
function abstract_eval_ssavalue(s::SSAValue, ssavaluetypes::Vector{Any})
3770
    (1 โ‰ค s.id โ‰ค length(ssavaluetypes)) || throw(InvalidIRError())
3,426,775✔
3771
    typ = ssavaluetypes[s.id]
3,426,775✔
3772
    if typ === NOT_FOUND
3,426,775✔
3773
        return Bottom
×
3774
    end
3775
    return typ
3,426,775✔
3776
end
3777

3778
struct AbstractEvalBasicStatementResult
3779
    rt
3780
    exct
3781
    effects::Union{Nothing,Effects}
3782
    changes::Union{Nothing,StateUpdate}
3783
    refinements # ::Union{Nothing,SlotRefinement,Vector{Any}}
3784
    currsaw_latestworld::Bool
3785
    function AbstractEvalBasicStatementResult(rt, exct, effects::Union{Nothing,Effects},
3786
        changes::Union{Nothing,StateUpdate}, refinements, currsaw_latestworld::Bool)
3787
        @nospecialize rt exct refinements
892,336✔
3788
        return new(rt, exct, effects, changes, refinements, currsaw_latestworld)
892,336✔
3789
    end
3790
end
3791

3792
@inline function abstract_eval_basic_statement(
3793
    interp::AbstractInterpreter, @nospecialize(stmt), sstate::StatementState, frame::InferenceState,
3794
    result::Union{Nothing,Future{RTEffects}}=nothing)
3795
    rt = nothing
12,430,470✔
3796
    exct = Bottom
5,133,966✔
3797
    changes = nothing
5,133,966✔
3798
    refinements = nothing
5,133,966✔
3799
    effects = nothing
5,133,966✔
3800
    currsaw_latestworld = sstate.saw_latestworld
5,133,966✔
3801
    if result !== nothing
5,133,966✔
3802
        @goto injectresult
990,401✔
3803
    end
3804
    if isa(stmt, NewvarNode)
4,143,565✔
3805
        changes = StateUpdate(stmt.slot, VarState(Bottom, true))
111,748✔
3806
    elseif isa(stmt, PhiNode)
4,031,817✔
3807
        add_curr_ssaflag!(frame, IR_FLAGS_REMOVABLE)
×
3808
        # Implement convergence for PhiNodes. In particular, PhiNodes need to tmerge over
3809
        # the incoming values from all iterations, but `abstract_eval_phi` will only tmerge
3810
        # over the first and last iterations. By tmerging in the current old_rt, we ensure that
3811
        # we will not lose an intermediate value.
3812
        rt = abstract_eval_phi(interp, stmt, sstate, frame)
×
3813
        old_rt = frame.ssavaluetypes[frame.currpc]
×
3814
        rt = old_rt === NOT_FOUND ? rt : tmerge(typeinf_lattice(interp), old_rt, rt)
×
3815
    else
3816
        lhs = nothing
4,031,817✔
3817
        if isexpr(stmt, :(=))
4,031,817✔
3818
            lhs = stmt.args[1]
414,681✔
3819
            stmt = stmt.args[2]
414,681✔
3820
        end
3821
        if !isa(stmt, Expr)
4,031,817✔
3822
            (; rt, exct, effects, refinements) = abstract_eval_special_value(interp, stmt, sstate, frame)
2,241,894✔
3823
        else
3824
            hd = stmt.head
1,789,923✔
3825
            if hd === :method
1,789,923✔
3826
                fname = stmt.args[1]
×
3827
                if isa(fname, SlotNumber)
×
3828
                    changes = StateUpdate(fname, VarState(Any, false))
×
3829
                end
3830
            elseif (hd === :code_coverage_effect ||
5,359,817✔
3831
                    # :boundscheck can be narrowed to Bool
3832
                    (hd !== :boundscheck && is_meta_expr(stmt)))
3833
                rt = Nothing
210✔
3834
            elseif hd === :latestworld
1,789,713✔
3835
                currsaw_latestworld = true
15✔
3836
                rt = Nothing
15✔
3837
            else
3838
                result = abstract_eval_statement_expr(interp, stmt, sstate, frame)::Future{RTEffects}
1,789,698✔
3839
                if !isready(result) || !isempty(frame.tasks)
3,579,396✔
3840
                    return result
990,401✔
3841

3842
                    @label injectresult
3843
                    # reload local variables
3844
                    lhs = nothing
990,401✔
3845
                    if isexpr(stmt, :(=))
990,401✔
3846
                        lhs = stmt.args[1]
170,319✔
3847
                        stmt = stmt.args[2]
170,319✔
3848
                    end
3849
                end
3850
                result = result[]
2,780,070✔
3851
                (; rt, exct, effects, refinements) = result
1,789,698✔
3852
                if effects.noub === NOUB_IF_NOINBOUNDS
1,789,698✔
3853
                    if has_curr_ssaflag(frame, IR_FLAG_INBOUNDS)
29,463✔
3854
                        effects = Effects(effects; noub=ALWAYS_FALSE)
14,861✔
3855
                    elseif !propagate_inbounds(frame)
14,602✔
3856
                        # The callee read our inbounds flag, but unless we propagate inbounds,
3857
                        # we ourselves don't read our parent's inbounds.
3858
                        effects = Effects(effects; noub=ALWAYS_TRUE)
12,099✔
3859
                    end
3860
                end
3861
                @assert !isa(rt, TypeVar) "unhandled TypeVar"
1,789,698✔
3862
                rt = maybe_singleton_const(rt)
2,604,200✔
3863
                if !isempty(frame.pclimitations)
1,789,698✔
3864
                    if rt isa Const || rt === Union{}
502✔
3865
                        empty!(frame.pclimitations)
20✔
3866
                    else
3867
                        rt = LimitedAccuracy(rt, frame.pclimitations)
231✔
3868
                        frame.pclimitations = IdSet{InferenceState}()
231✔
3869
                    end
3870
                end
3871
            end
3872
        end
3873
        if lhs !== nothing && rt !== Bottom
4,031,817✔
3874
            changes = StateUpdate(lhs::SlotNumber, VarState(rt, false))
413,127✔
3875
        end
3876
    end
3877
    return AbstractEvalBasicStatementResult(rt, exct, effects, changes, refinements, currsaw_latestworld)
7,465,652✔
3878
end
3879

3880
struct BestguessInfo{Interp<:AbstractInterpreter}
3881
    interp::Interp
3882
    bestguess
3883
    nargs::Int
3884
    slottypes::Vector{Any}
3885
    changes::VarTable
3886
    function BestguessInfo(interp::Interp, @nospecialize(bestguess), nargs::Int,
3887
        slottypes::Vector{Any}, changes::VarTable) where Interp<:AbstractInterpreter
3888
        new{Interp}(interp, bestguess, nargs, slottypes, changes)
370,460✔
3889
    end
3890
end
3891

3892
@nospecializeinfer function widenreturn(@nospecialize(rt), info::BestguessInfo)
3893
    return widenreturn(typeinf_lattice(info.interp), rt, info)
370,772✔
3894
end
3895

3896
@nospecializeinfer function widenreturn(๐•ƒแตข::AbstractLattice, @nospecialize(rt), info::BestguessInfo)
3897
    return widenreturn(widenlattice(๐•ƒแตข), rt, info)
370,772✔
3898
end
3899
@nospecializeinfer function widenreturn_noslotwrapper(๐•ƒแตข::AbstractLattice, @nospecialize(rt), info::BestguessInfo)
111,717✔
3900
    return widenreturn_noslotwrapper(widenlattice(๐•ƒแตข), rt, info)
111,717✔
3901
end
3902

3903
@nospecializeinfer function widenreturn(๐•ƒแตข::MustAliasesLattice, @nospecialize(rt), info::BestguessInfo)
3904
    if isa(rt, MustAlias)
513✔
3905
        if 1 โ‰ค rt.slot โ‰ค info.nargs
216✔
3906
            rt = InterMustAlias(rt)
201✔
3907
        else
3908
            rt = widenmustalias(rt)
15✔
3909
        end
3910
    end
3911
    isa(rt, InterMustAlias) && return rt
513✔
3912
    return widenreturn(widenlattice(๐•ƒแตข), rt, info)
312✔
3913
end
3914

3915
@nospecializeinfer function widenreturn(๐•ƒแตข::ConditionalsLattice, @nospecialize(rt), info::BestguessInfo)
370,253✔
3916
    โŠ‘แตข = โŠ‘(๐•ƒแตข)
370,253✔
3917
    if !(โŠ‘(ipo_lattice(info.interp), info.bestguess, Bool)) || info.bestguess === Bool
713,438✔
3918
        # give up inter-procedural constraint back-propagation
3919
        # when tmerge would widen the result anyways (as an optimization)
3920
        rt = widenconditional(rt)
28,538✔
3921
    else
3922
        if isa(rt, Conditional)
341,757✔
3923
            id = rt.slot
3,662✔
3924
            if 1 โ‰ค id โ‰ค info.nargs
3,662✔
3925
                old_id_type = widenconditional(info.slottypes[id]) # same as `(states[1]::VarTable)[id].typ`
3,670✔
3926
                if (!(rt.thentype โŠ‘แตข old_id_type) || old_id_type โŠ‘แตข rt.thentype) &&
4,776✔
3927
                   (!(rt.elsetype โŠ‘แตข old_id_type) || old_id_type โŠ‘แตข rt.elsetype)
3928
                   # discard this `Conditional` since it imposes
3929
                   # no new constraint on the argument type
3930
                   # (the caller will recreate it if needed)
3931
                   rt = widenconditional(rt)
828✔
3932
               end
3933
            else
3934
                # discard this `Conditional` imposed on non-call arguments,
3935
                # since it's not interesting in inter-procedural context;
3936
                # we may give constraints on other call argument
3937
                rt = widenconditional(rt)
288✔
3938
            end
3939
        end
3940
        if isa(rt, Conditional)
341,757✔
3941
            rt = InterConditional(rt.slot, rt.thentype, rt.elsetype)
2,960✔
3942
        elseif is_lattice_bool(๐•ƒแตข, rt)
677,594✔
3943
            rt = bool_rt_to_conditional(rt, info)
32,338✔
3944
        end
3945
    end
3946
    if isa(rt, Conditional)
370,253✔
3947
        rt = InterConditional(rt)
×
3948
    end
3949
    isa(rt, InterConditional) && return rt
370,253✔
3950
    return widenreturn(widenlattice(๐•ƒแตข), rt, info)
367,170✔
3951
end
3952
@nospecializeinfer function bool_rt_to_conditional(@nospecialize(rt), info::BestguessInfo)
26,250✔
3953
    bestguess = info.bestguess
32,338✔
3954
    if isa(bestguess, InterConditional)
32,338✔
3955
        # if the bestguess so far is already `Conditional`, try to convert
3956
        # this `rt` into `Conditional` on the slot to avoid overapproximation
3957
        # due to conflict of different slots
3958
        rt = bool_rt_to_conditional(rt, bestguess.slot, info)
234✔
3959
    else
3960
        # pick up the first "interesting" slot, convert `rt` to its `Conditional`
3961
        # TODO: ideally we want `Conditional` and `InterConditional` to convey
3962
        # constraints on multiple slots
3963
        for slot_id = 1:Int(info.nargs)
38,282✔
3964
            rt = bool_rt_to_conditional(rt, slot_id, info)
170,289✔
3965
            rt isa InterConditional && break
94,150✔
3966
        end
94,051✔
3967
    end
3968
    return rt
32,338✔
3969
end
3970
@nospecializeinfer function bool_rt_to_conditional(@nospecialize(rt), slot_id::Int, info::BestguessInfo)
18,011✔
3971
    โŠ‘แตข = โŠ‘(typeinf_lattice(info.interp))
94,267✔
3972
    old = info.slottypes[slot_id]
94,267✔
3973
    new = widenslotwrapper(info.changes[slot_id].typ) # avoid nested conditional
95,186✔
3974
    if isvarargtype(old) || isvarargtype(new)
188,534✔
3975
        return rt
×
3976
    end
3977
    if new โŠ‘แตข old && !(old โŠ‘แตข new)
94,267✔
3978
        if isa(rt, Const)
123✔
3979
            val = rt.val
69✔
3980
            if val === true
69✔
3981
                return InterConditional(slot_id, new, Bottom)
24✔
3982
            elseif val === false
45✔
3983
                return InterConditional(slot_id, Bottom, new)
45✔
3984
            end
3985
        elseif rt === Bool
54✔
3986
            return InterConditional(slot_id, new, new)
54✔
3987
        end
3988
    end
3989
    return rt
94,144✔
3990
end
3991

3992
@nospecializeinfer function widenreturn(๐•ƒแตข::PartialsLattice, @nospecialize(rt), info::BestguessInfo)
3993
    return widenreturn_partials(๐•ƒแตข, rt, info)
367,176✔
3994
end
3995
@nospecializeinfer function widenreturn_noslotwrapper(๐•ƒแตข::PartialsLattice, @nospecialize(rt), info::BestguessInfo)
55,848✔
3996
    return widenreturn_partials(๐•ƒแตข, rt, info)
55,848✔
3997
end
3998
@nospecializeinfer function widenreturn_partials(๐•ƒแตข::PartialsLattice, @nospecialize(rt), info::BestguessInfo)
423,024✔
3999
    if isa(rt, PartialStruct)
423,024✔
4000
        fields = copy(rt.fields)
50,638✔
4001
        anyrefine = n_initialized(rt) > datatype_min_ninitialized(rt.typ)
50,638✔
4002
        ๐•ƒ = typeinf_lattice(info.interp)
25,319✔
4003
        โŠ = strictpartialorder(๐•ƒ)
25,319✔
4004
        for i in 1:length(fields)
32,052✔
4005
            a = fields[i]
55,848✔
4006
            a = isvarargtype(a) ? a : widenreturn_noslotwrapper(๐•ƒ, a, info)
111,696✔
4007
            if !anyrefine
55,848✔
4008
                # TODO: consider adding && const_prop_profitable(a) here?
4009
                anyrefine = has_extended_info(a) || a โŠ fieldtype(rt.typ, i)
56,684✔
4010
            end
4011
            fields[i] = a
55,848✔
4012
        end
86,377✔
4013
        anyrefine && return PartialStruct(๐•ƒแตข, rt.typ, _getundefs(rt), fields)
25,319✔
4014
    end
4015
    if isa(rt, PartialOpaque)
398,383✔
4016
        return rt # XXX: this case was missed in #39512
×
4017
    end
4018
    return widenreturn(widenlattice(๐•ƒแตข), rt, info)
398,383✔
4019
end
4020

4021
@nospecializeinfer function widenreturn(::ConstsLattice, @nospecialize(rt), ::BestguessInfo)
4022
    return widenreturn_consts(rt)
398,383✔
4023
end
4024
@nospecializeinfer function widenreturn_noslotwrapper(::ConstsLattice, @nospecialize(rt), ::BestguessInfo)
×
4025
    return widenreturn_consts(rt)
×
4026
end
4027
@nospecializeinfer function widenreturn_consts(@nospecialize(rt))
126,341✔
4028
    isa(rt, Const) && return rt
126,341✔
4029
    return widenconst(rt)
55,462✔
4030
end
4031

4032
@nospecializeinfer function widenreturn(::JLTypeLattice, @nospecialize(rt), ::BestguessInfo)
×
4033
    return widenconst(rt)
×
4034
end
4035
@nospecializeinfer function widenreturn_noslotwrapper(::JLTypeLattice, @nospecialize(rt), ::BestguessInfo)
×
4036
    return widenconst(rt)
×
4037
end
4038

4039
function handle_control_backedge!(interp::AbstractInterpreter, frame::InferenceState, from::Int, to::Int)
4040
    if from > to
319,307✔
4041
        if is_effect_overridden(frame, :terminates_locally)
43,287✔
4042
            # this backedge is known to terminate
4043
        else
4044
            merge_effects!(interp, frame, Effects(EFFECTS_TOTAL; terminates=false))
20,206✔
4045
        end
4046
    end
4047
    return nothing
319,307✔
4048
end
4049

4050
function update_bbstate!(๐•ƒแตข::AbstractLattice, frame::InferenceState, bb::Int, vartable::VarTable, saw_latestworld::Bool)
4051
    frame.bb_saw_latestworld[bb] |= saw_latestworld
649,263✔
4052
    bbtable = frame.bb_vartables[bb]
649,263✔
4053
    if bbtable === nothing
649,263✔
4054
        # if a basic block hasn't been analyzed yet,
4055
        # we can update its state a bit more aggressively
4056
        frame.bb_vartables[bb] = copy(vartable)
479,058✔
4057
        return true
479,058✔
4058
    else
4059
        return stupdate!(๐•ƒแตข, bbtable, vartable)
170,205✔
4060
    end
4061
end
4062

4063
function init_vartable!(vartable::VarTable, frame::InferenceState)
4064
    nargtypes = length(frame.result.argtypes)
×
4065
    for i = 1:length(vartable)
×
4066
        vartable[i] = VarState(Bottom, i > nargtypes)
×
4067
    end
×
4068
    return vartable
×
4069
end
4070

4071
function update_bestguess!(interp::AbstractInterpreter, frame::InferenceState,
370,460✔
4072
                           currstate::VarTable, @nospecialize(rt))
4073
    bestguess = frame.bestguess
370,460✔
4074
    nargs = narguments(frame, #=include_va=#false)
370,460✔
4075
    slottypes = frame.slottypes
370,460✔
4076
    rt = widenreturn(rt, BestguessInfo(interp, bestguess, nargs, slottypes, currstate))
370,772✔
4077
    # narrow representation of bestguess slightly to prepare for tmerge with rt
4078
    if rt isa InterConditional && bestguess isa Const && bestguess.val isa Bool
370,460✔
4079
        slot_id = rt.slot
×
4080
        old_id_type = widenconditional(slottypes[slot_id])
×
4081
        if bestguess.val === true && rt.elsetype !== Bottom
×
4082
            bestguess = InterConditional(slot_id, old_id_type, Bottom)
×
4083
        elseif bestguess.val === false && rt.thentype !== Bottom
×
4084
            bestguess = InterConditional(slot_id, Bottom, old_id_type)
×
4085
        end
4086
    # or narrow representation of rt slightly to prepare for tmerge with bestguess
4087
    elseif bestguess isa InterConditional && rt isa Const && rt.val isa Bool
370,460✔
4088
        slot_id = bestguess.slot
87✔
4089
        old_id_type = widenconditional(slottypes[slot_id])
87✔
4090
        if rt.val === true && bestguess.elsetype !== Bottom
87✔
4091
            rt = InterConditional(slot_id, old_id_type, Bottom)
3✔
4092
        elseif rt.val === false && bestguess.thentype !== Bottom
84✔
4093
            rt = InterConditional(slot_id, Bottom, old_id_type)
69✔
4094
        end
4095
    end
4096
    # copy limitations to return value
4097
    if !isempty(frame.pclimitations)
370,460✔
4098
        union!(frame.limitations, frame.pclimitations)
89✔
4099
        empty!(frame.pclimitations)
89✔
4100
    end
4101
    if !isempty(frame.limitations)
370,460✔
4102
        rt = LimitedAccuracy(rt, copy(frame.limitations))
125✔
4103
    end
4104
    ๐•ƒโ‚š = ipo_lattice(interp)
370,460✔
4105
    if !โŠ‘(๐•ƒโ‚š, rt, bestguess)
370,460✔
4106
        # TODO: if bestguess isa InterConditional && !interesting(bestguess); bestguess = widenconditional(bestguess); end
4107
        frame.bestguess = tmerge(๐•ƒโ‚š, bestguess, rt) # new (wider) return type for frame
350,409✔
4108
        return true
349,974✔
4109
    else
4110
        return false
20,486✔
4111
    end
4112
end
4113

4114
function update_exc_bestguess!(interp::AbstractInterpreter, @nospecialize(exct), frame::InferenceState)
324,482✔
4115
    ๐•ƒโ‚š = ipo_lattice(interp)
324,482✔
4116
    handler = gethandler(frame)
374,777✔
4117
    if handler === nothing
324,482✔
4118
        if !โŠ‘(๐•ƒโ‚š, exct, frame.exc_bestguess)
308,615✔
4119
            frame.exc_bestguess = tmerge(๐•ƒโ‚š, frame.exc_bestguess, exct)
121,286✔
4120
            update_cycle_worklists!(frame) do caller::InferenceState, caller_pc::Int
121,121✔
4121
                caller_handler = gethandler(caller, caller_pc)
16✔
4122
                caller_exct = caller_handler === nothing ?
16✔
4123
                    caller.exc_bestguess : caller_handler.exct
4124
                return caller_exct !== Any
16✔
4125
            end
4126
        end
4127
    else
4128
        if !โŠ‘(๐•ƒโ‚š, exct, handler.exct)
15,867✔
4129
            handler.exct = tmerge(๐•ƒโ‚š, handler.exct, exct)
5,276✔
4130
            enter = frame.src.code[handler.enter_idx]::EnterNode
5,276✔
4131
            exceptbb = block_for_inst(frame.cfg, enter.catch_dest)
5,276✔
4132
            push!(frame.ip, exceptbb)
5,276✔
4133
        end
4134
    end
4135
end
4136

4137
function propagate_to_error_handler!(currstate::VarTable, currsaw_latestworld::Bool, frame::InferenceState, ๐•ƒแตข::AbstractLattice)
39,558✔
4138
    # If this statement potentially threw, propagate the currstate to the
4139
    # exception handler, BEFORE applying any state changes.
4140
    curr_hand = gethandler(frame)
50,356✔
4141
    if curr_hand !== nothing
39,558✔
4142
        enter = frame.src.code[curr_hand.enter_idx]::EnterNode
3,040✔
4143
        exceptbb = block_for_inst(frame.cfg, enter.catch_dest)
3,040✔
4144
        if update_bbstate!(๐•ƒแตข, frame, exceptbb, currstate, currsaw_latestworld)
3,040✔
4145
            push!(frame.ip, exceptbb)
2,864✔
4146
        end
4147
    end
4148
end
4149

4150
function update_cycle_worklists!(callback, frame::InferenceState)
135,523✔
4151
    for (caller, caller_pc) in frame.cycle_backedges
135,523✔
4152
        if callback(caller, caller_pc)
32✔
4153
            push!(caller.ip, block_for_inst(caller.cfg, caller_pc))
16✔
4154
        end
4155
    end
32✔
4156
end
4157

4158
# make as much progress on `frame` as possible (without handling cycles)
4159
struct CurrentState
4160
    result::Future{RTEffects}
4161
    currstate::VarTable
4162
    currsaw_latestworld::Bool
4163
    bbstart::Int
4164
    bbend::Int
4165
    CurrentState(result::Future{RTEffects}, currstate::VarTable, currsaw_latestworld::Bool, bbstart::Int, bbend::Int) =
990,401✔
4166
        new(result, currstate, currsaw_latestworld, bbstart, bbend)
4167
    CurrentState() = new()
689,515✔
4168
end
4169

4170
function typeinf_local(interp::AbstractInterpreter, frame::InferenceState, nextresult::CurrentState)
1,335,236✔
4171
    @assert !is_inferred(frame)
1,335,236✔
4172
    W = frame.ip
1,335,236✔
4173
    ssavaluetypes = frame.ssavaluetypes
1,335,236✔
4174
    bbs = frame.cfg.blocks
1,335,236✔
4175
    nbbs = length(bbs)
1,335,236✔
4176
    ๐•ƒแตข = typeinf_lattice(interp)
1,335,236✔
4177
    states = frame.bb_vartables
1,335,236✔
4178
    saw_latestworld = frame.bb_saw_latestworld
1,335,236✔
4179
    currbb = frame.currbb
1,335,236✔
4180
    currpc = frame.currpc
1,335,236✔
4181

4182
    if isdefined(nextresult, :result)
1,335,236✔
4183
        # for reasons that are fairly unclear, some state is arbitrarily on the stack instead in the InferenceState as normal
4184
        bbstart = nextresult.bbstart
990,401✔
4185
        bbend = nextresult.bbend
990,401✔
4186
        currstate = nextresult.currstate
990,401✔
4187
        currsaw_latestworld = nextresult.currsaw_latestworld
990,401✔
4188
        stmt = frame.src.code[currpc]
990,401✔
4189
        result = abstract_eval_basic_statement(interp, stmt, StatementState(currstate, currsaw_latestworld), frame, nextresult.result)
1,159,549✔
4190
        @goto injected_result
990,401✔
4191
    end
4192

4193
    if currbb != 1
344,835✔
4194
        currbb = frame.currbb = _bits_findnext(W.bits, 1)::Int # next basic block
472✔
4195
    end
4196
    currstate = copy(states[currbb]::VarTable)
688,969✔
4197
    currsaw_latestworld = saw_latestworld[currbb]
344,835✔
4198
    while currbb <= nbbs
895,551✔
4199
        delete!(W, currbb)
1,791,102✔
4200
        bbstart = first(bbs[currbb].stmts)
895,551✔
4201
        bbend = last(bbs[currbb].stmts)
895,551✔
4202

4203
        currpc = bbstart - 1
895,551✔
4204
        while currpc < bbend
5,016,644✔
4205
            currpc += 1
4,958,967✔
4206
            frame.currpc = currpc
4,958,967✔
4207
            stmt = frame.src.code[currpc]
4,958,967✔
4208
            # If we're at the end of the basic block ...
4209
            if currpc == bbend
4,958,967✔
4210
                # Handle control flow
4211
                if isa(stmt, GotoNode)
881,160✔
4212
                    succs = bbs[currbb].succs
148,651✔
4213
                    @assert length(succs) == 1
148,651✔
4214
                    nextbb = succs[1]
148,651✔
4215
                    ssavaluetypes[currpc] = Any
148,651✔
4216
                    handle_control_backedge!(interp, frame, currpc, stmt.label)
168,857✔
4217
                    add_curr_ssaflag!(frame, IR_FLAG_NOTHROW)
148,651✔
4218
                    @goto branch
148,651✔
4219
                elseif isa(stmt, GotoIfNot)
732,509✔
4220
                    condx = stmt.cond
284,444✔
4221
                    condslot = ssa_def_slot(condx, frame)
284,444✔
4222
                    condt = abstract_eval_value(interp, condx, StatementState(currstate, currsaw_latestworld), frame)
568,888✔
4223
                    if condt === Bottom
284,444✔
4224
                        ssavaluetypes[currpc] = Bottom
×
4225
                        empty!(frame.pclimitations)
×
4226
                        @goto find_next_bb
×
4227
                    end
4228
                    orig_condt = condt
284,444✔
4229
                    if !(isa(condt, Const) || isa(condt, Conditional)) && isa(condslot, SlotNumber)
505,263✔
4230
                        # if this non-`Conditional` object is a slot, we form and propagate
4231
                        # the conditional constraint on it
4232
                        condt = Conditional(condslot, Const(true), Const(false))
8,094✔
4233
                    end
4234
                    condval = maybe_extract_const_bool(condt)
505,263✔
4235
                    nothrow = (condval !== nothing) || โŠ‘(๐•ƒแตข, orig_condt, Bool)
428,248✔
4236
                    if nothrow
284,444✔
4237
                        add_curr_ssaflag!(frame, IR_FLAG_NOTHROW)
282,257✔
4238
                    else
4239
                        update_exc_bestguess!(interp, TypeError, frame)
2,187✔
4240
                        propagate_to_error_handler!(currstate, currsaw_latestworld, frame, ๐•ƒแตข)
2,187✔
4241
                        merge_effects!(interp, frame, EFFECTS_THROWS)
2,187✔
4242
                    end
4243

4244
                    if !isempty(frame.pclimitations)
284,444✔
4245
                        # we can't model the possible effect of control
4246
                        # dependencies on the return
4247
                        # directly to all the return values (unless we error first)
4248
                        condval isa Bool || union!(frame.limitations, frame.pclimitations)
24✔
4249
                        empty!(frame.pclimitations)
12✔
4250
                    end
4251
                    ssavaluetypes[currpc] = Any
284,444✔
4252
                    if condval === true
284,444✔
4253
                        @goto fallthrough
100,166✔
4254
                    else
4255
                        if !nothrow && !hasintersect(widenconst(orig_condt), Bool)
184,278✔
4256
                            ssavaluetypes[currpc] = Bottom
8✔
4257
                            @goto find_next_bb
8✔
4258
                        end
4259

4260
                        succs = bbs[currbb].succs
184,270✔
4261
                        if length(succs) == 1
184,270✔
4262
                            @assert condval === false || (stmt.dest === currpc + 1)
×
4263
                            nextbb = succs[1]
×
4264
                            @goto branch
×
4265
                        end
4266
                        @assert length(succs) == 2
184,270✔
4267
                        truebb = currbb + 1
184,270✔
4268
                        falsebb = succs[1] == truebb ? succs[2] : succs[1]
184,270✔
4269
                        if condval === false
184,270✔
4270
                            nextbb = falsebb
40,474✔
4271
                            handle_control_backedge!(interp, frame, currpc, stmt.dest)
40,474✔
4272
                            @goto branch
40,474✔
4273
                        end
4274

4275
                        # We continue with the true branch, but process the false
4276
                        # branch here.
4277
                        if isa(condt, Conditional)
143,796✔
4278
                            else_change = conditional_change(๐•ƒแตข, currstate, condt, #=then_or_else=#false)
114,132✔
4279
                            if else_change !== nothing
63,343✔
4280
                                elsestate = copy(currstate)
103,744✔
4281
                                stoverwrite1!(elsestate, else_change)
51,872✔
4282
                            elseif condslot isa SlotNumber
11,471✔
4283
                                elsestate = copy(currstate)
10,855✔
4284
                            else
4285
                                elsestate = currstate
616✔
4286
                            end
4287
                            if condslot isa SlotNumber # refine the type of this conditional object itself for this else branch
63,343✔
4288
                                stoverwrite1!(elsestate, condition_object_change(currstate, condt, condslot, #=then_or_else=#false))
19,178✔
4289
                            end
4290
                            else_changed = update_bbstate!(๐•ƒแตข, frame, falsebb, elsestate, currsaw_latestworld)
63,343✔
4291
                            then_change = conditional_change(๐•ƒแตข, currstate, condt, #=then_or_else=#true)
114,192✔
4292
                            thenstate = currstate
63,343✔
4293
                            if then_change !== nothing
63,343✔
4294
                                stoverwrite1!(thenstate, then_change)
51,932✔
4295
                            end
4296
                            if condslot isa SlotNumber # refine the type of this conditional object itself for this then branch
63,343✔
4297
                                stoverwrite1!(thenstate, condition_object_change(currstate, condt, condslot, #=then_or_else=#true))
19,178✔
4298
                            end
4299
                        else
4300
                            else_changed = update_bbstate!(๐•ƒแตข, frame, falsebb, currstate, currsaw_latestworld)
80,453✔
4301
                        end
4302
                        if else_changed
143,796✔
4303
                            handle_control_backedge!(interp, frame, currpc, stmt.dest)
130,182✔
4304
                            push!(W, falsebb)
130,182✔
4305
                        end
4306
                        @goto fallthrough
143,796✔
4307
                    end
4308
                elseif isa(stmt, ReturnNode)
448,065✔
4309
                    rt = abstract_eval_value(interp, stmt.val, StatementState(currstate, currsaw_latestworld), frame)
741,288✔
4310
                    if update_bestguess!(interp, frame, currstate, rt)
370,644✔
4311
                        update_cycle_worklists!(frame) do caller::InferenceState, caller_pc::Int
350,155✔
4312
                            # no reason to revisit if that call-site doesn't affect the final result
4313
                            return caller.ssavaluetypes[caller_pc] !== Any
16✔
4314
                        end
4315
                    end
4316
                    ssavaluetypes[currpc] = Any
370,644✔
4317
                    @goto find_next_bb
370,644✔
4318
                elseif isa(stmt, EnterNode)
77,421✔
4319
                    ssavaluetypes[currpc] = Any
5,605✔
4320
                    add_curr_ssaflag!(frame, IR_FLAG_NOTHROW)
5,605✔
4321
                    if isdefined(stmt, :scope)
5,605✔
4322
                        scopet = abstract_eval_value(interp, stmt.scope, StatementState(currstate, currsaw_latestworld), frame)
5,208✔
4323
                        handler = gethandler(frame, currpc + 1)::TryCatchFrame
5,208✔
4324
                        @assert handler.scopet !== nothing
2,604✔
4325
                        if !โŠ‘(๐•ƒแตข, scopet, handler.scopet)
2,604✔
4326
                            handler.scopet = tmerge(๐•ƒแตข, scopet, handler.scopet)
5,208✔
4327
                            if isdefined(handler, :scope_uses)
2,604✔
4328
                                for bb in handler.scope_uses
×
4329
                                    push!(W, bb)
×
4330
                                end
×
4331
                            end
4332
                        end
4333
                    end
4334
                    @goto fallthrough
5,605✔
4335
                elseif isexpr(stmt, :leave)
71,816✔
4336
                    ssavaluetypes[currpc] = Any
6,058✔
4337
                    @goto fallthrough
6,058✔
4338
                end
4339
                # Fall through terminator - treat as regular stmt
4340
            end
4341
            # Process non control-flow statements
4342
            @assert isempty(frame.tasks)
4,143,565✔
4343
            sstate = StatementState(currstate, currsaw_latestworld)
4,143,565✔
4344
            result = abstract_eval_basic_statement(interp, stmt, sstate, frame)
7,296,504✔
4345
            if result isa Future{RTEffects}
4,143,565✔
4346
                return CurrentState(result, currstate, currsaw_latestworld, bbstart, bbend)
990,401✔
4347
            else
4348
                @label injected_result
4349
                (; rt, exct, effects, changes, refinements, currsaw_latestworld) = result
4,143,565✔
4350
            end
4351
            effects === nothing || merge_override_effects!(interp, effects, frame)
8,175,157✔
4352
            if !has_curr_ssaflag(frame, IR_FLAG_NOTHROW)
4,143,565✔
4353
                if exct !== Union{}
434,524✔
4354
                    update_exc_bestguess!(interp, exct, frame)
322,551✔
4355
                    # TODO: assert that these conditions match. For now, we assume the `nothrow` flag
4356
                    # to be correct, but allow the exct to be an over-approximation.
4357
                end
4358
                propagate_to_error_handler!(currstate, currsaw_latestworld, frame, ๐•ƒแตข)
434,524✔
4359
            end
4360
            if rt === Bottom
4,143,565✔
4361
                ssavaluetypes[currpc] = Bottom
22,472✔
4362
                # Special case: Bottom-typed PhiNodes do not error (but must also be unused)
4363
                if isa(stmt, PhiNode)
22,472✔
4364
                    continue
×
4365
                end
4366
                @goto find_next_bb
22,472✔
4367
            end
4368
            if changes !== nothing
4,121,093✔
4369
                stoverwrite1!(currstate, changes)
524,875✔
4370
            end
4371
            if refinements isa SlotRefinement
4,121,093✔
4372
                apply_refinement!(๐•ƒแตข, refinements.slot, refinements.typ, currstate, changes)
4,688✔
4373
            elseif refinements isa Vector{Any}
4,117,316✔
4374
                for i = 1:length(refinements)
371✔
4375
                    newtyp = refinements[i]
1,669✔
4376
                    newtyp === nothing && continue
1,669✔
4377
                    apply_refinement!(๐•ƒแตข, SlotNumber(i), newtyp, currstate, changes)
371✔
4378
                end
1,669✔
4379
            end
4380
            if rt === nothing
4,121,093✔
4381
                ssavaluetypes[currpc] = Any
111,748✔
4382
                continue
111,748✔
4383
            end
4384
            record_ssa_assign!(๐•ƒแตข, currpc, rt, frame)
4,009,345✔
4385
        end # for currpc in bbstart:bbend
4,121,093✔
4386

4387
        # Case 1: Fallthrough termination
4388
        begin @label fallthrough
4389
            nextbb = currbb + 1
313,302✔
4390
        end
4391

4392
        # Case 2: Directly branch to a different BB
4393
        begin @label branch
4394
            if update_bbstate!(๐•ƒแตข, frame, nextbb, currstate, currsaw_latestworld)
502,427✔
4395
                push!(W, nextbb)
457,632✔
4396
            end
4397
        end
4398

4399
        # Case 3: Control flow ended along the current path (converged, return or throw)
4400
        begin @label find_next_bb
4401
            currbb = frame.currbb = _bits_findnext(W.bits, 1)::Int # next basic block
1,791,102✔
4402
            currbb == -1 && break # the working set is empty
895,551✔
4403
            currbb > nbbs && break
550,716✔
4404

4405
            nexttable = states[currbb]
550,716✔
4406
            if nexttable === nothing
550,716✔
4407
                init_vartable!(currstate, frame)
×
4408
            else
4409
                stoverwrite!(currstate, nexttable)
550,716✔
4410
            end
4411
        end
4412
    end # while currbb <= nbbs
550,716✔
4413

4414
    return CurrentState()
344,835✔
4415
end
4416

4417
function apply_refinement!(๐•ƒแตข::AbstractLattice, slot::SlotNumber, @nospecialize(newtyp),
×
4418
                           currstate::VarTable, currchanges::Union{Nothing,StateUpdate})
4419
    if currchanges !== nothing && currchanges.var == slot
60✔
4420
        return # type propagation from statement (like assignment) should have the precedence
×
4421
    end
4422
    vtype = currstate[slot_id(slot)]
60✔
4423
    oldtyp = vtype.typ
60✔
4424
    โŠ = strictpartialorder(๐•ƒแตข)
60✔
4425
    if newtyp โŠ oldtyp
60✔
4426
        stmtupdate = StateUpdate(slot, VarState(newtyp, vtype.undef))
28✔
4427
        stoverwrite1!(currstate, stmtupdate)
28✔
4428
    end
4429
end
4430

4431
function conditional_change(๐•ƒแตข::AbstractLattice, currstate::VarTable, condt::Conditional, then_or_else::Bool)
4432
    vtype = currstate[condt.slot]
126,686✔
4433
    oldtyp = vtype.typ
126,686✔
4434
    newtyp = then_or_else ? condt.thentype : condt.elsetype
126,686✔
4435
    if iskindtype(newtyp)
253,109✔
4436
        # this code path corresponds to the special handling for `isa(x, iskindtype)` check
4437
        # implemented within `abstract_call_builtin`
4438
    elseif โŠ‘(๐•ƒแตข, ignorelimited(newtyp), ignorelimited(oldtyp))
251,012✔
4439
        # approximate test for `typ โˆฉ oldtyp` being better than `oldtyp`
4440
        # since we probably formed these types with `typesubstract`,
4441
        # the comparison is likely simple
4442
    else
4443
        return nothing
22,882✔
4444
    end
4445
    if oldtyp isa LimitedAccuracy
103,804✔
4446
        # typ is better unlimited, but we may still need to compute the tmeet with the limit
4447
        # "causes" since we ignored those in the comparison
4448
        newtyp = tmerge(๐•ƒแตข, newtyp, LimitedAccuracy(Bottom, oldtyp.causes))
24✔
4449
    end
4450
    # if this `Conditional` is from `@isdefined condt.slot`, refine its `undef` information
4451
    newundef = condt.isdefined ? !then_or_else : vtype.undef
205,442✔
4452
    return StateUpdate(SlotNumber(condt.slot), VarState(newtyp, newundef), #=conditional=#true)
103,804✔
4453
end
4454

4455
function condition_object_change(currstate::VarTable, condt::Conditional,
4456
                                 condslot::SlotNumber, then_or_else::Bool)
4457
    vtype = currstate[slot_id(condslot)]
38,356✔
4458
    newcondt = Conditional(condt.slot,
38,876✔
4459
        then_or_else ? condt.thentype : Union{},
4460
        then_or_else ? Union{} : condt.elsetype)
4461
    return StateUpdate(condslot, VarState(newcondt, vtype.undef))
38,356✔
4462
end
4463

4464
# make as much progress on `frame` as possible (by handling cycles)
4465
warnlength::Int = 2500
4466
function typeinf(interp::AbstractInterpreter, frame::InferenceState)
193,511✔
4467
    time_before = _time_ns()
193,511✔
4468
    callstack = frame.callstack::Vector{AbsIntState}
193,511✔
4469
    nextstates = CurrentState[]
193,511✔
4470
    takenext = frame.frameid
193,511✔
4471
    minwarn = warnlength
193,511✔
4472
    while takenext >= frame.frameid
4,323,382✔
4473
        callee = takenext == 0 ? frame : callstack[takenext]::InferenceState
8,240,708✔
4474
        if !isempty(callstack)
4,131,816✔
4475
            if length(callstack) - frame.frameid >= minwarn
4,110,292✔
4476
                topmethod = callstack[1].linfo
×
4477
                topmethod.def isa Method || (topmethod = callstack[2].linfo)
×
4478
                print(Core.stderr, "info: inference of ", topmethod, " exceeding ", length(callstack), " frames (may be slow).\n")
×
4479
                minwarn *= 2
×
4480
            end
4481
            topcallee = (callstack[end]::InferenceState)
4,110,292✔
4482
            if topcallee.cycleid != callee.cycleid
4,110,292✔
4483
                callee = topcallee
151,169✔
4484
                takenext = length(callstack)
151,169✔
4485
            end
4486
        end
4487
        interp = callee.interp
4,131,816✔
4488
        nextstateid = takenext + 1 - frame.frameid
4,131,816✔
4489
        while length(nextstates) < nextstateid
4,476,496✔
4490
            push!(nextstates, CurrentState())
344,680✔
4491
        end
344,680✔
4492
        if doworkloop(interp, callee)
4,131,816✔
4493
            # First drain the workloop. Note that since some scheduled work doesn't
4494
            # affect the result (e.g. cfunction or abstract_call_method on
4495
            # get_compileable_sig), but still must be finished up since it may see and
4496
            # change the local variables of the InferenceState at currpc, we do this
4497
            # even if the nextresult status is already completed.
4498
        elseif isdefined(nextstates[nextstateid], :result) || !isempty(callee.ip)
2,392,106✔
4499
            # Next make progress on this frame
4500
            prev = length(callee.tasks) + 1
1,335,434✔
4501
            nextstates[nextstateid] = typeinf_local(interp, callee, nextstates[nextstateid])
1,335,434✔
4502
            reverse!(callee.tasks, prev)
1,335,434✔
4503
        elseif callee.cycleid == length(callstack)
354,864✔
4504
            # With no active ip's and no cycles, frame is done
4505
            time_now = _time_ns()
343,922✔
4506
            callee.time_self_ns += (time_now - time_before)
343,922✔
4507
            time_before = time_now
343,922✔
4508
            finish_nocycle(interp, callee, time_before)
343,922✔
4509
            callee.frameid == 0 && break
343,922✔
4510
            takenext = length(callstack)
341,977✔
4511
            nextstateid = takenext + 1 - frame.frameid
341,977✔
4512
            #@assert length(nextstates) == nextstateid + 1
4513
            #@assert all(i -> !isdefined(nextstates[i], :result), nextstateid+1:length(nextstates))
4514
            resize!(nextstates, nextstateid)
341,977✔
4515
            continue
341,977✔
4516
        elseif callee.cycleid == callee.frameid
10,942✔
4517
            # If the current frame is the top part of a cycle, check if the whole cycle
4518
            # is done, and if not, pick the next item to work on.
4519
            time_now = _time_ns()
342✔
4520
            callee.time_self_ns += (time_now - time_before)
342✔
4521
            time_before = time_now
342✔
4522
            no_active_ips_in_cycle = true
342✔
4523
            for i = callee.cycleid:length(callstack)
374✔
4524
                caller = callstack[i]::InferenceState
1,101✔
4525
                @assert caller.cycleid == callee.cycleid
1,101✔
4526
                if !isempty(caller.tasks) || isdefined(nextstates[i+1-frame.frameid], :result) || !isempty(caller.ip)
2,397✔
4527
                    no_active_ips_in_cycle = false
132✔
4528
                    break
132✔
4529
                end
4530
            end
969✔
4531
            if no_active_ips_in_cycle
342✔
4532
                finish_cycle(interp, callstack, callee.cycleid, time_before)
210✔
4533
            end
4534
            takenext = length(callstack)
342✔
4535
            nextstateid = takenext + 1 - frame.frameid
342✔
4536
            if no_active_ips_in_cycle
342✔
4537
                #@assert all(i -> !isdefined(nextstates[i], :result), nextstateid+1:length(nextstates))
4538
                resize!(nextstates, nextstateid)
210✔
4539
            else
4540
                #@assert length(nextstates) == nextstateid
4541
            end
4542
            continue
342✔
4543
        else
4544
            # Continue to the next frame in this cycle
4545
            takenext = takenext - 1
10,600✔
4546
        end
4547
        time_now = _time_ns()
3,787,552✔
4548
        callee.time_self_ns += (time_now - time_before)
3,787,552✔
4549
        time_before = time_now
3,787,552✔
4550
    end
4,129,871✔
4551
    #@assert all(nextresult -> !isdefined(nextresult, :result), nextstates)
4552
    return is_inferred(frame)
193,511✔
4553
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc