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

JuliaLang / julia / 1293

03 Oct 2025 01:05AM UTC coverage: 76.952% (-0.1%) from 77.068%
1293

push

buildkite

web-flow
Support superscript small q (#59544)

Co-authored-by: Steven G. Johnson <stevenj@alum.mit.edu>

61282 of 79637 relevant lines covered (76.95%)

21700458.33 hits per line

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

82.63
/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,149✔
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,438,480✔
13
    isexpr(sv.src.code[currpc], :call) && isempty(sv.ssavalue_uses[currpc])
14
call_result_unused(si::StmtInfo) = !si.used
1,633,963✔
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})
233,847✔
18
    isa(rt, InterConditional) || return false
466,724✔
19
    if rt.slot > length(argtypes)
970✔
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) &&
970✔
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)
217,455✔
44
    SafeBox(@nospecialize x) = new{Any}(x)
×
45
end
46
getindex(box::SafeBox) = box.x
859,872✔
47
setindex!(box::SafeBox{T}, x::T) where T = setfield!(box, :x, x)
215,668✔
48

49
struct FailedMethodMatch
50
    reason::String
19,579✔
51
end
52

53
struct MethodMatchTarget
54
    match::MethodMatch
2,689,441✔
55
    edges::Vector{Union{Nothing,CodeInstance}}
56
    edge_idx::Int
57
end
58

59
struct MethodMatches
60
    applicable::Vector{MethodMatchTarget}
2,637,257✔
61
    info::MethodMatchInfo
62
    valid_worlds::WorldRange
63
end
64
any_ambig(result::MethodLookupResult) = result.ambig
915,818✔
65
any_ambig(info::MethodMatchInfo) = any_ambig(info.results)
915,818✔
66
any_ambig(m::MethodMatches) = any_ambig(m.info)
886,210✔
67
fully_covering(info::MethodMatchInfo) = info.fullmatch
1,342,817✔
68
fully_covering(m::MethodMatches) = fully_covering(m.info)
888,074✔
69

70
struct UnionSplitMethodMatches
71
    applicable::Vector{MethodMatchTarget}
14,879✔
72
    applicable_argtypes::Vector{Vector{Any}}
73
    info::UnionSplitInfo
74
    valid_worlds::WorldRange
75
end
76
any_ambig(info::UnionSplitInfo) = any(any_ambig, info.split)
43,276✔
77
any_ambig(m::UnionSplitMethodMatches) = any_ambig(m.info)
43,276✔
78
fully_covering(info::UnionSplitInfo) = all(fully_covering, info.split)
14,539✔
79
fully_covering(m::UnionSplitMethodMatches) = fully_covering(m.info)
14,539✔
80

81
nmatches(info::MethodMatchInfo) = length(info.results)
504,150✔
82
function nmatches(info::UnionSplitInfo)
83
    n = 0
2,539✔
84
    for mminfo in info.split
7,500✔
85
        n += nmatches(mminfo)
16,389✔
86
    end
16,389✔
87
    return n
7,500✔
88
end
89

90
# intermediate state for computing gfresult
91
mutable struct CallInferenceState
92
    inferidx::Int
93
    rettype
94
    exctype
95
    all_effects::Effects
96
    const_results::Union{Nothing,Vector{Union{Nothing,ConstResult}}} # keeps the results of inference with the extended lattice elements (if happened)
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
    func
102
    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,
903,024✔
105
            #=const_results=#nothing, #=conditionals=#nothing, #=slotrefinements=#nothing,
106
            func, matches)
107
    end
108
end
109

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

126
    (; valid_worlds, applicable) = matches
903,024✔
127
    update_valid_age!(sv, 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
903,024✔
128
    if bail_out_toplevel_call(interp, sv)
903,024✔
129
        local napplicable = length(applicable)
1,059✔
130
        for i = 1:napplicable
1,059✔
131
            local sig = applicable[i].match.spec_types
1,059✔
132
            if !isdispatchtuple(sig)
1,059✔
133
                # only infer fully concrete call sites in top-level expressions (ignoring even isa_compileable_sig matches)
134
                add_remark!(interp, sv, "Refusing to infer non-concrete call site in top-level expression")
×
135
                return Future(CallMeta(Any, Any, Effects(), NoCallInfo()))
×
136
            end
137
        end
1,059✔
138
    end
139

140
    # final result
141
    gfresult = Future{CallMeta}()
903,024✔
142
    state = CallInferenceState(func, matches)
917,924✔
143

144
    # split the for loop off into a function, so that we can pause and restart it at will
145
    function infercalls(interp, sv)
1,935,115✔
146
        local napplicable = length(applicable)
1,032,091✔
147
        local multiple_matches = napplicable > 1
1,032,091✔
148
        while state.inferidx <= napplicable
1,826,607✔
149
            (; match, edges, edge_idx) = applicable[state.inferidx]
924,018✔
150
            local method = match.method
924,018✔
151
            local sig = match.spec_types
924,018✔
152
            if bail_out_call(interp, InferenceLoopState(state.rettype, state.all_effects), sv)
924,018✔
153
                add_remark!(interp, sv, "Call inference reached maximally imprecise information: bailing on doing more abstract inference.")
435✔
154
                break
435✔
155
            end
156
            # 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,
157
            # it also can hurt infer-ability of some constrained parameter types (e.g. quacks like a duck)
158
            # sigtuple = unwrap_unionall(sig)::DataType
159
            # splitunions = 1 < unionsplitcost(sigtuple.parameters) * napplicable <= InferenceParams(interp).max_union_splitting
160
            #if splitunions
161
            #    splitsigs = switchtupleunion(sig)
162
            #    for sig_n in splitsigs
163
            #        result = abstract_call_method(interp, method, sig_n, svec(), multiple_matches, si, sv)::Future
164
            #        handle1(...)
165
            #    end
166
            #end
167
            mresult = abstract_call_method(interp, method, sig, match.sparams, multiple_matches, si, sv)::Future
923,583✔
168
            function handle1(interp, sv)
1,847,166✔
169
                local (; rt, exct, effects, edge, volatile_inf_result) = mresult[]
1,052,650✔
170
                this_conditional = ignorelimited(rt)
1,847,123✔
171
                this_rt = widenwrappedconditional(rt)
923,583✔
172
                this_exct = exct
923,583✔
173
                # try constant propagation with argtypes for this match
174
                # this is in preparation for inlining, or improving the return result
175
                local matches = state.matches
923,583✔
176
                this_argtypes = isa(matches, MethodMatches) ? argtypes : matches.applicable_argtypes[state.inferidx]
954,991✔
177
                this_arginfo = ArgInfo(arginfo.fargs, this_argtypes)
1,799,276✔
178
                const_call_result = abstract_call_method_with_const_args(interp,
1,052,650✔
179
                    mresult[], state.func, this_arginfo, si, match, sv)
180
                const_result = volatile_inf_result
923,583✔
181
                if const_call_result !== nothing
923,583✔
182
                    this_const_conditional = ignorelimited(const_call_result.rt)
789,619✔
183
                    this_const_rt = widenwrappedconditional(const_call_result.rt)
394,823✔
184
                    const_edge = nothing
394,823✔
185
                    if this_const_rt โŠ‘โ‚š this_rt
394,823✔
186
                        # As long as the const-prop result we have is not *worse* than
187
                        # what we found out on types, we'd like to use it. Even if the
188
                        # end result is exactly equivalent, it is likely that the IR
189
                        # we produced while constproping is better than that with
190
                        # generic types.
191
                        # Return type of const-prop' inference can be wider than that of non const-prop' inference
192
                        # e.g. in cases when there are cycles but cached result is still accurate
193
                        this_conditional = this_const_conditional
394,805✔
194
                        this_rt = this_const_rt
394,805✔
195
                        (; effects, const_result, const_edge) = const_call_result
394,805✔
196
                    elseif is_better_effects(const_call_result.effects, effects)
18✔
197
                        (; effects, const_result, const_edge) = const_call_result
6✔
198
                    else
199
                        add_remark!(interp, sv, "[constprop] Discarded because the result was wider than inference")
12✔
200
                    end
201
                    # Treat the exception type separately. Currently, constprop often cannot determine the exception type
202
                    # because consistent-cy does not apply to exceptions.
203
                    if const_call_result.exct โ‹ค this_exct
394,823✔
204
                        this_exct = const_call_result.exct
165,563✔
205
                        (; const_result, const_edge) = const_call_result
165,563✔
206
                    else
207
                        add_remark!(interp, sv, "[constprop] Discarded exception type because result was wider than inference")
229,260✔
208
                    end
209
                    if const_edge !== nothing
394,823✔
210
                        edge = const_edge
383,629✔
211
                        update_valid_age!(sv, world_range(const_edge))
383,629✔
212
                    end
213
                end
214

215
                state.all_effects = merge_effects(state.all_effects, effects)
1,843,780✔
216
                if const_result !== nothing
923,583✔
217
                    local const_results = state.const_results
503,256✔
218
                    if const_results === nothing
503,256✔
219
                        const_results = state.const_results = fill!(Vector{Union{Nothing,ConstResult}}(undef, napplicable), nothing)
505,960✔
220
                    end
221
                    const_results[state.inferidx] = const_result
503,256✔
222
                end
223
                @assert !(this_conditional isa Conditional || this_rt isa MustAlias) "invalid lattice element returned from inter-procedural context"
923,583✔
224
                if can_propagate_conditional(this_conditional, argtypes)
923,583✔
225
                    # The only case where we need to keep this in rt is where
226
                    # we can directly propagate the conditional to a slot argument
227
                    # that is not one of our arguments, otherwise we keep all the
228
                    # relevant information in `conditionals` below.
229
                    this_rt = this_conditional
2,481✔
230
                end
231

232
                state.rettype = state.rettype โŠ”โ‚š this_rt
923,877✔
233
                state.exctype = state.exctype โŠ”โ‚š this_exct
923,877✔
234
                if has_conditional(๐•ƒโ‚š, sv) && this_conditional !== Bottom && is_lattice_bool(๐•ƒโ‚š, state.rettype) && arginfo.fargs !== nothing
923,583✔
235
                    local conditionals = state.conditionals
146,552✔
236
                    if conditionals === nothing
146,552✔
237
                        conditionals = state.conditionals = (
403,408✔
238
                            Any[Bottom for _ in 1:length(argtypes)],
239
                            Any[Bottom for _ in 1:length(argtypes)])
240
                    end
241
                    for i = 1:length(argtypes)
165,338✔
242
                        cnd = conditional_argtype(๐•ƒแตข, this_conditional, match.spec_types, argtypes, i)
409,660✔
243
                        conditionals[1][i] = conditionals[1][i] โŠ”แตข cnd.thentype
409,660✔
244
                        conditionals[2][i] = conditionals[2][i] โŠ”แตข cnd.elsetype
409,660✔
245
                    end
672,768✔
246
                end
247
                edges[edge_idx] = edge
923,583✔
248

249
                state.inferidx += 1
923,583✔
250
                return true
923,583✔
251
            end # function handle1
252
            if isready(mresult) && handle1(interp, sv)
1,052,650✔
253
                continue
794,516✔
254
            else
255
                push!(sv.tasks, handle1)
129,067✔
256
                return false
129,067✔
257
            end
258
        end # while
794,516✔
259

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

303
        # Also considering inferring the compilation signature for this method, so
304
        # it is available to the compiler in case it ends up needing it for the invoke.
305
        if (isa(sv, InferenceState) && infer_compilation_signature(interp) &&
916,845✔
306
            (!is_removable_if_unused(state.all_effects) || !call_result_unused(si)))
307
            inferidx = SafeBox{Int}(1)
217,455✔
308
            function infercalls2(interp, sv)
430,341✔
309
                local napplicable = length(applicable)
212,886✔
310
                local multiple_matches = napplicable > 1
212,886✔
311
                while inferidx[] <= napplicable
428,536✔
312
                    (; match) = applicable[inferidx[]]
215,668✔
313
                    inferidx[] += 1
215,668✔
314
                    local method = match.method
215,668✔
315
                    local sig = match.spec_types
215,668✔
316
                    mi = specialize_method(match; preexisting=true)
215,668✔
317
                    if mi === nothing || !const_prop_methodinstance_heuristic(interp, mi, arginfo, sv)
431,336✔
318
                        csig = get_compileable_sig(method, sig, match.sparams)
17,588✔
319
                        if csig !== nothing && (!seenall || csig !== sig) # corresponds to whether the first look already looked at this, so repeating abstract_call_method is not useful
35,146✔
320
                            #println(sig, " changed to ", csig, " for ", method)
321
                            sp_ = ccall(:jl_type_intersection_with_env, Any, (Any, Any), csig, method.sig)::SimpleVector
2,532✔
322
                            sparams = sp_[2]::SimpleVector
2,532✔
323
                            mresult = abstract_call_method(interp, method, csig, sparams, multiple_matches, StmtInfo(false, false), sv)::Future
2,532✔
324
                            isready(mresult) || return false # wait for mresult Future to resolve off the callstack before continuing
2,550✔
325
                        end
326
                    end
327
                end
215,650✔
328
                return true
212,868✔
329
            end
330
            # start making progress on the first call
331
            infercalls2(interp, sv) || push!(sv.tasks, infercalls2)
217,473✔
332
        end
333

334
        gfresult[] = CallMeta(state.rettype, state.exctype, state.all_effects, retinfo, state.slotrefinements)
1,310,936✔
335
        return true
903,024✔
336
    end # function infercalls
337
    # start making progress on the first call
338
    infercalls(interp, sv) || push!(sv.tasks, infercalls)
1,028,512✔
339
    return gfresult
903,024✔
340
end
341

342
function find_method_matches(interp::AbstractInterpreter, argtypes::Vector{Any}, @nospecialize(atype);
1,799,662✔
343
                             max_union_splitting::Int = InferenceParams(interp).max_union_splitting,
344
                             max_methods::Int = InferenceParams(interp).max_methods)
345
    if is_union_split_eligible(typeinf_lattice(interp), argtypes, max_union_splitting)
907,308✔
346
        return find_union_split_method_matches(interp, argtypes, max_methods)
14,954✔
347
    end
348
    return find_simple_method_matches(interp, atype, max_methods)
892,354✔
349
end
350

351
# NOTE this is valid as far as any "constant" lattice element doesn't represent `Union` type
352
is_union_split_eligible(๐•ƒ::AbstractLattice, argtypes::Vector{Any}, max_union_splitting::Int) =
907,308✔
353
    1 < unionsplitcost(๐•ƒ, argtypes) <= max_union_splitting
354

355
function find_union_split_method_matches(interp::AbstractInterpreter, argtypes::Vector{Any},
14,933✔
356
                                         max_methods::Int)
357
    split_argtypes = switchtupleunion(typeinf_lattice(interp), argtypes)
14,933✔
358
    infos = MethodMatchInfo[]
14,933✔
359
    applicable = MethodMatchTarget[]
14,933✔
360
    applicable_argtypes = Vector{Any}[] # arrays like `argtypes`, including constants, for each match
14,933✔
361
    valid_worlds = WorldRange()
14,933✔
362
    for i in 1:length(split_argtypes)
17,682✔
363
        arg_n = split_argtypes[i]::Vector{Any}
32,716✔
364
        sig_n = argtypes_to_type(arg_n)
32,716✔
365
        sig_n === Bottom && continue
32,716✔
366
        thismatches = findall(sig_n, method_table(interp); limit = max_methods)
32,770✔
367
        if thismatches === nothing
32,716✔
368
            return FailedMethodMatch("For one of the union split cases, too many methods matched")
54✔
369
        end
370
        valid_worlds = intersect(valid_worlds, thismatches.valid_worlds)
32,662✔
371
        thisfullmatch = any(match::MethodMatch->match.fully_covers, thismatches)
65,096✔
372
        mt = Core.methodtable
32,662✔
373
        thisinfo = MethodMatchInfo(thismatches, mt, sig_n, thisfullmatch)
33,085✔
374
        push!(infos, thisinfo)
32,662✔
375
        for idx = 1:length(thismatches)
38,208✔
376
            push!(applicable, MethodMatchTarget(thismatches[idx], thisinfo.edges, idx))
31,849✔
377
            push!(applicable_argtypes, arg_n)
31,849✔
378
        end
31,849✔
379
    end
50,445✔
380
    info = UnionSplitInfo(infos)
14,879✔
381
    return UnionSplitMethodMatches(
14,879✔
382
        applicable, applicable_argtypes, info, valid_worlds)
383
end
384

385
function find_simple_method_matches(interp::AbstractInterpreter, @nospecialize(atype), max_methods::Int)
2,660,914✔
386
    matches = findall(atype, method_table(interp); limit = max_methods)
2,664,989✔
387
    if matches === nothing
2,660,914✔
388
        # this means too many methods matched
389
        # (assume this will always be true, so we don't compute / update valid age in this case)
390
        return FailedMethodMatch("Too many methods matched")
23,657✔
391
    end
392
    fullmatch = any(match::MethodMatch->match.fully_covers, matches)
5,326,872✔
393
    mt = Core.methodtable
2,637,257✔
394
    info = MethodMatchInfo(matches, mt, atype, fullmatch)
2,658,799✔
395
    applicable = MethodMatchTarget[MethodMatchTarget(matches[idx], info.edges, idx) for idx = 1:length(matches)]
2,658,799✔
396
    return MethodMatches(applicable, info, matches.valid_worlds)
2,637,257✔
397
end
398

399
"""
400
    from_interprocedural!(interp::AbstractInterpreter, rt, sv::AbsIntState,
401
                          arginfo::ArgInfo, maybecondinfo) -> newrt
402

403
Converts inter-procedural return type `rt` into a local lattice element `newrt`,
404
that is appropriate in the context of current local analysis frame `sv`, especially:
405
- unwraps `rt::LimitedAccuracy` and collects its limitations into the current frame `sv`
406
- converts boolean `rt` to new boolean `newrt` in a way `newrt` can propagate extra conditional
407
  refinement information, e.g. translating `rt::InterConditional` into `newrt::Conditional`
408
  that holds a type constraint information about a variable in `sv`
409

410
This function _should_ be used wherever we propagate results returned from
411
`abstract_call_method` or `abstract_call_method_with_const_args`.
412

413
When `maybecondinfo !== nothing`, this function also tries extra conditional argument type refinement.
414
In such cases `maybecondinfo` should be either of:
415
- `maybecondinfo::Tuple{Vector{Any},Vector{Any}}`: precomputed argument type refinement information
416
- method call signature tuple type
417
When we deal with multiple `MethodMatch`es, it's better to precompute `maybecondinfo` by
418
`tmerge`ing argument signature type of each method call.
419
"""
420
function from_interprocedural!(interp::AbstractInterpreter, @nospecialize(rt), sv::AbsIntState,
704,241✔
421
                               arginfo::ArgInfo, @nospecialize(maybecondinfo))
422
    rt = collect_limitations!(rt, sv)
1,795,812✔
423
    if isa(rt, InterMustAlias)
897,929✔
424
        rt = from_intermustalias(typeinf_lattice(interp), rt, arginfo, sv)
147✔
425
    elseif is_lattice_bool(ipo_lattice(interp), rt)
897,782✔
426
        if maybecondinfo === nothing
145,147✔
427
            rt = widenconditional(rt)
1,606✔
428
        else
429
            rt = from_interconditional(typeinf_lattice(interp), rt, sv, arginfo, maybecondinfo)
143,541✔
430
        end
431
    end
432
    @assert !(rt isa InterConditional || rt isa InterMustAlias) "invalid lattice element returned from inter-procedural context"
897,929✔
433
    return rt
897,929✔
434
end
435

436
function collect_limitations!(@nospecialize(typ), sv::InferenceState)
437
    if isa(typ, LimitedAccuracy)
5,803,240✔
438
        union!(sv.pclimitations, typ.causes)
175✔
439
        return typ.typ
175✔
440
    end
441
    return typ
5,803,065✔
442
end
443

444
function from_intermustalias(๐•ƒแตข::AbstractLattice, rt::InterMustAlias, arginfo::ArgInfo, sv::AbsIntState)
147✔
445
    fargs = arginfo.fargs
147✔
446
    if fargs !== nothing && 1 โ‰ค rt.slot โ‰ค length(fargs)
147✔
447
        arg = ssa_def_slot(fargs[rt.slot], sv)
147✔
448
        if isa(arg, SlotNumber)
147✔
449
            argtyp = widenslotwrapper(arginfo.argtypes[rt.slot])
147✔
450
            โŠ‘ = partialorder(๐•ƒแตข)
147✔
451
            if rt.vartyp โŠ‘ argtyp
147✔
452
                return MustAlias(arg, rt.vartyp, rt.fldidx, rt.fldtyp)
147✔
453
            else
454
                # TODO optimize this case?
455
            end
456
        end
457
    end
458
    return widenmustalias(rt)
×
459
end
460

461
function from_interconditional(๐•ƒแตข::AbstractLattice, @nospecialize(rt), sv::AbsIntState,
18,744✔
462
                               arginfo::ArgInfo, @nospecialize(maybecondinfo))
463
    has_conditional(๐•ƒแตข, sv) || return widenconditional(rt)
18,744✔
464
    (; fargs, argtypes) = arginfo
18,744✔
465
    fargs === nothing && return widenconditional(rt)
18,744✔
466
    if can_propagate_conditional(rt, argtypes)
18,744✔
467
        return propagate_conditional(rt, argtypes[rt.slot]::Conditional)
6✔
468
    end
469
    slot = 0
18,738✔
470
    alias = nothing
18,738✔
471
    thentype = elsetype = Any
18,738✔
472
    condval = maybe_extract_const_bool(rt)
21,798✔
473
    โŠ‘, โ‹ค, โŠ“ = partialorder(๐•ƒแตข), strictneqpartialorder(๐•ƒแตข), meet(๐•ƒแตข)
18,738✔
474
    for i in 1:length(fargs)
37,434✔
475
        # find the first argument which supports refinement,
476
        # and intersect all equivalent arguments with it
477
        argtyp = argtypes[i]
52,754✔
478
        if alias === nothing
52,754✔
479
            arg = ssa_def_slot(fargs[i], sv)
52,745✔
480
            if isa(arg, SlotNumber) && widenslotwrapper(argtyp) isa Type
52,745✔
481
                old = argtyp
1,958✔
482
                id = slot_id(arg)
1,958✔
483
            elseif argtyp isa MustAlias
50,787✔
484
                old = argtyp.fldtyp
24✔
485
                id = argtyp.slot
24✔
486
            else
487
                continue # unlikely to refine
50,763✔
488
            end
489
        elseif argtyp isa MustAlias && issubalias(argtyp, alias)
9✔
490
            arg = nothing
6✔
491
            old = alias.fldtyp
6✔
492
            id = alias.slot
6✔
493
        else
494
            continue
3✔
495
        end
496
        if slot == 0 || id == slot
1,994✔
497
            if isa(maybecondinfo, Tuple{Vector{Any},Vector{Any}})
1,988✔
498
                # if we have already computed argument refinement information, apply that now to get the result
499
                new_thentype = maybecondinfo[1][i]
1,988✔
500
                new_elsetype = maybecondinfo[2][i]
1,988✔
501
            else
502
                # otherwise compute it on the fly
503
                cnd = conditional_argtype(๐•ƒแตข, rt, maybecondinfo, argtypes, i)
×
504
                new_thentype = cnd.thentype
×
505
                new_elsetype = cnd.elsetype
×
506
            end
507
            if condval === false
1,988✔
508
                thentype = Bottom
6✔
509
            elseif new_thentype โŠ‘ thentype
1,982✔
510
                thentype = new_thentype
1,979✔
511
            else
512
                thentype = thentype โŠ“ widenconst(new_thentype)
3✔
513
            end
514
            if condval === true
1,988✔
515
                elsetype = Bottom
29✔
516
            elseif new_elsetype โŠ‘ elsetype
1,959✔
517
                elsetype = new_elsetype
1,956✔
518
            else
519
                elsetype = elsetype โŠ“ widenconst(new_elsetype)
3✔
520
            end
521
            if (slot > 0 || condval !== false) && thentype โ‹ค old
3,922✔
522
                slot = id
42✔
523
                if !(arg isa SlotNumber) && argtyp isa MustAlias
42✔
524
                    alias = argtyp
27✔
525
                end
526
            elseif (slot > 0 || condval !== true) && elsetype โ‹ค old
3,865✔
527
                slot = id
3✔
528
                if !(arg isa SlotNumber) && argtyp isa MustAlias
3✔
529
                    alias = argtyp
3✔
530
                end
531
            else # reset: no new useful information for this slot
532
                slot = 0
1,943✔
533
                alias = nothing
1,943✔
534
                thentype = elsetype = Any
1,943✔
535
            end
536
        end
537
    end
86,770✔
538
    if thentype === Bottom && elsetype === Bottom
18,738✔
539
        return Bottom # accidentally proved this call to be dead / throw !
×
540
    elseif slot > 0
18,738✔
541
        if alias !== nothing
39✔
542
            return form_mustalias_conditional(alias, thentype, elsetype)
24✔
543
        end
544
        return Conditional(slot, thentype, elsetype) # record a Conditional improvement to this slot
15✔
545
    end
546
    return widenconditional(rt)
18,699✔
547
end
548

549
function conditional_argtype(๐•ƒแตข::AbstractLattice, @nospecialize(rt), @nospecialize(sig),
53,042✔
550
                             argtypes::Vector{Any}, i::Int)
551
    if isa(rt, InterConditional) && rt.slot == i
53,042✔
552
        return rt
961✔
553
    else
554
        argt = widenslotwrapper(argtypes[i])
52,081✔
555
        if isvarargtype(argt)
52,081✔
556
            @assert fieldcount(sig) == i
×
557
            argt = unwrapva(argt)
×
558
        end
559
        thentype = elsetype = tmeet(๐•ƒแตข, argt, fieldtype(sig, i))
52,081✔
560
        condval = maybe_extract_const_bool(rt)
62,006✔
561
        condval === true && (elsetype = Bottom)
52,081✔
562
        condval === false && (thentype = Bottom)
52,081✔
563
        return InterConditional(i, thentype, elsetype)
52,081✔
564
    end
565
end
566

567
function collect_slot_refinements(๐•ƒแตข::AbstractLattice, applicable::Vector{MethodMatchTarget},
173,583✔
568
    argtypes::Vector{Any}, fargs::Vector{Any}, sv::InferenceState)
569
    โŠ, โŠ” = strictpartialorder(๐•ƒแตข), join(๐•ƒแตข)
173,583✔
570
    slotrefinements = nothing
173,583✔
571
    for i = 1:length(fargs)
346,884✔
572
        fargแตข = fargs[i]
499,511✔
573
        if fargแตข isa SlotNumber
499,511✔
574
            fidx = slot_id(fargแตข)
109,795✔
575
            argt = widenslotwrapper(argtypes[i])
110,011✔
576
            if isvarargtype(argt)
109,795✔
577
                argt = unwrapva(argt)
×
578
            end
579
            sigt = Bottom
109,795✔
580
            for j = 1:length(applicable)
219,359✔
581
                (;match) = applicable[j]
109,799✔
582
                valid_as_lattice(match.spec_types, true) || continue
219,598✔
583
                sigt = sigt โŠ” fieldtype(match.spec_types, i)
219,598✔
584
            end
109,818✔
585
            if sigt โŠ argt # i.e. signature type is strictly more specific than the type of the argument slot
109,795✔
586
                if slotrefinements === nothing
15✔
587
                    slotrefinements = fill!(Vector{Any}(undef, length(sv.slottypes)), nothing)
75✔
588
                end
589
                slotrefinements[fidx] = sigt
15✔
590
            end
591
        end
592
    end
825,439✔
593
    return slotrefinements
173,583✔
594
end
595

596
const RECURSION_UNUSED_MSG = "Bounded recursion detected with unused result. Annotated return type may be wider than true result."
597
const RECURSION_MSG = "Bounded recursion detected. Call was widened to force convergence."
598
const RECURSION_MSG_HARDLIMIT = "Bounded recursion detected under hardlimit. Call was widened to force convergence."
599

600
function abstract_call_method(interp::AbstractInterpreter,
921,827✔
601
                              method::Method, @nospecialize(sig), sparams::SimpleVector,
602
                              hardlimit::Bool, si::StmtInfo, sv::AbsIntState)
603
    sigtuple = unwrap_unionall(sig)
921,827✔
604
    sigtuple isa DataType ||
921,827✔
605
        return Future(MethodCallResult(Any, Any, Effects(), nothing, false, false))
606
    all(@nospecialize(x) -> isvarargtype(x) || valid_as_lattice(x, true), sigtuple.parameters) ||
6,286,436✔
607
        return Future(MethodCallResult(Union{}, Any, EFFECTS_THROWS, nothing, false, false)) # catch bad type intersections early
608

609
    if is_nospecializeinfer(method)
921,815✔
610
        sig = get_nospecializeinfer_sig(method, sig, sparams)
687✔
611
    end
612

613
    # Limit argument type tuple growth of functions:
614
    # look through the parents list to see if there's a call to the same method
615
    # and from the same method.
616
    # Returns the topmost occurrence of that repeated edge.
617
    edgecycle = edgelimited = false
921,815✔
618
    topmost = nothing
921,815✔
619

620
    for svโ€ฒ in AbsIntStackUnwind(sv)
1,839,381✔
621
        infmi = frame_instance(svโ€ฒ)
33,280,040✔
622
        if method === infmi.def
16,640,020✔
623
            if infmi.specTypes::Type == sig::Type
8,440✔
624
                # avoid widening when detecting self-recursion
625
                # TODO: merge call cycle and return right away
626
                topmost = nothing
3,406✔
627
                edgecycle = true
3,406✔
628
                break
3,406✔
629
            end
630
            topmost === nothing || continue
5,034✔
631
            if edge_matches_sv(interp, svโ€ฒ, method, sig, sparams, hardlimit, sv)
4,110✔
632
                topmost = svโ€ฒ
1,843✔
633
                edgecycle = true
1,843✔
634
            end
635
        end
636
    end
16,636,614✔
637
    washardlimit = hardlimit
921,815✔
638

639
    if topmost !== nothing
921,815✔
640
        msig = unwrap_unionall(method.sig)::DataType
1,564✔
641
        spec_len = length(msig.parameters) + 1
1,564✔
642
        mi = frame_instance(sv)
1,564✔
643

644
        if isdefined(method, :recursion_relation)
1,564✔
645
            # We don't require the recursion_relation to be transitive, so
646
            # apply a hard limit
647
            hardlimit = true
×
648
        end
649

650
        if method === mi.def
1,564✔
651
            # Under direct self-recursion, permit much greater use of reducers.
652
            # here we assume that complexity(specTypes) :>= complexity(sig)
653
            comparison = mi.specTypes
606✔
654
            l_comparison = length((unwrap_unionall(comparison)::DataType).parameters)
606✔
655
            spec_len = max(spec_len, l_comparison)
606✔
656
        elseif !hardlimit && isa(topmost, InferenceState)
958✔
657
            # Without a hardlimit, permit use of reducers too.
658
            comparison = frame_instance(topmost).specTypes
404✔
659
            # n.b. currently don't allow vararg reducers
660
            #l_comparison = length((unwrap_unionall(comparison)::DataType).parameters)
661
            #spec_len = max(spec_len, l_comparison)
662
        else
663
            comparison = method.sig
554✔
664
        end
665

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

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

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

735
    return typeinf_edge(interp, method, sig, sparams, sv, edgecycle, edgelimited)
921,372✔
736
end
737

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

762
        # check in the cycle list first
763
        # all items in here are considered mutual parents of all others
764
        if !any(p::AbsIntState->matches_sv(p, sv), callers_in_cycle(frame))
15,383✔
765
            let parent = cycle_parent(frame)
5,553✔
766
                parent === nothing && return false
2,787✔
767
                (is_cached(parent) || frame_parent(parent) !== nothing) || return false
3,145✔
768
                matches_sv(parent, sv) || return false
5,012✔
769
            end
770
        end
771

772
        # If the method defines a recursion relation, give it a chance
773
        # to tell us that this recursion is actually ok.
774
        if isdefined(method, :recursion_relation)
803✔
775
            if Core._call_in_world_total(get_world_counter(), method.recursion_relation, method, callee_method2, sig, frame_instance(frame).specTypes)
×
776
                return false
×
777
            end
778
        end
779
    end
780
    return true
1,843✔
781
end
782

783
# This function is used for computing alternate limit heuristics
784
function method_for_inference_heuristics(method::Method, @nospecialize(sig), sparams::SimpleVector, world::UInt)
422✔
785
    if (hasgenerator(method) && !(method.generator isa Core.GeneratedFunctionStub) &&
422✔
786
        may_invoke_generator(method, sig, sparams))
787
        mi = specialize_method(method, sig, sparams)
9✔
788
        cinfo = get_staged(mi, world)
9✔
789
        if isa(cinfo, CodeInfo)
9✔
790
            method2 = cinfo.method_for_inference_limit_heuristics
9✔
791
            if method2 isa Method
9✔
792
                return method2
×
793
            end
794
        end
795
    end
796
    return nothing
422✔
797
end
798

799
function matches_sv(parent::AbsIntState, sv::AbsIntState)
800
    # limit only if user token match
801
    return (frame_instance(parent).def === frame_instance(sv).def &&
13,315✔
802
            method_for_inference_limit_heuristics(sv) === method_for_inference_limit_heuristics(parent))
803
end
804

805
function is_edge_recursed(edge::CodeInstance, caller::AbsIntState)
806
    return any(AbsIntStackUnwind(caller)) do sv::AbsIntState
69,416✔
807
        return edge.def === frame_instance(sv)
65,026✔
808
    end
809
end
810

811
function is_method_recursed(method::Method, caller::AbsIntState)
×
812
    return any(AbsIntStackUnwind(caller)) do sv::AbsIntState
×
813
        return method === frame_instance(sv).def
×
814
    end
815
end
816

817
function is_constprop_edge_recursed(edge::MethodInstance, caller::AbsIntState)
818
    return any(AbsIntStackUnwind(caller)) do sv::AbsIntState
621✔
819
        return edge === frame_instance(sv) && is_constproped(sv)
1,164✔
820
    end
821
end
822

823
function is_constprop_method_recursed(method::Method, caller::AbsIntState)
824
    return any(AbsIntStackUnwind(caller)) do sv::AbsIntState
48✔
825
        return method === frame_instance(sv).def && is_constproped(sv)
78✔
826
    end
827
end
828

829
# keeps result and context information of abstract_method_call, which will later be used for
830
# backedge computation, and concrete evaluation or constant-propagation
831
struct MethodCallResult
832
    rt
833
    exct
834
    effects::Effects
835
    edge::Union{Nothing,CodeInstance}
836
    edgecycle::Bool
837
    edgelimited::Bool
838
    volatile_inf_result::Union{Nothing,VolatileInferenceResult}
839
    function MethodCallResult(@nospecialize(rt), @nospecialize(exct), effects::Effects,
840
                              edge::Union{Nothing,CodeInstance}, edgecycle::Bool, edgelimited::Bool,
841
                              volatile_inf_result::Union{Nothing,VolatileInferenceResult}=nothing)
842
        return new(rt, exct, effects, edge, edgecycle, edgelimited, volatile_inf_result)
1,074,312✔
843
    end
844
end
845

846
struct InvokeCall
847
    types     # ::Type
848
    InvokeCall(@nospecialize(types)) = new(types)
448✔
849
end
850

851
struct ConstCallResult
852
    rt::Any
853
    exct::Any
854
    const_result::ConstResult
855
    effects::Effects
856
    const_edge::Union{Nothing,CodeInstance}
857
    function ConstCallResult(
858
        @nospecialize(rt), @nospecialize(exct),
859
        const_result::ConstResult, effects::Effects,
860
        const_edge::Union{Nothing,CodeInstance})
861
        return new(rt, exct, const_result, effects, const_edge)
394,641✔
862
    end
863
end
864

865
function abstract_call_method_with_const_args(interp::AbstractInterpreter,
924,037✔
866
    result::MethodCallResult, @nospecialize(f), arginfo::ArgInfo, si::StmtInfo,
867
    match::MethodMatch, sv::AbsIntState, invokecall::Union{Nothing,InvokeCall}=nothing)
868
    if bail_out_const_call(interp, result, si, match, sv)
2,768,165✔
869
        return nothing
8,940✔
870
    end
871
    eligibility = concrete_eval_eligible(interp, f, result, arginfo, sv)
1,706,141✔
872
    concrete_eval_result = nothing
915,097✔
873
    if eligibility === :concrete_eval
915,097✔
874
        concrete_eval_result = concrete_eval_call(interp, f, result, arginfo, sv, invokecall)
10,852✔
875
        # if we don't inline the result of this concrete evaluation,
876
        # give const-prop' a chance to inline a better method body
877
        if !may_optimize(interp) || (
10,891✔
878
            may_inline_concrete_result(concrete_eval_result.const_result::ConcreteResult) ||
879
            concrete_eval_result.rt === Bottom) # unless this call deterministically throws and thus is non-inlineable
880
            return concrete_eval_result
10,816✔
881
        end
882
        # TODO allow semi-concrete interp for this call?
883
    end
884
    mi = maybe_get_const_prop_profitable(interp, result, f, arginfo, si, match, sv)
904,281✔
885
    mi === nothing && return concrete_eval_result
904,281✔
886
    if is_constprop_recursed(result, mi, sv)
427,198✔
887
        add_remark!(interp, sv, "[constprop] Edge cycle encountered")
176✔
888
        return nothing
176✔
889
    end
890
    # try semi-concrete evaluation
891
    if eligibility === :semi_concrete_eval
427,022✔
892
        irinterp_result = semi_concrete_eval_call(interp, mi, result, arginfo, sv)
429✔
893
        if irinterp_result !== nothing
429✔
894
            return irinterp_result
330✔
895
        end
896
    end
897
    # try constant prop'
898
    return const_prop_call(interp, mi, result, arginfo, sv, concrete_eval_result)
426,692✔
899
end
900

901
function bail_out_const_call(interp::AbstractInterpreter, result::MethodCallResult,
3,678✔
902
                             si::StmtInfo, match::MethodMatch, sv::AbsIntState)
903
    if !InferenceParams(interp).ipo_constant_propagation
924,037✔
904
        add_remark!(interp, sv, "[constprop] Disabled by parameter")
×
905
        return true
×
906
    end
907
    if is_no_constprop(match.method)
924,037✔
908
        add_remark!(interp, sv, "[constprop] Disabled by method parameter")
2,359✔
909
        return true
2,365✔
910
    end
911
    if is_removable_if_unused(result.effects)
921,672✔
912
        if isa(result.rt, Const)
26,075✔
913
            add_remark!(interp, sv, "[constprop] No more information to be gained (const)")
6,180✔
914
            return true
6,455✔
915
        elseif call_result_unused(si)
19,620✔
916
            add_remark!(interp, sv, "[constprop] No more information to be gained (unused result)")
×
917
            return true
3✔
918
        end
919
    end
920
    if result.rt === Bottom
915,214✔
921
        if is_terminates(result.effects) && is_effect_free(result.effects)
11,547✔
922
            # In the future, we may want to add `&& isa(result.exct, Const)` to
923
            # the list of conditions here, but currently, our effect system isn't
924
            # precise enough to let us determine :consistency of `exct`, so we
925
            # would have to force constprop just to determine this, which is too
926
            # expensive.
927
            add_remark!(interp, sv, "[constprop] No more information to be gained (bottom)")
51✔
928
            return true
117✔
929
        end
930
    end
931
    return false
915,097✔
932
end
933

934
function concrete_eval_eligible(interp::AbstractInterpreter,
3,645✔
935
    @nospecialize(f), result::MethodCallResult, arginfo::ArgInfo, sv::AbsIntState)
936
    (;effects) = result
915,097✔
937
    if inbounds_option() === :off
1,623,089✔
938
        if !is_nothrow(effects)
×
939
            # Disable concrete evaluation in `--check-bounds=no` mode,
940
            # unless it is known to not throw.
941
            return :none
×
942
        end
943
    end
944
    if result.edge !== nothing && is_foldable(effects, #=check_rtcall=#true)
921,511✔
945
        if f !== nothing && is_all_const_arg(arginfo, #=start=#2)
18,501✔
946
            if (is_nonoverlayed(interp) || is_nonoverlayed(effects) ||
10,360✔
947
                # Even if overlay methods are involved, when `:consistent_overlay` is
948
                # explicitly applied, we can still perform concrete evaluation using the
949
                # original methods for executing them.
950
                # While there's a chance that the non-overlayed counterparts may raise
951
                # non-egal exceptions, it will not impact the compilation validity, since:
952
                # - the results of the concrete evaluation will not be inlined
953
                # - the exception types from the concrete evaluation will not be propagated
954
                is_consistent_overlay(effects))
955
                return :concrete_eval
10,852✔
956
            end
957
            # disable concrete-evaluation if this function call is tainted by some overlayed
958
            # method since currently there is no easy way to execute overlayed methods
959
            add_remark!(interp, sv, "[constprop] Concrete eval disabled for overlayed methods")
3✔
960
        end
961
        if !any_conditional(arginfo)
30,517✔
962
            if may_optimize(interp)
6,213✔
963
                return :semi_concrete_eval
1,764✔
964
            else
965
                # disable irinterp if optimization is disabled, since it requires optimized IR
966
                add_remark!(interp, sv, "[constprop] Semi-concrete interpretation disabled for non-optimizing interpreter")
5,849✔
967
            end
968
        end
969
    end
970
    return :none
902,481✔
971
end
972

973
is_all_const_arg(arginfo::ArgInfo, start::Int) = is_all_const_arg(arginfo.argtypes, start::Int)
18,501✔
974
function is_all_const_arg(argtypes::Vector{Any}, start::Int)
187,678✔
975
    for i = start:length(argtypes)
375,353✔
976
        argtype = widenslotwrapper(argtypes[i])
319,268✔
977
        is_const_argtype(argtype) || return false
380,108✔
978
    end
386,871✔
979
    return true
125,788✔
980
end
981

982
is_const_argtype(@nospecialize argtype) = isa(argtype, Const) || isconstType(argtype) || issingletontype(argtype)
380,222✔
983

984
any_conditional(argtypes::Vector{Any}) = any(@nospecialize(x)->isa(x, Conditional), argtypes)
53,421✔
985
any_conditional(arginfo::ArgInfo) = any_conditional(arginfo.argtypes)
30,517✔
986

987
collect_const_args(arginfo::ArgInfo, start::Int) = collect_const_args(arginfo.argtypes, start)
10,348✔
988
function collect_const_args(argtypes::Vector{Any}, start::Int)
108,156✔
989
    return Any[ let a = widenslotwrapper(argtypes[i])
108,174✔
990
                    isa(a, Const) ? a.val :
228,876✔
991
                    isconstType(a) ? a.parameters[1] :
992
                    (a::DataType).instance
993
                end for i = start:length(argtypes) ]
994
end
995

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

1019
# check if there is a cycle and duplicated inference of `mi`
1020
function is_constprop_recursed(result::MethodCallResult, mi::MethodInstance, sv::AbsIntState)
161,267✔
1021
    result.edgecycle || return false
322,498✔
1022
    if result.edgelimited
36✔
1023
        return is_constprop_method_recursed(mi.def::Method, sv)
6✔
1024
    else
1025
        # if the type complexity limiting didn't decide to limit the call signature (as
1026
        # indicated by `result.edgelimited === false`), we can relax the cycle detection
1027
        # by comparing `MethodInstance`s and allow inference to propagate different
1028
        # constant elements if the recursion is finite over the lattice
1029
        return is_constprop_edge_recursed(mi, sv)
30✔
1030
    end
1031
end
1032

1033
# if there's a possibility we could get a better result with these constant arguments
1034
# (hopefully without doing too much work), returns `MethodInstance`, or nothing otherwise
1035
function maybe_get_const_prop_profitable(interp::AbstractInterpreter,
899,843✔
1036
    result::MethodCallResult, @nospecialize(f), arginfo::ArgInfo, si::StmtInfo,
1037
    match::MethodMatch, sv::AbsIntState)
1038
    method = match.method
899,843✔
1039
    force = force_const_prop(interp, f, method)
899,843✔
1040
    if !const_prop_rettype_heuristic(interp, result, si, sv, force)
1,796,178✔
1041
        # N.B. remarks are emitted within `const_prop_rettype_heuristic`
1042
        return nothing
59,338✔
1043
    end
1044
    if !const_prop_argument_heuristic(interp, arginfo, sv)
840,811✔
1045
        add_remark!(interp, sv, "[constprop] Disabled by argument heuristics")
298,281✔
1046
        return nothing
298,281✔
1047
    end
1048
    all_overridden = is_all_overridden(interp, arginfo, sv)
542,224✔
1049
    if !force && !const_prop_function_heuristic(interp, f, arginfo, all_overridden, sv)
542,224✔
1050
        add_remark!(interp, sv, "[constprop] Disabled by function heuristic")
61,868✔
1051
        return nothing
61,868✔
1052
    end
1053
    force |= all_overridden
480,356✔
1054
    mi = specialize_method(match; preexisting=!force)
849,614✔
1055
    if mi === nothing
480,356✔
1056
        add_remark!(interp, sv, "[constprop] Failed to specialize")
×
1057
        return nothing
×
1058
    end
1059
    mi = mi::MethodInstance
480,356✔
1060
    if !force && !const_prop_methodinstance_heuristic(interp, mi, arginfo, sv)
480,356✔
1061
        add_remark!(interp, sv, "[constprop] Disabled by method instance heuristic")
54,642✔
1062
        return nothing
54,642✔
1063
    end
1064
    return mi
425,714✔
1065
end
1066

1067
function const_prop_rettype_heuristic(interp::AbstractInterpreter, result::MethodCallResult,
3,465✔
1068
                                      si::StmtInfo, sv::AbsIntState, force::Bool)
1069
    rt = result.rt
899,828✔
1070
    if rt isa LimitedAccuracy
899,828✔
1071
        # optimizations like inlining are disabled for limited frames,
1072
        # thus there won't be much benefit in constant-prop' here
1073
        # N.B. don't allow forced constprop' for safety (xref #52763)
1074
        add_remark!(interp, sv, "[constprop] Disabled by rettype heuristic (limited accuracy)")
28✔
1075
        return false
28✔
1076
    elseif force
899,800✔
1077
        return true
202,392✔
1078
    elseif call_result_unused(si) && result.edgecycle
697,408✔
1079
        add_remark!(interp, sv, "[constprop] Disabled by rettype heuristic (edgecycle with unused result)")
1,568✔
1080
        return false
1,568✔
1081
    end
1082
    # check if this return type is improvable (i.e. whether it's possible that with more
1083
    # information, we might get a more precise type)
1084
    if isa(rt, Type)
695,840✔
1085
        # could always be improved to `Const`, `PartialStruct` or just a more precise type,
1086
        # unless we're already at `Bottom`
1087
        if rt === Bottom
588,244✔
1088
            add_remark!(interp, sv, "[constprop] Disabled by rettype heuristic (erroneous result)")
9,965✔
1089
            return false
9,965✔
1090
        end
1091
        return true
578,279✔
1092
    elseif isa(rt, PartialStruct) || isa(rt, InterConditional) || isa(rt, InterMustAlias)
188,430✔
1093
        # could be improved to `Const` or a more precise wrapper
1094
        return true
39,165✔
1095
    elseif isa(rt, Const)
68,431✔
1096
        if is_nothrow(result.effects)
68,431✔
1097
            add_remark!(interp, sv, "[constprop] Disabled by rettype heuristic (nothrow const)")
47,777✔
1098
            return false
47,777✔
1099
        end
1100
        # Could still be improved to Bottom (or at least could see the effects improved)
1101
        return true
20,654✔
1102
    else
1103
        add_remark!(interp, sv, "[constprop] Disabled by rettype heuristic (unimprovable result)")
×
1104
        return false
×
1105
    end
1106
end
1107

1108
# determines heuristically whether if constant propagation can be worthwhile
1109
# by checking if any of given `argtypes` is "interesting" enough to be propagated
1110
function const_prop_argument_heuristic(interp::AbstractInterpreter, arginfo::ArgInfo, sv::AbsIntState)
722,119✔
1111
    ๐•ƒแตข = typeinf_lattice(interp)
722,119✔
1112
    argtypes = arginfo.argtypes
722,119✔
1113
    for i in 1:length(argtypes)
922,823✔
1114
        a = argtypes[i]
1,914,851✔
1115
        if has_conditional(๐•ƒแตข, sv) && isa(a, Conditional) && arginfo.fargs !== nothing
1,914,851✔
1116
            is_const_prop_profitable_conditional(a, arginfo.fargs, sv) && return true
7,807✔
1117
        else
1118
            a = widenslotwrapper(a)
1,909,548✔
1119
            has_nontrivial_extended_info(๐•ƒแตข, a) && is_const_prop_profitable_arg(๐•ƒแตข, a) && return true
1,909,548✔
1120
        end
1121
    end
2,683,745✔
1122
    return false
298,281✔
1123
end
1124

1125
function is_const_prop_profitable_conditional(cnd::Conditional, fargs::Vector{Any}, sv::InferenceState)
1126
    slotid = find_constrained_arg(cnd, fargs, sv)
24,195✔
1127
    if slotid !== nothing
7,976✔
1128
        return true
4,960✔
1129
    end
1130
    # as a minor optimization, we just check the result is a constant or not,
1131
    # since both `has_nontrivial_extended_info`/`is_const_prop_profitable_arg` return `true`
1132
    # for `Const(::Bool)`
1133
    return isa(widenconditional(cnd), Const)
3,016✔
1134
end
1135

1136
function find_constrained_arg(cnd::Conditional, fargs::Vector{Any}, sv::InferenceState)
1137
    slot = cnd.slot
8,162✔
1138
    for i in 1:length(fargs)
8,519✔
1139
        arg = ssa_def_slot(fargs[i], sv)
21,860✔
1140
        if isa(arg, SlotNumber) && slot_id(arg) == slot
21,860✔
1141
            return i
5,146✔
1142
        end
1143
    end
30,412✔
1144
    return nothing
3,016✔
1145
end
1146

1147
# checks if all argtypes has additional information other than what `Type` can provide
1148
function is_all_overridden(interp::AbstractInterpreter, (; fargs, argtypes)::ArgInfo, sv::AbsIntState)
542,224✔
1149
    ๐•ƒแตข = typeinf_lattice(interp)
542,224✔
1150
    for i in 1:length(argtypes)
712,312✔
1151
        a = argtypes[i]
1,329,508✔
1152
        if has_conditional(๐•ƒแตข, sv) && isa(a, Conditional) && fargs !== nothing
1,329,508✔
1153
            is_const_prop_profitable_conditional(a, fargs, sv) || return false
2,898✔
1154
        else
1155
            is_forwardable_argtype(๐•ƒแตข, widenslotwrapper(a)) || return false
1,326,835✔
1156
        end
1157
    end
1,806,700✔
1158
    return true
232,132✔
1159
end
1160

1161
function force_const_prop(interp::AbstractInterpreter, @nospecialize(f), method::Method)
899,843✔
1162
    return is_aggressive_constprop(method) ||
899,843✔
1163
           InferenceParams(interp).aggressive_constant_propagation ||
1164
           typename(typeof(f)).constprop_heuristic === Core.FORCE_CONST_PROP
1165
end
1166

1167
function const_prop_function_heuristic(interp::AbstractInterpreter, @nospecialize(f),
340,576✔
1168
    arginfo::ArgInfo, all_overridden::Bool, sv::AbsIntState)
1169
    argtypes = arginfo.argtypes
340,576✔
1170
    heuristic = typename(typeof(f)).constprop_heuristic
340,576✔
1171
    if length(argtypes) > 1
340,576✔
1172
        ๐•ƒแตข = typeinf_lattice(interp)
340,452✔
1173
        if heuristic === Core.ARRAY_INDEX_HEURISTIC
340,452✔
1174
            arrty = argtypes[2]
14,607✔
1175
            # don't propagate constant index into indexing of non-constant array
1176
            if arrty isa Type && arrty <: AbstractArray && !issingletontype(arrty)
14,607✔
1177
                # For static arrays, allow the constprop if we could possibly
1178
                # deduce nothrow as a result.
1179
                still_nothrow = isa(sv, InferenceState) ? is_nothrow(sv.ipo_effects) : false
4,093✔
1180
                if !still_nothrow || ismutabletype(arrty)
5,459✔
1181
                    return false
4,085✔
1182
                end
1183
            elseif โŠ‘(๐•ƒแตข, arrty, Array) || โŠ‘(๐•ƒแตข, arrty, GenericMemory)
21,010✔
1184
                return false
18✔
1185
            end
1186
        elseif heuristic === Core.ITERATE_HEURISTIC
325,845✔
1187
            itrty = argtypes[2]
37,037✔
1188
            if โŠ‘(๐•ƒแตข, itrty, Array) || โŠ‘(๐•ƒแตข, itrty, GenericMemory)
73,889✔
1189
                return false
191✔
1190
            end
1191
        end
1192
    end
1193
    if !all_overridden && heuristic === Core.SAMETYPE_HEURISTIC
336,282✔
1194
        # it is almost useless to inline the op when all the same type,
1195
        # but highly worthwhile to inline promote of a constant
1196
        length(argtypes) > 2 || return false
66,942✔
1197
        t1 = widenconst(argtypes[2])
66,942✔
1198
        for i in 3:length(argtypes)
70,014✔
1199
            at = argtypes[i]
67,258✔
1200
            ty = isvarargtype(at) ? unwraptv(at) : widenconst(at)
134,516✔
1201
            if ty !== t1
67,258✔
1202
                return true
9,368✔
1203
            end
1204
        end
58,206✔
1205
        return false
57,574✔
1206
    end
1207
    return true
269,340✔
1208
end
1209

1210
# This is a heuristic to avoid trying to const prop through complicated functions
1211
# where we would spend a lot of time, but are probably unlikely to get an improved
1212
# result anyway.
1213
function const_prop_methodinstance_heuristic(interp::AbstractInterpreter,
365,835✔
1214
    mi::MethodInstance, arginfo::ArgInfo, sv::AbsIntState)
1215
    method = mi.def::Method
365,835✔
1216
    if method.is_for_opaque_closure
365,835✔
1217
        # Not inlining an opaque closure can be very expensive, so be generous
1218
        # with the const-prop-ability. It is quite possible that we can't infer
1219
        # anything at all without const-propping, so the inlining check below
1220
        # isn't particularly helpful here.
1221
        return true
×
1222
    end
1223
    # now check if the source of this method instance is inlineable, since the extended type
1224
    # information we have here would be discarded if it is not inlined into a callee context
1225
    # (modulo the inferred return type that can be potentially refined)
1226
    if is_declared_inline(method)
704,700✔
1227
        # this method is declared as `@inline` and will be inlined
1228
        return true
66,628✔
1229
    end
1230
    flag = get_curr_ssaflag(sv)
299,207✔
1231
    if is_stmt_inline(flag)
299,207✔
1232
        # force constant propagation for a call that is going to be inlined
1233
        # since the inliner will try to find this constant result
1234
        # if these constant arguments arrive there
1235
        return true
44✔
1236
    elseif is_stmt_noinline(flag)
299,163✔
1237
        # this call won't be inlined, thus this constant-prop' will most likely be unfruitful
1238
        return false
248✔
1239
    else
1240
        # Peek at the inferred result for the method to determine if the optimizer
1241
        # was able to cut it down to something simple (inlineable in particular).
1242
        # If so, there will be a good chance we might be able to const prop
1243
        # all the way through and learn something new.
1244
        code = get(code_cache(interp), mi, nothing)
596,947✔
1245
        if isa(code, CodeInstance)
298,915✔
1246
            inferred = @atomic :monotonic code.inferred
298,032✔
1247
            # TODO propagate a specific `CallInfo` that conveys information about this call
1248
            if src_inlining_policy(interp, mi, inferred, NoCallInfo(), IR_FLAG_NULL)
298,032✔
1249
                return true
222,868✔
1250
            end
1251
        end
1252
    end
1253
    return false # the cache isn't inlineable, so this constant-prop' will most likely be unfruitful
76,047✔
1254
end
1255

1256
function semi_concrete_eval_call(interp::AbstractInterpreter,
429✔
1257
    mi::MethodInstance, result::MethodCallResult, arginfo::ArgInfo, sv::AbsIntState)
1258
    world = frame_world(sv)
429✔
1259
    mi_cache = WorldView(code_cache(interp), world)
429✔
1260
    codeinst = get(mi_cache, mi, nothing)
858✔
1261
    if codeinst !== nothing
429✔
1262
        irsv = IRInterpretationState(interp, codeinst, mi, arginfo.argtypes, world)
429✔
1263
        if irsv !== nothing
429✔
1264
            assign_parentchild!(irsv, sv)
429✔
1265
            rt, (nothrow, noub) = ir_abstract_constant_propagation(interp, irsv)
429✔
1266
            @assert !(rt isa Conditional || rt isa MustAlias) "invalid lattice element returned from irinterp"
429✔
1267
            if !(isa(rt, Type) && hasintersect(rt, Bool))
429✔
1268
                ir = irsv.ir
330✔
1269
                # TODO (#48913) enable double inlining pass when there are any calls
1270
                # that are newly resolved by irinterp
1271
                # state = InliningState(interp)
1272
                # ir = ssa_inlining_pass!(irsv.ir, state, propagate_inbounds(irsv))
1273
                effects = result.effects
330✔
1274
                if nothrow
330✔
1275
                    effects = Effects(effects; nothrow=true)
309✔
1276
                end
1277
                if noub
330✔
1278
                    effects = Effects(effects; noub=ALWAYS_TRUE)
312✔
1279
                end
1280
                exct = refine_exception_type(result.exct, effects)
348✔
1281
                semi_concrete_result = SemiConcreteResult(codeinst, ir, effects, spec_info(irsv))
330✔
1282
                const_edge = nothing # TODO use the edges from irsv?
330✔
1283
                return ConstCallResult(rt, exct, semi_concrete_result, effects, const_edge)
330✔
1284
            end
1285
        end
1286
    end
1287
    return nothing
99✔
1288
end
1289

1290
function const_prop_result(inf_result::InferenceResult)
1291
    @assert isdefined(inf_result, :ci_as_edge) "InferenceResult without ci_as_edge"
383,963✔
1292
    const_prop_result = ConstPropResult(inf_result)
383,963✔
1293
    return ConstCallResult(inf_result.result, inf_result.exc_result, const_prop_result,
383,963✔
1294
                           inf_result.ipo_effects, inf_result.ci_as_edge)
1295
end
1296

1297
# return cached result of constant analysis
1298
return_localcache_result(::AbstractInterpreter, inf_result::InferenceResult, ::AbsIntState) =
206,261✔
1299
    const_prop_result(inf_result)
1300

1301
function compute_forwarded_argtypes(interp::AbstractInterpreter, arginfo::ArgInfo, sv::AbsIntState)
1302
    ๐•ƒแตข = typeinf_lattice(interp)
425,529✔
1303
    return has_conditional(๐•ƒแตข, sv) ? ConditionalSimpleArgtypes(arginfo, sv) : SimpleArgtypes(arginfo.argtypes)
426,692✔
1304
end
1305

1306
function const_prop_call(interp::AbstractInterpreter,
426,692✔
1307
    mi::MethodInstance, result::MethodCallResult, arginfo::ArgInfo, sv::AbsIntState,
1308
    concrete_eval_result::Union{Nothing,ConstCallResult}=nothing)
1309
    inf_cache = get_inference_cache(interp)
426,692✔
1310
    ๐•ƒแตข = typeinf_lattice(interp)
426,692✔
1311
    forwarded_argtypes = compute_forwarded_argtypes(interp, arginfo, sv)
426,692✔
1312
    # use `cache_argtypes` that has been constructed for fresh regular inference if available
1313
    volatile_inf_result = result.volatile_inf_result
426,692✔
1314
    if volatile_inf_result !== nothing
426,692✔
1315
        cache_argtypes = volatile_inf_result.inf_result.argtypes
26,209✔
1316
    else
1317
        cache_argtypes = matching_cache_argtypes(๐•ƒแตข, mi)
400,483✔
1318
    end
1319
    argtypes = matching_cache_argtypes(๐•ƒแตข, mi, forwarded_argtypes, cache_argtypes)
426,692✔
1320
    inf_result = cache_lookup(๐•ƒแตข, mi, argtypes, inf_cache)
426,692✔
1321
    if inf_result !== nothing
426,692✔
1322
        # found the cache for this constant prop'
1323
        if inf_result.result === nothing
206,261✔
1324
            add_remark!(interp, sv, "[constprop] Found cached constant inference in a cycle")
×
1325
            return nothing
×
1326
        end
1327
        @assert inf_result.linfo === mi "MethodInstance for cached inference result does not match"
206,261✔
1328
        return return_localcache_result(interp, inf_result, sv)
206,261✔
1329
    end
1330
    overridden_by_const = falses(length(argtypes))
220,431✔
1331
    for i = 1:length(argtypes)
318,586✔
1332
        if argtypes[i] !== argtype_by_index(cache_argtypes, i)
670,802✔
1333
            overridden_by_const[i] = true
277,302✔
1334
        end
1335
    end
1,121,173✔
1336
    if !any(overridden_by_const)
440,862✔
1337
        add_remark!(interp, sv, "[constprop] Could not handle constant info in matching_cache_argtypes")
42,729✔
1338
        return nothing
42,729✔
1339
    end
1340
    # perform fresh constant prop'
1341
    inf_result = InferenceResult(mi, argtypes, overridden_by_const)
177,702✔
1342
    frame = InferenceState(inf_result, #=cache_mode=#:local, interp) # TODO: this should also be converted to a stackless Future
355,404✔
1343
    if frame === nothing
177,702✔
1344
        add_remark!(interp, sv, "[constprop] Could not retrieve the source")
×
1345
        return nothing # this is probably a bad generated function (unsound), but just ignore it
×
1346
    end
1347
    assign_parentchild!(frame, sv)
177,702✔
1348
    if !typeinf(interp, frame)
177,702✔
1349
        sv.time_caches += frame.time_caches
×
1350
        sv.time_paused += frame.time_paused
×
1351
        add_remark!(interp, sv, "[constprop] Fresh constant inference hit a cycle")
×
1352
        @assert frame.frameid != 0 && frame.cycleid == frame.frameid
×
1353
        callstack = frame.callstack::Vector{AbsIntState}
×
1354
        @assert callstack[end] === frame && length(callstack) == frame.frameid
×
1355
        pop!(callstack)
×
1356
        return nothing
×
1357
    end
1358
    existing_edge = result.edge
177,702✔
1359
    inf_result.ci_as_edge = codeinst_as_edge(interp, frame, existing_edge)
355,334✔
1360
    @assert frame.frameid != 0 && frame.cycleid == frame.frameid
177,702✔
1361
    @assert frame.parentid == sv.frameid
177,702✔
1362
    @assert inf_result.result !== nothing
177,702✔
1363
    # ConditionalSimpleArgtypes is allowed, because the only case in which it modifies
1364
    # the argtypes is when one of the argtypes is a `Conditional`, which case
1365
    # concrete_eval_result will not be available.
1366
    if concrete_eval_result !== nothing && isa(forwarded_argtypes, Union{SimpleArgtypes, ConditionalSimpleArgtypes})
177,702✔
1367
        # override return type and effects with concrete evaluation result if available
1368
        inf_result.result = concrete_eval_result.rt
×
1369
        inf_result.ipo_effects = concrete_eval_result.effects
×
1370
    end
1371
    return const_prop_result(inf_result)
177,702✔
1372
end
1373

1374
# TODO implement MustAlias forwarding
1375

1376
struct ConditionalSimpleArgtypes
1377
    arginfo::ArgInfo
426,692✔
1378
    sv::InferenceState
1379
end
1380

1381
function matching_cache_argtypes(๐•ƒ::AbstractLattice, mi::MethodInstance,
161,444✔
1382
                                 conditional_argtypes::ConditionalSimpleArgtypes,
1383
                                 cache_argtypes::Vector{Any})
1384
    (; arginfo, sv) = conditional_argtypes
161,444✔
1385
    (; fargs, argtypes) = arginfo
161,444✔
1386
    given_argtypes = Vector{Any}(undef, length(argtypes))
161,444✔
1387
    def = mi.def::Method
161,444✔
1388
    nargs = Int(def.nargs)
161,444✔
1389
    for i in 1:length(argtypes)
322,711✔
1390
        argtype = argtypes[i]
485,025✔
1391
        # forward `Conditional` if it conveys a constraint on any other argument
1392
        if isa(argtype, Conditional) && fargs !== nothing
485,025✔
1393
            cnd = argtype
186✔
1394
            slotid = find_constrained_arg(cnd, fargs, sv)
681✔
1395
            if slotid !== nothing
186✔
1396
                # using union-split signature, we may be able to narrow down `Conditional`
1397
                sigt = widenconst(slotid > nargs ? argtypes[slotid] : cache_argtypes[slotid])
186✔
1398
                โŠ“ = meet(๐•ƒ)
186✔
1399
                thentype = cnd.thentype โŠ“ sigt
186✔
1400
                elsetype = cnd.elsetype โŠ“ sigt
186✔
1401
                if thentype === Bottom && elsetype === Bottom
186✔
1402
                    # we accidentally proved this method match is impossible
1403
                    # TODO bail out here immediately rather than just propagating Bottom ?
1404
                    given_argtypes[i] = Bottom
×
1405
                else
1406
                    given_argtypes[i] = Conditional(slotid, thentype, elsetype)
186✔
1407
                end
1408
                continue
186✔
1409
            end
1410
        end
1411
        given_argtypes[i] = widenslotwrapper(argtype)
484,839✔
1412
    end
808,606✔
1413
    return pick_const_args!(๐•ƒ, given_argtypes, cache_argtypes)
161,444✔
1414
end
1415

1416
# This is only for use with `Conditional`.
1417
# In general, usage of this is wrong.
1418
function ssa_def_slot(@nospecialize(arg), sv::InferenceState)
138,263✔
1419
    code = sv.src.code
138,263✔
1420
    init = sv.currpc
138,263✔
1421
    while isa(arg, SSAValue)
221,505✔
1422
        init = arg.id
83,242✔
1423
        arg = code[init]
83,242✔
1424
    end
83,242✔
1425
    if arg isa SlotNumber
138,263✔
1426
        # found this kind of pattern:
1427
        # %init = SlotNumber(x)
1428
        # [...]
1429
        # goto if not isa(%init, T)
1430
        # now conservatively make sure there isn't potentially another conflicting assignment
1431
        # to the same slot between the def and usage
1432
        # we can assume the IR is sorted, since the front-end only creates SSA values in order
1433
        for i = init:(sv.currpc-1)
51,709✔
1434
            e = code[i]
10,823✔
1435
            if isexpr(e, :(=)) && e.args[1] === arg
10,823✔
1436
                return nothing
×
1437
            end
1438
        end
15,994✔
1439
    else
1440
        # there might still be the following kind of pattern (see #45499):
1441
        # %init = ...
1442
        # [...]
1443
        # SlotNumber(x) = %init
1444
        # [...]
1445
        # goto if not isa(%init, T)
1446
        # let's check if there is a slot assigned to the def SSA value but also there isn't
1447
        # any potentially conflicting assignment to the same slot
1448
        arg = nothing
92,206✔
1449
        def = SSAValue(init)
92,206✔
1450
        for i = (init+1):(sv.currpc-1)
104,196✔
1451
            e = code[i]
36,275✔
1452
            if isexpr(e, :(=))
36,275✔
1453
                lhs = e.args[1]
42✔
1454
                if isa(lhs, SlotNumber)
42✔
1455
                    lhs === arg && return nothing
42✔
1456
                    rhs = e.args[2]
42✔
1457
                    if rhs === def
42✔
1458
                        arg = lhs
6✔
1459
                    end
1460
                end
1461
            end
1462
        end
36,275✔
1463
    end
1464
    return arg
138,263✔
1465
end
1466

1467
# No slots in irinterp
1468
ssa_def_slot(@nospecialize(arg), ::IRInterpretationState) = nothing
×
1469

1470
struct AbstractIterationResult
1471
    cti::Vector{Any}
39,893✔
1472
    info::MaybeAbstractIterationInfo
1473
    ai_effects::Effects
1474
end
1475
AbstractIterationResult(cti::Vector{Any}, info::MaybeAbstractIterationInfo) =
39,890✔
1476
    AbstractIterationResult(cti, info, EFFECTS_TOTAL)
1477

1478
# `typ` is the inferred type for expression `arg`.
1479
# if the expression constructs a container (e.g. `svec(x,y,z)`),
1480
# refine its type to an array of element types.
1481
# Union of Tuples of the same length is converted to Tuple of Unions.
1482
# returns an array of types
1483
function precise_container_type(interp::AbstractInterpreter, @nospecialize(itft), @nospecialize(typ),
34,722✔
1484
                                sv::AbsIntState)
1485
    if isa(typ, PartialStruct)
34,722✔
1486
        widet = typ.typ
6,376✔
1487
        if isa(widet, DataType)
6,376✔
1488
            if widet.name === Tuple.name
6,376✔
1489
                return Future(AbstractIterationResult(typ.fields, nothing))
1,576✔
1490
            elseif widet.name === _NAMEDTUPLE_NAME
4,800✔
1491
                return Future(AbstractIterationResult(typ.fields, nothing))
×
1492
            end
1493
        end
1494
    end
1495

1496
    if isa(typ, Const)
33,146✔
1497
        val = typ.val
13,627✔
1498
        if isa(val, SimpleVector) || isa(val, Tuple) || isa(val, NamedTuple)
27,252✔
1499
            return Future(AbstractIterationResult(Any[ Const(val[i]) for i in 1:length(val) ], nothing)) # avoid making a tuple Generator here!
8,824✔
1500
        end
1501
    end
1502

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

1574
# simulate iteration protocol on container type up to fixpoint
1575
function abstract_iteration(interp::AbstractInterpreter, @nospecialize(itft), @nospecialize(itertype), sv::AbsIntState)
9,672✔
1576
    if isa(itft, Const)
9,672✔
1577
        iteratef = itft.val
9,672✔
1578
    else
1579
        return Future(AbstractIterationResult(Any[Vararg{Any}], nothing, Effects()))
×
1580
    end
1581
    @assert !isvarargtype(itertype)
9,672✔
1582

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

1604
        nextstate::UInt8 = 0x0
9,672✔
1605
        function inferiterate_2arg(interp, sv)
34,319✔
1606
            if nextstate === 0x1
14,975✔
1607
                nextstate = 0xff
87✔
1608
                @goto state1
87✔
1609
            elseif nextstate === 0x2
14,888✔
1610
                nextstate = 0xff
45✔
1611
                @goto state2
45✔
1612
            else
1613
                @assert nextstate === 0x0
14,843✔
1614
                nextstate = 0xff
14,843✔
1615
            end
1616

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

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

1741
    applyresult = Future{CallMeta}()
19,544✔
1742
    # split the rest into a resumable state machine
1743
    i::Int = 1
19,544✔
1744
    j::Int = 1
19,544✔
1745
    nextstate::UInt8 = 0x0
19,544✔
1746
    function infercalls(interp, sv)
43,467✔
1747
        # n.b. Remember that variables will lose their values across restarts,
1748
        # so be sure to manually hoist any values that must be preserved and do
1749
        # not rely on program order.
1750
        # This is a little more complex than the closure continuations often used elsewhere, but avoids needing to manage all of that indentation
1751
        if nextstate === 0x1
23,923✔
1752
            nextstate = 0xff
24✔
1753
            @goto state1
24✔
1754
        elseif nextstate === 0x2
23,899✔
1755
            nextstate = 0xff
×
1756
            @goto state2
×
1757
        elseif nextstate === 0x3
23,899✔
1758
            nextstate = 0xff
4,355✔
1759
            @goto state3
4,355✔
1760
        else
1761
            @assert nextstate === 0x0
19,544✔
1762
            nextstate = 0xff
19,544✔
1763
        end
1764
        while i <= length(aargtypes)
54,059✔
1765
            argtypesi = (splitunions ? uniontypes(aargtypes[i]) : Any[aargtypes[i]])
34,613✔
1766
            i += 1
34,515✔
1767
            j = 1
34,515✔
1768
            while j <= length(argtypesi)
69,237✔
1769
                ti = argtypesi[j]
34,722✔
1770
                j += 1
34,722✔
1771
                if !isvarargtype(ti)
34,722✔
1772
                    ctfuture = precise_container_type(interp, itft.contents, ti, sv)::Future
34,722✔
1773
                    if !isready(ctfuture)
44,394✔
1774
                        nextstate = 0x1
24✔
1775
                        return false
24✔
1776
                        @label state1
1777
                    end
1778
                    (;cti, info, ai_effects) = ctfuture[]
44,394✔
1779
                else
1780
                    ctfuture = precise_container_type(interp, itft.contents, unwrapva(ti), sv)::Future
×
1781
                    if !isready(ctfuture)
×
1782
                        nextstate = 0x2
×
1783
                        return false
×
1784
                        @label state2
1785
                    end
1786
                    (;cti, info, ai_effects) = ctfuture[]
×
1787
                    # We can't represent a repeating sequence of the same types,
1788
                    # so tmerge everything together to get one type that represents
1789
                    # everything.
1790
                    argt = cti[end]
×
1791
                    if isvarargtype(argt)
×
1792
                        argt = unwrapva(argt)
×
1793
                    end
1794
                    for k in 1:(length(cti)-1)
×
1795
                        argt = tmerge(argt, cti[k])
×
1796
                    end
×
1797
                    cti = Any[Vararg{argt}]
×
1798
                end
1799
                all_effects = merge_effects(all_effects, ai_effects)
69,444✔
1800
                if info !== nothing
34,722✔
1801
                    for call in info.each
9,672✔
1802
                        all_effects = merge_effects(all_effects, call.effects)
58,014✔
1803
                    end
29,010✔
1804
                end
1805
                if any(@nospecialize(t) -> t === Bottom, cti)
157,716✔
1806
                    continue
×
1807
                end
1808
                for k = 1:length(ctypes)
54,858✔
1809
                    ct = ctypes[k]
34,722✔
1810
                    if isvarargtype(ct[end])
34,722✔
1811
                        # This is vararg, we're not gonna be able to do any inlining,
1812
                        # drop the info
1813
                        info = nothing
15✔
1814
                        tail = tuple_tail_elem(typeinf_lattice(interp), unwrapva(ct[end]), cti)
15✔
1815
                        push!(ctypesยด, push!(ct[1:(end - 1)], tail))
30✔
1816
                    else
1817
                        push!(ctypesยด, append!(ct[:], cti))
34,707✔
1818
                    end
1819
                    push!(infosยด, push!(copy(infos[k]), info))
44,394✔
1820
                end
34,722✔
1821
            end
34,722✔
1822
            # swap for the new array and empty the temporary one
1823
            ctypesยด, ctypes = ctypes, ctypesยด
34,515✔
1824
            infosยด, infos = infos, infosยด
34,515✔
1825
            empty!(ctypesยด)
34,515✔
1826
            empty!(infosยด)
34,515✔
1827
        end
34,515✔
1828
        all_effects.nothrow || (exctype = Any)
19,550✔
1829

1830
        i = 1
19,544✔
1831
        while i <= length(ctypes)
39,209✔
1832
            ct = ctypes[i]
19,711✔
1833
            if bail_out_apply(interp, InferenceLoopState(res, all_effects), sv)
19,711✔
1834
                add_remark!(interp, sv, "_apply_iterate inference reached maximally imprecise information: bailing on analysis of more methods.")
46✔
1835
                # there is unanalyzed candidate, widen type and effects to the top
1836
                let retinfo = NoCallInfo() # NOTE this is necessary to prevent the inlining processing
46✔
1837
                    applyresult[] = CallMeta(Any, Any, Effects(), retinfo)
46✔
1838
                    return true
46✔
1839
                end
1840
            end
1841
            lct = length(ct)
19,665✔
1842
            # truncate argument list at the first Vararg
1843
            for k = 1:lct-1
30,064✔
1844
                cti = ct[k]
61,457✔
1845
                if isvarargtype(cti)
61,457✔
1846
                    ct[k] = tuple_tail_elem(typeinf_lattice(interp), unwrapva(cti), ct[(k+1):lct])
×
1847
                    resize!(ct, k)
×
1848
                    break
×
1849
                end
1850
            end
61,457✔
1851
            callfuture = abstract_call(interp, ArgInfo(nothing, ct), si, sv, max_methods)::Future
19,665✔
1852
            if !isready(callfuture)
37,287✔
1853
                nextstate = 0x3
4,355✔
1854
                return false
4,355✔
1855
                @label state3
1856
            end
1857
            let (; info, rt, exct, effects) = callfuture[]
37,287✔
1858
                push!(retinfos, ApplyCallInfo(info, infos[i]))
19,665✔
1859
                res = tmerge(typeinf_lattice(interp), res, rt)
39,330✔
1860
                exctype = tmerge(typeinf_lattice(interp), exctype, exct)
39,330✔
1861
                all_effects = merge_effects(all_effects, effects)
39,324✔
1862
            end
1863
            i += 1
19,665✔
1864
        end
19,665✔
1865
        # TODO: Add a special info type to capture all the iteration info.
1866
        # For now, only propagate info if we don't also union-split the iteration
1867
        applyresult[] = CallMeta(res, exctype, all_effects, retinfo)
19,498✔
1868
        return true
19,498✔
1869
    end # function infercalls
1870
    # start making progress on the first call
1871
    infercalls(interp, sv) || push!(sv.tasks, infercalls)
23,905✔
1872
    return applyresult
19,544✔
1873
end
1874

1875
function argtype_by_index(argtypes::Vector{Any}, i::Int)
1876
    n = length(argtypes)
1,197,149✔
1877
    na = argtypes[n]
1,197,149✔
1878
    if isvarargtype(na)
1,197,149✔
1879
        return i >= n ? unwrapva(na) : argtypes[i]
12✔
1880
    else
1881
        return i > n ? Bottom : argtypes[i]
1,197,137✔
1882
    end
1883
end
1884

1885
function argtype_tail(argtypes::Vector{Any}, i::Int)
1886
    n = length(argtypes)
19,998✔
1887
    if isvarargtype(argtypes[n]) && i > n
19,998✔
1888
        i = n
×
1889
    end
1890
    return argtypes[i:n]
39,996✔
1891
end
1892

1893
struct ConditionalTypes
1894
    thentype
1895
    elsetype
1896
    ConditionalTypes(thentype, elsetype) = (@nospecialize; new(thentype, elsetype))
23,055✔
1897
end
1898

1899
@inline function isa_condition(@nospecialize(xt), @nospecialize(ty), max_union_splitting::Int,
1900
    @nospecialize(rt))
1901
    if isa(rt, Const)
60,656✔
1902
        xt = widenslotwrapper(xt)
52,807✔
1903
        if rt.val === false
52,161✔
1904
            return ConditionalTypes(Bottom, xt)
8,718✔
1905
        elseif rt.val === true
43,443✔
1906
            return ConditionalTypes(xt, Bottom)
43,443✔
1907
        end
1908
    end
1909
    return isa_condition(xt, ty, max_union_splitting)
8,495✔
1910
end
1911
@inline function isa_condition(@nospecialize(xt), @nospecialize(ty), max_union_splitting::Int)
1912
    tty_ub, isexact_tty = instanceof_tfunc(ty, true)
8,552✔
1913
    tty = widenconst(xt)
8,552✔
1914
    if isexact_tty && !isa(tty_ub, TypeVar)
8,552✔
1915
        tty_lb = tty_ub # TODO: this would be wrong if !isexact_tty, but instanceof_tfunc doesn't preserve this info
1,512✔
1916
        if !has_free_typevars(tty_lb) && !has_free_typevars(tty_ub)
6,417✔
1917
            thentype = typeintersect(tty, tty_ub)
6,417✔
1918
            if iskindtype(tty_ub) && thentype !== Bottom
12,684✔
1919
                # `typeintersect` may be unable narrow down `Type`-type
1920
                thentype = tty_ub
777✔
1921
            end
1922
            valid_as_lattice(thentype, true) || (thentype = Bottom)
6,417✔
1923
            elsetype = typesubtract(tty, tty_lb, max_union_splitting)
6,417✔
1924
            return ConditionalTypes(thentype, elsetype)
6,417✔
1925
        end
1926
    end
1927
    return nothing
2,135✔
1928
end
1929

1930
@inline function egal_condition(c::Const, @nospecialize(xt), max_union_splitting::Int,
1931
    @nospecialize(rt))
1932
    thentype = c
3,458✔
1933
    elsetype = widenslotwrapper(xt)
32,908✔
1934
    if rt === Const(false)
32,757✔
1935
        thentype = Bottom
2,496✔
1936
    elseif rt === Const(true)
24,668✔
1937
        elsetype = Bottom
653✔
1938
    elseif elsetype isa Type && issingletontype(typeof(c.val)) # can only widen a if it is a singleton
23,794✔
1939
        elsetype = typesubtract(elsetype, typeof(c.val), max_union_splitting)
19,142✔
1940
    end
1941
    return ConditionalTypes(thentype, elsetype)
40,846✔
1942
end
1943
@inline function egal_condition(c::Const, @nospecialize(xt), max_union_splitting::Int)
1944
    thentype = c
×
1945
    elsetype = widenslotwrapper(xt)
6✔
1946
    if elsetype isa Type && issingletontype(typeof(c.val)) # can only widen a if it is a singleton
6✔
1947
        elsetype = typesubtract(elsetype, typeof(c.val), max_union_splitting)
×
1948
    end
1949
    return ConditionalTypes(thentype, elsetype)
6✔
1950
end
1951

1952
function abstract_call_builtin(interp::AbstractInterpreter, f::Builtin, (; fargs, argtypes)::ArgInfo,
544,894✔
1953
                               sv::AbsIntState)
1954
    @nospecialize f
544,894✔
1955
    la = length(argtypes)
544,894✔
1956
    ๐•ƒแตข = typeinf_lattice(interp)
544,894✔
1957
    โŠ‘, โŠ, โŠ”, โŠ“ = partialorder(๐•ƒแตข), strictpartialorder(๐•ƒแตข), join(๐•ƒแตข), meet(๐•ƒแตข)
544,894✔
1958
    if has_conditional(๐•ƒแตข, sv) && f === Core.ifelse && fargs isa Vector{Any} && la == 4
544,894✔
1959
        cnd = argtypes[2]
2,458✔
1960
        if isa(cnd, Conditional)
2,458✔
1961
            newcnd = widenconditional(cnd)
864✔
1962
            tx = argtypes[3]
432✔
1963
            ty = argtypes[4]
432✔
1964
            if isa(newcnd, Const)
432✔
1965
                # if `cnd` is constant, we should just respect its constantness to keep inference accuracy
1966
                return newcnd.val::Bool ? tx : ty
×
1967
            else
1968
                # try to simulate this as a real conditional (`cnd ? x : y`), so that the penalty for using `ifelse` instead isn't too high
1969
                a = ssa_def_slot(fargs[3], sv)
432✔
1970
                b = ssa_def_slot(fargs[4], sv)
432✔
1971
                if isa(a, SlotNumber) && cnd.slot == slot_id(a)
432✔
1972
                    tx = (cnd.thentype โŠ‘ tx ? cnd.thentype : tx โŠ“ widenconst(cnd.thentype))
×
1973
                end
1974
                if isa(b, SlotNumber) && cnd.slot == slot_id(b)
432✔
1975
                    ty = (cnd.elsetype โŠ‘ ty ? cnd.elsetype : ty โŠ“ widenconst(cnd.elsetype))
×
1976
                end
1977
                return tx โŠ” ty
432✔
1978
            end
1979
        end
1980
    end
1981
    ft = popfirst!(argtypes)
544,462✔
1982
    rt = builtin_tfunction(interp, f, argtypes, sv)
544,462✔
1983
    pushfirst!(argtypes, ft)
546,944✔
1984
    if has_mustalias(๐•ƒแตข) && f === getfield && isa(fargs, Vector{Any}) && la โ‰ฅ 3
544,462✔
1985
        a3 = argtypes[3]
252✔
1986
        if isa(a3, Const)
252✔
1987
            if rt !== Bottom && !isalreadyconst(rt)
432✔
1988
                var = ssa_def_slot(fargs[2], sv)
210✔
1989
                if isa(var, SlotNumber)
210✔
1990
                    vartyp = widenslotwrapper(argtypes[2])
210✔
1991
                    fldidx = maybe_const_fldidx(vartyp, a3.val)
210✔
1992
                    if fldidx !== nothing
210✔
1993
                        # wrap this aliasable field into `MustAlias` for possible constraint propagations
1994
                        return MustAlias(var, vartyp, fldidx, rt)
195✔
1995
                    end
1996
                end
1997
            end
1998
        end
1999
    elseif has_conditional(๐•ƒแตข, sv) && (rt === Bool || (isa(rt, Const) && isa(rt.val, Bool))) && isa(fargs, Vector{Any})
1,044,097✔
2000
        # perform very limited back-propagation of type information for `is` and `isa`
2001
        if f === isa
139,320✔
2002
            # try splitting value argument, based on types
2003
            a = ssa_def_slot(fargs[2], sv)
64,373✔
2004
            a2 = argtypes[2]
64,373✔
2005
            a3 = argtypes[3]
64,373✔
2006
            if isa(a, SlotNumber)
64,373✔
2007
                cndt = isa_condition(a2, a3, InferenceParams(interp).max_union_splitting, rt)
104,099✔
2008
                if cndt !== nothing
60,656✔
2009
                    return Conditional(a, cndt.thentype, cndt.elsetype)
58,521✔
2010
                end
2011
            end
2012
            if isa(a2, MustAlias)
5,852✔
2013
                if !isa(rt, Const) # skip refinement when the field is known precisely (just optimization)
60✔
2014
                    cndt = isa_condition(a2, a3, InferenceParams(interp).max_union_splitting)
114✔
2015
                    if cndt !== nothing
57✔
2016
                        return form_mustalias_conditional(a2, cndt.thentype, cndt.elsetype)
57✔
2017
                    end
2018
                end
2019
            end
2020
            # try splitting type argument, based on value
2021
            if isdispatchelem(widenconst(a2)) && a3 isa Union && !has_free_typevars(a3) && !isa(rt, Const)
11,590✔
2022
                b = ssa_def_slot(fargs[3], sv)
256✔
2023
                if isa(b, SlotNumber)
256✔
2024
                    # !(x isa T) implies !(Type{a2} <: T)
2025
                    # TODO: complete splitting, based on which portions of the Union a3 for which isa_tfunc returns Const(true) or Const(false) instead of Bool
2026
                    elsetype = typesubtract(a3, Type{widenconst(a2)}, InferenceParams(interp).max_union_splitting)
256✔
2027
                    return Conditional(b, a3, elsetype)
256✔
2028
                end
2029
            end
2030
        elseif f === (===)
74,947✔
2031
            a = ssa_def_slot(fargs[2], sv)
46,648✔
2032
            b = ssa_def_slot(fargs[3], sv)
46,648✔
2033
            aty = argtypes[2]
46,648✔
2034
            bty = argtypes[3]
46,648✔
2035
            # if doing a comparison to a singleton, consider returning a `Conditional` instead
2036
            if isa(aty, Const)
46,648✔
2037
                if isa(b, SlotNumber)
11,181✔
2038
                    cndt = egal_condition(aty, bty, InferenceParams(interp).max_union_splitting, rt)
2,608✔
2039
                    return Conditional(b, cndt.thentype, cndt.elsetype)
1,936✔
2040
                elseif isa(bty, MustAlias) && !isa(rt, Const) # skip refinement when the field is known precisely (just optimization)
9,245✔
2041
                    cndt = egal_condition(aty, bty.fldtyp, InferenceParams(interp).max_union_splitting)
3✔
2042
                    return form_mustalias_conditional(bty, cndt.thentype, cndt.elsetype)
3✔
2043
                end
2044
            elseif isa(bty, Const)
35,467✔
2045
                if isa(a, SlotNumber)
32,100✔
2046
                    cndt = egal_condition(bty, aty, InferenceParams(interp).max_union_splitting, rt)
38,238✔
2047
                    return Conditional(a, cndt.thentype, cndt.elsetype)
30,821✔
2048
                elseif isa(aty, MustAlias) && !isa(rt, Const) # skip refinement when the field is known precisely (just optimization)
1,279✔
2049
                    cndt = egal_condition(bty, aty.fldtyp, InferenceParams(interp).max_union_splitting)
3✔
2050
                    return form_mustalias_conditional(aty, cndt.thentype, cndt.elsetype)
3✔
2051
                end
2052
            end
2053
            # TODO enable multiple constraints propagation here, there are two possible improvements:
2054
            # 1. propagate constraints for both lhs and rhs
2055
            # 2. we can propagate both constraints on aliased fields and slots
2056
            # As for 2, for now, we prioritize constraints on aliased fields, since currently
2057
            # different slots that represent the same object can't share same field constraint,
2058
            # and thus binding `MustAlias` to the other slot is less likely useful
2059
            if !isa(rt, Const) # skip refinement when the field is known precisely (just optimization)
13,885✔
2060
                if isa(bty, MustAlias)
4,253✔
2061
                    thentype = widenslotwrapper(aty)
3✔
2062
                    elsetype = bty.fldtyp
3✔
2063
                    if thentype โŠ elsetype
3✔
2064
                        return form_mustalias_conditional(bty, thentype, elsetype)
3✔
2065
                    end
2066
                elseif isa(aty, MustAlias)
4,250✔
2067
                    thentype = widenslotwrapper(bty)
3✔
2068
                    elsetype = aty.fldtyp
3✔
2069
                    if thentype โŠ elsetype
3✔
2070
                        return form_mustalias_conditional(aty, thentype, elsetype)
3✔
2071
                    end
2072
                end
2073
            end
2074
            # narrow the lattice slightly (noting the dependency on one of the slots), to promote more effective smerge
2075
            if isa(b, SlotNumber)
13,879✔
2076
                thentype = rt === Const(false) ? Bottom : widenslotwrapper(bty)
4,858✔
2077
                elsetype = rt === Const(true)  ? Bottom : widenslotwrapper(bty)
5,230✔
2078
                return Conditional(b, thentype, elsetype)
2,615✔
2079
            elseif isa(a, SlotNumber)
11,264✔
2080
                thentype = rt === Const(false) ? Bottom : widenslotwrapper(aty)
14,320✔
2081
                elsetype = rt === Const(true)  ? Bottom : widenslotwrapper(aty)
13,136✔
2082
                return Conditional(a, thentype, elsetype)
8,974✔
2083
            end
2084
        elseif f === Core.Intrinsics.not_int
28,299✔
2085
            aty = argtypes[2]
6,026✔
2086
            if isa(aty, Conditional)
6,026✔
2087
                thentype = rt === Const(false) ? Bottom : aty.elsetype
11,274✔
2088
                elsetype = rt === Const(true)  ? Bottom : aty.thentype
6,564✔
2089
                return Conditional(aty.slot, thentype, elsetype)
5,946✔
2090
            end
2091
        elseif f === isdefined
22,273✔
2092
            a = ssa_def_slot(fargs[2], sv)
5,842✔
2093
            if isa(a, SlotNumber)
5,842✔
2094
                argtype2 = argtypes[2]
5,638✔
2095
                if isa(argtype2, Union)
5,638✔
2096
                    fld = argtypes[3]
×
2097
                    thentype = Bottom
×
2098
                    elsetype = Bottom
×
2099
                    for ty in uniontypes(argtype2)
×
2100
                        cnd = isdefined_tfunc(๐•ƒแตข, ty, fld)
×
2101
                        if isa(cnd, Const)
×
2102
                            if cnd.val::Bool
×
2103
                                thentype = thentype โŠ” ty
×
2104
                            else
2105
                                elsetype = elsetype โŠ” ty
×
2106
                            end
2107
                        else
2108
                            thentype = thentype โŠ” ty
×
2109
                            elsetype = elsetype โŠ” ty
×
2110
                        end
2111
                    end
×
2112
                    return Conditional(a, thentype, elsetype)
×
2113
                else
2114
                    thentype = form_partially_defined_struct(๐•ƒแตข, argtype2, argtypes[3])
5,638✔
2115
                    if thentype !== nothing
5,638✔
2116
                        elsetype = widenslotwrapper(argtype2)
362✔
2117
                        if rt === Const(false)
362✔
2118
                            thentype = Bottom
×
2119
                        elseif rt === Const(true)
362✔
2120
                            elsetype = Bottom
×
2121
                        end
2122
                        return Conditional(a, thentype, elsetype)
362✔
2123
                    end
2124
                end
2125
            end
2126
        end
2127
    end
2128
    @assert !isa(rt, TypeVar) "unhandled TypeVar"
434,767✔
2129
    return rt
434,767✔
2130
end
2131

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

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

2211
function get_ci_abi(ci::CodeInstance)
2212
    def = ci.def
×
2213
    isa(def, ABIOverride) && return def.abi
×
2214
    (def::MethodInstance).specTypes
×
2215
end
2216

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

2335
function invoke_rewrite(xs::Vector{Any})
2336
    x0 = xs[2]
1,295✔
2337
    newxs = xs[3:end]
2,590✔
2338
    newxs[1] = x0
1,295✔
2339
    return newxs
1,133✔
2340
end
2341

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

2353
function abstract_throw(interp::AbstractInterpreter, argtypes::Vector{Any}, ::AbsIntState)
18✔
2354
    na = length(argtypes)
9,231✔
2355
    โŠ” = join(typeinf_lattice(interp))
9,128✔
2356
    if na == 2
9,231✔
2357
        argtype2 = argtypes[2]
9,222✔
2358
        if isvarargtype(argtype2)
9,222✔
2359
            exct = unwrapva(argtype2) โŠ” ArgumentError
×
2360
        else
2361
            exct = argtype2
9,119✔
2362
        end
2363
    elseif na == 3 && isvarargtype(argtypes[3])
9✔
2364
        exct = argtypes[2] โŠ” ArgumentError
×
2365
    else
2366
        exct = ArgumentError
9✔
2367
    end
2368
    return Future(CallMeta(Union{}, exct, EFFECTS_THROWS, NoCallInfo()))
9,231✔
2369
end
2370

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

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

2402
function merge_exct(cm::CallMeta, @nospecialize(exct))
2403
    if exct !== Bottom
57✔
2404
        cm = CallMeta(cm.rt, Union{cm.exct, exct}, Effects(cm.effects; nothrow=false), cm.info)
×
2405
    end
2406
    return cm
57✔
2407
end
2408

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

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

2431
@nospecs function abstract_eval_get_binding_type(interp::AbstractInterpreter, sv::AbsIntState, M, s)
66✔
2432
    @nospecialize M s
66✔
2433
    โŠ‘ = partialorder(typeinf_lattice(interp))
66✔
2434
    if isa(M, Const) && isa(s, Const)
66✔
2435
        (M, s) = (M.val, s.val)
66✔
2436
        if !isa(M, Module) || !isa(s, Symbol)
132✔
2437
            return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
×
2438
        end
2439
        gr = GlobalRef(M, s)
66✔
2440
        (valid_worlds, rt) = scan_leaf_partitions(interp, gr, sv.world) do interp::AbstractInterpreter, ::Core.Binding, partition::Core.BindingPartition
66✔
2441
            local rt
108✔
2442
            kind = binding_kind(partition)
108✔
2443
            if is_some_guard(kind) || kind == PARTITION_KIND_DECLARED
300✔
2444
                # We do not currently assume an invalidation for guard -> defined transitions
2445
                # rt = Const(nothing)
2446
                rt = Type
42✔
2447
            elseif is_some_const_binding(kind)
132✔
2448
                rt = Const(Any)
×
2449
            else
2450
                rt = Const(partition_restriction(partition))
66✔
2451
            end
2452
            rt
108✔
2453
        end
2454
        update_valid_age!(sv, valid_worlds)
66✔
2455
        return CallMeta(rt, Union{}, EFFECTS_TOTAL, GlobalAccessInfo(convert(Core.Binding, gr)))
66✔
2456
    elseif !hasintersect(widenconst(M), Module) || !hasintersect(widenconst(s), Symbol)
×
2457
        return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
×
2458
    elseif M โŠ‘ Module && s โŠ‘ Symbol
×
2459
        return CallMeta(Type, Union{}, EFFECTS_TOTAL, NoCallInfo())
×
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])
69✔
2466
        if length(argtypes) == 3
69✔
2467
            return abstract_eval_get_binding_type(interp, sv, argtypes[2], argtypes[3])
69✔
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))
84✔
2481
    if isa(M, Const) && isa(s, Const)
84✔
2482
        M, s = M.val, s.val
84✔
2483
        if M isa Module && s isa Symbol
84✔
2484
            gr = GlobalRef(M, s)
84✔
2485
            (rt, exct) = global_assignment_rt_exct(interp, sv, saw_latestworld, gr, v)
168✔
2486
            return CallMeta(rt, exct, Effects(setglobal!_effects, nothrow=exct===Bottom), GlobalAccessInfo(convert(Core.Binding, gr)))
84✔
2487
        end
2488
        return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
×
2489
    end
2490
    โŠ‘ = partialorder(typeinf_lattice(interp))
×
2491
    if !(hasintersect(widenconst(M), Module) && hasintersect(widenconst(s), Symbol))
×
2492
        return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
×
2493
    elseif M โŠ‘ Module && s โŠ‘ Symbol
×
2494
        return CallMeta(v, ErrorException, setglobal!_effects, NoCallInfo())
×
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)
×
2501
    cm = abstract_eval_setglobal!(interp, sv, saw_latestworld, M, s, v)
×
2502
    return merge_exct(cm, goe)
×
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})
78✔
2508
    if !isvarargtype(argtypes[end])
78✔
2509
        if length(argtypes) == 4
78✔
2510
            return abstract_eval_setglobal!(interp, sv, saw_latestworld, argtypes[2], argtypes[3], argtypes[4])
78✔
2511
        elseif length(argtypes) == 5
×
2512
            return abstract_eval_setglobal!(interp, sv, saw_latestworld, argtypes[2], argtypes[3], argtypes[4], argtypes[5])
×
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
                (valid_worlds, (rte, T)) = scan_leaf_partitions(interp, gr, sv.world) do interp::AbstractInterpreter, binding::Core.Binding, partition::Core.BindingPartition
×
2590
                    partition_T = nothing
×
2591
                    partition_rte = abstract_eval_partition_load(interp, binding, partition)
×
2592
                    if binding_kind(partition) == PARTITION_KIND_GLOBAL
×
2593
                        partition_T = partition_restriction(partition)
×
2594
                    end
2595
                    partition_exct = Union{partition_rte.exct, global_assignment_binding_rt_exct(interp, partition, vโ€ฒ[])[2]}
×
2596
                    partition_rte = RTEffects(partition_rte.rt, partition_exct, partition_rte.effects)
×
2597
                    Pair{RTEffects, Any}(partition_rte, partition_T)
×
2598
                end
2599
                update_valid_age!(sv, valid_worlds)
×
2600
                effects = merge_effects(rte.effects, Effects(setglobal!_effects, nothrow=rte.exct===Bottom))
×
2601
                sg = CallMeta(Any, rte.exct, effects, GlobalAccessInfo(convert(Core.Binding, gr)))
×
2602
            else
2603
                sg = abstract_eval_setglobal!(interp, sv, saw_latestworld, M, s, v)
×
2604
            end
2605
            if length(argtypes) >= 6
×
2606
                goe = global_order_exct(argtypes[6], #=loading=#true, #=storing=#true)
×
2607
                sg = merge_exct(sg, goe)
×
2608
            end
2609
            if length(argtypes) == 7
×
2610
                goe = global_order_exct(argtypes[7], #=loading=#true, #=storing=#false)
×
2611
                sg = merge_exct(sg, goe)
×
2612
            end
2613
            rt = T === nothing ?
×
2614
                ccall(:jl_apply_cmpswap_type, Any, (Any,), S) where S :
2615
                ccall(:jl_apply_cmpswap_type, Any, (Any,), T)
2616
            return CallMeta(rt, sg.exct, sg.effects, sg.info)
×
2617
        else
2618
            return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
×
2619
        end
2620
    elseif length(argtypes) > 8
×
2621
        return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
×
2622
    else
2623
        return CallMeta(Any, Union{generic_getglobal_exct,generic_setglobal!_exct}, setglobal!_effects, NoCallInfo())
×
2624
    end
2625
end
2626

2627
function argtypes_are_actually_getglobal(argtypes::Vector{Any})
2628
    length(argtypes) in (3, 4) || return false
132,173✔
2629
    M = argtypes[2]
132,173✔
2630
    s = argtypes[3]
132,173✔
2631
    isa(M, Const) || return false
234,104✔
2632
    isa(s, Const) || return false
31,603✔
2633
    return isa(M.val, Module) && isa(s.val, Symbol)
57,707✔
2634
end
2635

2636
# call where the function is known exactly
2637
function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f),
1,488,322✔
2638
        arginfo::ArgInfo, si::StmtInfo, sv::AbsIntState,
2639
        max_methods::Int = get_max_methods(interp, f, sv))
2640
    (; fargs, argtypes) = arginfo
1,565,258✔
2641
    argtypes::Vector{Any} = arginfo.argtypes  # declare type because the closure below captures `argtypes`
1,488,346✔
2642
    fargs = arginfo.fargs
1,488,346✔
2643
    la = length(argtypes)
1,488,346✔
2644
    ๐•ƒแตข = typeinf_lattice(interp)
1,488,346✔
2645
    if isa(f, Builtin)
1,488,346✔
2646
        if f === _apply_iterate
584,225✔
2647
            return abstract_apply(interp, argtypes, si, sv, max_methods)
19,550✔
2648
        elseif f === invoke
564,675✔
2649
            return abstract_invoke(interp, arginfo, si, sv)
448✔
2650
        elseif f === modifyfield! || f === Core.modifyglobal! ||
1,128,366✔
2651
               f === Core.memoryrefmodify! || f === atomic_pointermodify
2652
            return abstract_modifyop!(interp, f, argtypes, si, sv)
64✔
2653
        elseif f === Core.finalizer
564,163✔
2654
            return abstract_finalizer(interp, argtypes, sv)
27✔
2655
        elseif f === applicable
564,136✔
2656
            return abstract_applicable(interp, argtypes, sv, max_methods)
50✔
2657
        elseif f === throw
564,086✔
2658
            return abstract_throw(interp, argtypes, sv)
9,231✔
2659
        elseif f === Core.throw_methoderror
554,855✔
2660
            return abstract_throw_methoderror(interp, argtypes, sv)
×
2661
        elseif f === Core.getglobal
554,855✔
2662
            return Future(abstract_eval_getglobal(interp, sv, si.saw_latestworld, argtypes))
5,591✔
2663
        elseif f === Core.setglobal!
549,264✔
2664
            return Future(abstract_eval_setglobal!(interp, sv, si.saw_latestworld, argtypes))
81✔
2665
        elseif f === Core.swapglobal!
549,183✔
2666
            return Future(abstract_eval_swapglobal!(interp, sv, si.saw_latestworld, argtypes))
6✔
2667
        elseif f === Core.setglobalonce!
549,177✔
2668
            return Future(abstract_eval_setglobalonce!(interp, sv, si.saw_latestworld, argtypes))
×
2669
        elseif f === Core.replaceglobal!
549,177✔
2670
            return Future(abstract_eval_replaceglobal!(interp, sv, si.saw_latestworld, argtypes))
×
2671
        elseif f === Core.getfield && argtypes_are_actually_getglobal(argtypes)
576,560✔
2672
            return Future(abstract_eval_getglobal(interp, sv, si.saw_latestworld, argtypes))
28✔
2673
        elseif f === Core.isdefined && argtypes_are_actually_getglobal(argtypes)
550,592✔
2674
            return Future(abstract_eval_isdefinedglobal(interp, argtypes[2], argtypes[3], Const(true),
27✔
2675
                length(argtypes) == 4 ? argtypes[4] : Const(:unordered),
2676
                si.saw_latestworld, sv))
2677
        elseif f === Core.isdefinedglobal
549,122✔
2678
            return Future(abstract_eval_isdefinedglobal(interp, sv, si.saw_latestworld, argtypes))
123✔
2679
        elseif f === Core.get_binding_type
548,999✔
2680
            return Future(abstract_eval_get_binding_type(interp, sv, argtypes))
69✔
2681
        end
2682
        rt = abstract_call_builtin(interp, f, arginfo, sv)
548,930✔
2683
        ft = popfirst!(argtypes)
548,930✔
2684
        effects = builtin_effects(๐•ƒแตข, f, argtypes, rt)
548,930✔
2685
        if effects.nothrow
548,930✔
2686
            exct = Union{}
518,906✔
2687
        else
2688
            exct = builtin_exct(๐•ƒแตข, f, argtypes, rt)
30,024✔
2689
        end
2690
        pushfirst!(argtypes, ft)
548,930✔
2691
        refinements = nothing
548,930✔
2692
        if sv isa InferenceState
548,930✔
2693
            if f === typeassert
548,000✔
2694
                # perform very limited back-propagation of invariants after this type assertion
2695
                if rt !== Bottom && isa(fargs, Vector{Any})
24,043✔
2696
                    farg2 = ssa_def_slot(fargs[2], sv)
24,028✔
2697
                    if farg2 isa SlotNumber
24,028✔
2698
                        refinements = SlotRefinement(farg2, rt)
2,851✔
2699
                    end
2700
                end
2701
            elseif f === setfield! && length(argtypes) == 4 && isa(argtypes[3], Const)
523,957✔
2702
                # from there on we know that the struct field will never be undefined,
2703
                # so we try to encode that information with a `PartialStruct`
2704
                if rt !== Bottom && isa(fargs, Vector{Any})
5,824✔
2705
                    farg2 = ssa_def_slot(fargs[2], sv)
5,824✔
2706
                    if farg2 isa SlotNumber
5,824✔
2707
                        refined = form_partially_defined_struct(๐•ƒแตข, argtypes[2], argtypes[3])
5,780✔
2708
                        if refined !== nothing
5,780✔
2709
                            refinements = SlotRefinement(farg2, refined)
298✔
2710
                        end
2711
                    end
2712
                end
2713
            end
2714
        end
2715
        return Future(CallMeta(rt, exct, effects, NoCallInfo(), refinements))
548,930✔
2716
    elseif isa(f, Core.OpaqueClosure)
904,121✔
2717
        # calling an OpaqueClosure about which we have no information returns no information
2718
        return Future(CallMeta(typeof(f).parameters[2], Any, Effects(), NoCallInfo()))
×
2719
    elseif f === TypeVar && !isvarargtype(argtypes[end])
904,121✔
2720
        # Manually look through the definition of TypeVar to
2721
        # make sure to be able to get `PartialTypeVar`s out.
2722
        2 โ‰ค la โ‰ค 4 || return Future(CallMeta(Bottom, Any, EFFECTS_THROWS, NoCallInfo()))
174✔
2723
        # make sure generic code is prepared for inlining if needed later
2724
        let T = Any[Type{TypeVar}, Any, Any, Any]
696✔
2725
            resize!(T, la)
174✔
2726
            atype = Tuple{T...}
174✔
2727
            T[1] = Const(TypeVar)
174✔
2728
            let call = abstract_call_gf_by_type(interp, f, ArgInfo(nothing, T), si, atype, sv, max_methods)::Future
174✔
2729
                return Future{CallMeta}(call, interp, sv) do call, interp, sv
174✔
2730
                    n = argtypes[2]
171✔
2731
                    ub_var = Const(Any)
171✔
2732
                    lb_var = Const(Union{})
171✔
2733
                    if la == 4
171✔
2734
                        ub_var = argtypes[4]
30✔
2735
                        lb_var = argtypes[3]
30✔
2736
                    elseif la == 3
141✔
2737
                        ub_var = argtypes[3]
141✔
2738
                    end
2739
                    pT = typevar_tfunc(๐•ƒแตข, n, lb_var, ub_var)
171✔
2740
                    typevar_argtypes = Any[n, lb_var, ub_var]
513✔
2741
                    effects = builtin_effects(๐•ƒแตข, Core._typevar, typevar_argtypes, pT)
207✔
2742
                    if effects.nothrow
171✔
2743
                        exct = Union{}
135✔
2744
                    else
2745
                        exct = builtin_exct(๐•ƒแตข, Core._typevar, typevar_argtypes, pT)
36✔
2746
                    end
2747
                    return CallMeta(pT, exct, effects, call.info)
171✔
2748
                end
2749
            end
2750
        end
2751
    elseif f === UnionAll
903,947✔
2752
        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
945✔
2753
            return Future{CallMeta}(call, interp, sv) do call, interp, sv
315✔
2754
                return abstract_call_unionall(interp, argtypes, call)
1,715✔
2755
            end
2756
        end
2757
    elseif f === Tuple && la == 2
903,632✔
2758
        aty = argtypes[2]
68✔
2759
        ty = isvarargtype(aty) ? unwrapva(aty) : widenconst(aty)
68✔
2760
        if !isconcretetype(ty)
68✔
2761
            return Future(CallMeta(Tuple, Any, EFFECTS_UNKNOWN, NoCallInfo()))
42✔
2762
        end
2763
    elseif is_return_type(f)
1,806,879✔
2764
        return return_type_tfunc(interp, argtypes, si, sv)
249✔
2765
    elseif la == 3 && f === Core.:(!==)
903,315✔
2766
        # mark !== as exactly a negated call to ===
2767
        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,
6,808✔
2768
            rtfuture = abstract_call_known(interp, (===), arginfo, si, sv, max_methods)::Future
2769
            return Future{CallMeta}(isready(callfuture) && isready(rtfuture), interp, sv) do interp, sv
3,416✔
2770
                local rty = rtfuture[].rt
4,749✔
2771
                if isa(rty, Conditional)
4,749✔
2772
                    return CallMeta(Conditional(rty.slot, rty.elsetype, rty.thentype), Bottom, EFFECTS_TOTAL, NoCallInfo()) # swap if-else
4,379✔
2773
                elseif isa(rty, Const)
370✔
2774
                    return CallMeta(Const(rty.val === false), Bottom, EFFECTS_TOTAL, MethodResultPure())
132✔
2775
                end
2776
                return callfuture[]
238✔
2777
            end
2778
        end
2779
    elseif la == 3 && f === Core.:(>:)
899,899✔
2780
        # mark issupertype as a exact alias for issubtype
2781
        # swap T1 and T2 arguments and call <:
2782
        if fargs !== nothing && length(fargs) == 3
396✔
2783
            fargs = Any[<:, fargs[3], fargs[2]]
1,188✔
2784
        else
2785
            fargs = nothing
×
2786
        end
2787
        argtypes = Any[typeof(<:), argtypes[3], argtypes[2]]
1,188✔
2788
        return abstract_call_known(interp, <:, ArgInfo(fargs, argtypes), si, sv, max_methods)
396✔
2789
    elseif la == 2 && f === Core.typename
899,503✔
2790
        return Future(CallMeta(typename_static(argtypes[2]), Bottom, EFFECTS_TOTAL, MethodResultPure()))
36✔
2791
    elseif f === Core._hasmethod
899,467✔
2792
        return Future(_hasmethod_tfunc(interp, argtypes, sv))
8✔
2793
    end
2794
    atype = argtypes_to_type(argtypes)
899,485✔
2795
    return abstract_call_gf_by_type(interp, f, arginfo, si, atype, sv, max_methods)::Future
899,485✔
2796
end
2797

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

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

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

2891
# call where the function is any lattice element
2892
function abstract_call(interp::AbstractInterpreter, arginfo::ArgInfo, si::StmtInfo,
1,459,625✔
2893
                       sv::AbsIntState, max_methods::Int=typemin(Int))
2894
    ft = widenslotwrapper(arginfo.argtypes[1])
2,898,987✔
2895
    f = singleton_type(ft)
1,463,456✔
2896
    if f === nothing
1,459,490✔
2897
        max_methods = max_methods == typemin(Int) ? get_max_methods(interp, sv) : max_methods
7,787✔
2898
        return abstract_call_unknown(interp, ft, arginfo, si, sv, max_methods)
3,966✔
2899
    end
2900
    max_methods = max_methods == typemin(Int) ? get_max_methods(interp, f, sv) : max_methods
2,885,059✔
2901
    return abstract_call_known(interp, f, arginfo, si, sv, max_methods)
1,455,524✔
2902
end
2903

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

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

2966
function abstract_eval_special_value(interp::AbstractInterpreter, @nospecialize(e), sstate::StatementState, sv::AbsIntState)
6,866,037✔
2967
    if isa(e, SSAValue)
6,866,262✔
2968
        return RTEffects(abstract_eval_ssavalue(e, sv), Union{}, EFFECTS_TOTAL)
3,012,927✔
2969
    elseif isa(e, SlotNumber)
3,853,335✔
2970
        if sstate.vtypes !== nothing
1,497,357✔
2971
            vtyp = sstate.vtypes[slot_id(e)]
1,497,357✔
2972
            if !vtyp.undef
1,497,357✔
2973
                return RTEffects(vtyp.typ, Union{}, EFFECTS_TOTAL)
1,496,745✔
2974
            end
2975
            return RTEffects(vtyp.typ, UndefVarError, EFFECTS_THROWS)
612✔
2976
        end
2977
        return RTEffects(Any, UndefVarError, EFFECTS_THROWS)
×
2978
    elseif isa(e, Argument)
2,355,978✔
2979
        if sstate.vtypes !== nothing
84✔
2980
            return RTEffects(sstate.vtypes[slot_id(e)].typ, Union{}, EFFECTS_TOTAL)
×
2981
        else
2982
            @assert isa(sv, IRInterpretationState)
84✔
2983
            return RTEffects(sv.ir.argtypes[e.n], Union{}, EFFECTS_TOTAL) # TODO frame_argtypes(sv)[e.n] and remove the assertion
84✔
2984
        end
2985
    elseif isa(e, GlobalRef)
2,355,894✔
2986
        # No need for an edge since an explicit GlobalRef will be picked up by the source scan
2987
        return abstract_eval_globalref(interp, e, sstate.saw_latestworld, sv)
1,655,116✔
2988
    end
2989
    if isa(e, QuoteNode)
700,778✔
2990
        e = e.value
143,332✔
2991
    end
2992
    effects = Effects(EFFECTS_TOTAL;
700,778✔
2993
        inaccessiblememonly = is_mutation_free_argtype(typeof(e)) ? ALWAYS_TRUE : ALWAYS_FALSE)
2994
    return RTEffects(Const(e), Union{}, effects)
700,778✔
2995
end
2996

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

3011
function abstract_eval_value(interp::AbstractInterpreter, @nospecialize(e), sstate::StatementState, sv::AbsIntState)
222✔
3012
    if isa(e, Expr)
4,905,551✔
3013
        return abstract_eval_value_expr(interp, e, sv)
18✔
3014
    else
3015
        (;rt, effects) = abstract_eval_special_value(interp, e, sstate, sv)
4,905,533✔
3016
        merge_effects!(interp, sv, effects)
9,239,973✔
3017
        return collect_limitations!(rt, sv)
4,905,533✔
3018
    end
3019
end
3020

3021
function collect_argtypes(interp::AbstractInterpreter, ea::Vector{Any}, sstate::StatementState, sv::AbsIntState)
1,429,811✔
3022
    n = length(ea)
1,430,756✔
3023
    argtypes = Vector{Any}(undef, n)
1,430,756✔
3024
    @inbounds for i = 1:n
1,772,613✔
3025
        ai = abstract_eval_value(interp, ea[i], sstate, sv)
8,446,302✔
3026
        if ai === Bottom
4,224,591✔
3027
            return nothing
×
3028
        end
3029
        argtypes[i] = ai
4,224,591✔
3030
    end
7,018,426✔
3031
    return argtypes
1,430,756✔
3032
end
3033

3034
struct RTEffects
3035
    rt::Any
3036
    exct::Any
3037
    effects::Effects
3038
    refinements # ::Union{Nothing,SlotRefinement,Vector{Any}}
3039
    function RTEffects(rt, exct, effects::Effects, refinements=nothing)
3040
        @nospecialize rt exct refinements
13,276,392✔
3041
        return new(rt, exct, effects, refinements)
25,687,488✔
3042
    end
3043
end
3044

3045
CallMeta(rte::RTEffects, info::CallInfo) =
5,307✔
3046
    CallMeta(rte.rt, rte.exct, rte.effects, info, rte.refinements)
3047

3048
function abstract_call(interp::AbstractInterpreter, arginfo::ArgInfo, sstate::StatementState, sv::InferenceState)
1,438,477✔
3049
    unused = call_result_unused(sv, sv.currpc)
1,438,477✔
3050
    if unused
1,438,477✔
3051
        add_curr_ssaflag!(sv, IR_FLAG_UNUSED)
79,001✔
3052
    end
3053
    si = StmtInfo(!unused, sstate.saw_latestworld)
1,438,477✔
3054
    call = abstract_call(interp, arginfo, si, sv)::Future
1,438,477✔
3055
    Future{Any}(call, interp, sv) do call, _, sv
1,438,477✔
3056
        # this only is needed for the side-effect, sequenced before any task tries to consume the return value,
3057
        # which this will do even without returning this Future
3058
        sv.stmt_info[sv.currpc] = call.info
2,979,188✔
3059
        nothing
2,979,188✔
3060
    end
3061
    return call
1,438,477✔
3062
end
3063

3064
function abstract_eval_call(interp::AbstractInterpreter, e::Expr, sstate::StatementState,
930✔
3065
                            sv::AbsIntState)
3066
    ea = e.args
1,439,407✔
3067
    argtypes = collect_argtypes(interp, ea, sstate, sv)
1,442,233✔
3068
    if argtypes === nothing
1,439,407✔
3069
        return Future(RTEffects(Bottom, Any, Effects()))
×
3070
    end
3071
    arginfo = ArgInfo(ea, argtypes)
1,439,407✔
3072
    call = abstract_call(interp, arginfo, sstate, sv)::Future
1,439,407✔
3073
    return Future{RTEffects}(call, interp, sv) do call, _, _
1,439,407✔
3074
        (; rt, exct, effects, refinements) = call
4,199,530✔
3075
        return RTEffects(rt, exct, effects, refinements)
4,199,530✔
3076
    end
3077
end
3078

3079
function abstract_eval_new(interp::AbstractInterpreter, e::Expr, sstate::StatementState,
22,625✔
3080
                           sv::AbsIntState)
3081
    ๐•ƒแตข = typeinf_lattice(interp)
22,625✔
3082
    rt, _... = instanceof_tfunc(abstract_eval_value(interp, e.args[1], sstate, sv), true)
45,250✔
3083
    ut = unwrap_unionall(rt)
22,625✔
3084
    exct = Union{ErrorException,TypeError}
22,625✔
3085
    if isa(ut, DataType) && !isabstracttype(ut)
22,625✔
3086
        ismutable = ismutabletype(ut)
22,607✔
3087
        fcount = datatype_fieldcount(ut)
22,607✔
3088
        nargs = length(e.args) - 1
22,607✔
3089
        has_any_uninitialized = (fcount === nothing || (fcount > nargs && (let t = rt
45,214✔
3090
                any(i::Int -> !is_undefref_fieldtype(fieldtype(t, i)), (nargs+1):fcount)
22,833✔
3091
            end)))
3092
        if has_any_uninitialized
22,607✔
3093
            # allocation with undefined field is inconsistent always
3094
            consistent = ALWAYS_FALSE
44✔
3095
        elseif ismutable
22,563✔
3096
            # mutable allocation isn't `:consistent`, but we still have a chance that
3097
            # return type information later refines the `:consistent`-cy of the method
3098
            consistent = CONSISTENT_IF_NOTRETURNED
4,512✔
3099
        else
3100
            consistent = ALWAYS_TRUE # immutable allocation is consistent
18,051✔
3101
        end
3102
        if isconcretedispatch(rt)
44,814✔
3103
            nothrow = true
22,207✔
3104
            @assert fcount !== nothing && fcount โ‰ฅ nargs "malformed :new expression" # syntactically enforced by the front-end
22,207✔
3105
            ats = Vector{Any}(undef, nargs)
22,207✔
3106
            local anyrefine = false
22,207✔
3107
            local allconst = true
22,207✔
3108
            for i = 1:nargs
34,648✔
3109
                at = widenslotwrapper(abstract_eval_value(interp, e.args[i+1], sstate, sv))
44,304✔
3110
                ft = fieldtype(rt, i)
44,033✔
3111
                nothrow && (nothrow = โŠ‘(๐•ƒแตข, at, ft))
44,033✔
3112
                at = tmeet(๐•ƒแตข, at, ft)
44,033✔
3113
                at === Bottom && return RTEffects(Bottom, TypeError, EFFECTS_THROWS)
44,033✔
3114
                if ismutable && !isconst(rt, i)
48,209✔
3115
                    ats[i] = ft # can't constrain this field (as it may be modified later)
8,549✔
3116
                    continue
8,549✔
3117
                end
3118
                allconst &= isa(at, Const)
35,484✔
3119
                if !anyrefine
35,484✔
3120
                    anyrefine = has_nontrivial_extended_info(๐•ƒแตข, at) || # extended lattice information
36,403✔
3121
                                โ‹ค(๐•ƒแตข, at, ft) # just a type-level information, but more precise than the declared type
3122
                end
3123
                ats[i] = at
35,484✔
3124
            end
66,891✔
3125
            if fcount == nargs && consistent === ALWAYS_TRUE && allconst
22,207✔
3126
                argvals = Vector{Any}(undef, nargs)
9,133✔
3127
                for j in 1:nargs
15,969✔
3128
                    argvals[j] = (ats[j]::Const).val
15,201✔
3129
                end
22,232✔
3130
                rt = Const(ccall(:jl_new_structv, Any, (Any, Ptr{Cvoid}, UInt32), rt, argvals, nargs))
9,133✔
3131
            elseif anyrefine || nargs > datatype_min_ninitialized(rt)
20,068✔
3132
                # propagate partially initialized struct as `PartialStruct` when:
3133
                # - any refinement information is available (`anyrefine`), or when
3134
                # - `nargs` is greater than `n_initialized` derived from the struct type
3135
                #   information alone
3136
                undefs = Union{Nothing,Bool}[false for _ in 1:nargs]
13,617✔
3137
                if nargs < fcount # fill in uninitialized fields
6,283✔
3138
                    for i = (nargs+1):fcount
12✔
3139
                        ft = fieldtype(rt, i)
6✔
3140
                        push!(ats, ft)
6✔
3141
                        if ft === Union{} # `Union{}`-typed field is never initialized
6✔
3142
                            push!(undefs, true)
×
3143
                        elseif isconcretetype(ft) && datatype_pointerfree(ft) # this check is probably incomplete
6✔
3144
                            push!(undefs, false)
×
3145
                        # TODO If we can implement the query such that it accurately
3146
                        #      identifies fields that never be `#undef'd, we can make the
3147
                        #      following improvements:
3148
                        # elseif is_field_pointerfree(rt, i)
3149
                        #     push!(undefs, false)
3150
                        # elseif ismutable && !isconst(rt, i) # can't constrain this field (as it may be modified later)
3151
                        #     push!(undefs, nothing)
3152
                        # else
3153
                        #     push!(undefs, true)
3154
                        else
3155
                            push!(undefs, nothing)
6✔
3156
                        end
3157
                    end
6✔
3158
                end
3159
                rt = PartialStruct(๐•ƒแตข, rt, undefs, ats)
6,283✔
3160
            end
3161
        else
3162
            rt = refine_partial_type(rt)
800✔
3163
            nothrow = false
400✔
3164
        end
3165
    else
3166
        consistent = ALWAYS_FALSE
18✔
3167
        nothrow = false
18✔
3168
    end
3169
    nothrow && (exct = Union{})
22,625✔
3170
    effects = Effects(EFFECTS_TOTAL; consistent, nothrow)
22,625✔
3171
    return RTEffects(rt, exct, effects)
22,625✔
3172
end
3173

3174
function abstract_eval_splatnew(interp::AbstractInterpreter, e::Expr, sstate::StatementState,
2,145✔
3175
                                sv::AbsIntState)
3176
    ๐•ƒแตข = typeinf_lattice(interp)
2,145✔
3177
    rt, isexact = instanceof_tfunc(abstract_eval_value(interp, e.args[1], sstate, sv), true)
4,290✔
3178
    nothrow = false
2,145✔
3179
    if length(e.args) == 2 && isconcretedispatch(rt) && !ismutabletype(rt)
4,178✔
3180
        at = abstract_eval_value(interp, e.args[2], sstate, sv)
4,066✔
3181
        n = fieldcount(rt)
2,033✔
3182
        if (isa(at, Const) && isa(at.val, Tuple) && n == length(at.val::Tuple) &&
2,033✔
3183
            (let t = rt, at = at
3184
                all(i::Int -> getfield(at.val::Tuple, i) isa fieldtype(t, i), 1:n)
2,428✔
3185
            end))
3186
            nothrow = isexact
1,065✔
3187
            rt = Const(ccall(:jl_new_structt, Any, (Any, Any), rt, at.val))
1,065✔
3188
        elseif at isa PartialStruct
968✔
3189
            if โŠ‘(๐•ƒแตข, at, Tuple) && n > 0
133✔
3190
                fields = at.fields
133✔
3191
                if (n == length(fields) && !isvarargtype(fields[end]) &&
133✔
3192
                    (let t = rt
3193
                        all(i::Int -> โŠ‘(๐•ƒแตข, fields[i], fieldtype(t, i)), 1:n)
555✔
3194
                    end))
3195
                    nothrow = isexact
133✔
3196
                    undefs = Union{Nothing,Bool}[false for _ in 1:n]
422✔
3197
                    rt = PartialStruct(๐•ƒแตข, rt, undefs, fields)
133✔
3198
                end
3199
            end
3200
        end
3201
    else
3202
        rt = refine_partial_type(rt)
112✔
3203
    end
3204
    consistent = !ismutabletype(rt) ? ALWAYS_TRUE : CONSISTENT_IF_NOTRETURNED
3,343✔
3205
    effects = Effects(EFFECTS_TOTAL; consistent, nothrow)
2,145✔
3206
    return RTEffects(rt, Any, effects)
2,145✔
3207
end
3208

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

3245
function abstract_eval_copyast(interp::AbstractInterpreter, e::Expr, sstate::StatementState,
3246
                               sv::AbsIntState)
3247
    effects = EFFECTS_UNKNOWN
51✔
3248
    rt = abstract_eval_value(interp, e.args[1], sstate, sv)
102✔
3249
    if rt isa Const && rt.val isa Expr
51✔
3250
        # `copyast` makes copies of Exprs
3251
        rt = Expr
51✔
3252
    end
3253
    return RTEffects(rt, Any, effects)
51✔
3254
end
3255

3256
function abstract_eval_isdefined_expr(::AbstractInterpreter, e::Expr, sstate::StatementState,
×
3257
                                      sv::AbsIntState)
3258
    sym = e.args[1]
1,988✔
3259
    if isa(sym, SlotNumber) && sstate.vtypes !== nothing
1,988✔
3260
        vtyp = sstate.vtypes[slot_id(sym)]
1,638✔
3261
        if vtyp.typ === Bottom
1,638✔
3262
            rt = Const(false) # never assigned previously
14✔
3263
        elseif !vtyp.undef
1,624✔
3264
            rt = Const(true) # definitely assigned previously
596✔
3265
        else # form `Conditional` to refine `vtyp.undef` in the then branch
3266
            rt = Conditional(sym, widenslotwrapper(vtyp.typ), widenslotwrapper(vtyp.typ); isdefined=true)
1,028✔
3267
        end
3268
        return RTEffects(rt, Union{}, EFFECTS_TOTAL)
2,248✔
3269
    end
3270
    rt = Bool
344✔
3271
    effects = EFFECTS_TOTAL
344✔
3272
    exct = Union{}
344✔
3273
    if isexpr(sym, :static_parameter)
350✔
3274
        n = sym.args[1]::Int
350✔
3275
        if 1 <= n <= length(sv.sptypes)
350✔
3276
            sp = sv.sptypes[n]
350✔
3277
            if !sp.undef
350✔
3278
                rt = Const(true)
314✔
3279
            elseif sp.typ === Bottom
30✔
3280
                rt = Const(false)
×
3281
            end
3282
        end
3283
    else
3284
        effects = EFFECTS_UNKNOWN
×
3285
        exct = Any
×
3286
    end
3287
    return RTEffects(rt, exct, effects)
350✔
3288
end
3289

3290
const generic_isdefinedglobal_effects = Effects(EFFECTS_TOTAL, consistent=ALWAYS_FALSE, nothrow=false)
3291
function abstract_eval_isdefinedglobal(interp::AbstractInterpreter, mod::Module, sym::Symbol, allow_import::Union{Bool, Nothing}, saw_latestworld::Bool, sv::AbsIntState)
57✔
3292
    rt = Bool
57✔
3293
    if saw_latestworld
57✔
3294
        return CallMeta(RTEffects(rt, Union{}, Effects(generic_isdefinedglobal_effects, nothrow=true)), NoCallInfo())
×
3295
    end
3296

3297
    effects = EFFECTS_TOTAL
57✔
3298
    gr = GlobalRef(mod, sym)
57✔
3299
    if allow_import !== true
57✔
3300
        gr = GlobalRef(mod, sym)
×
3301
        partition = lookup_binding_partition!(interp, gr, sv)
×
3302
        if allow_import !== true && is_some_binding_imported(binding_kind(partition))
×
3303
            if allow_import === false
×
3304
                rt = Const(false)
×
3305
            else
3306
                effects = Effects(generic_isdefinedglobal_effects, nothrow=true)
×
3307
            end
3308
            @goto done
×
3309
        end
3310
    end
3311

3312
    (_, rte) = abstract_load_all_consistent_leaf_partitions(interp, gr, sv.world)
57✔
3313
    if rte.exct == Union{}
57✔
3314
        rt = Const(true)
33✔
3315
    elseif rte.rt === Union{} && rte.exct === UndefVarError
24✔
3316
        rt = Const(false)
×
3317
    else
3318
        effects = Effects(generic_isdefinedglobal_effects, nothrow=true)
24✔
3319
    end
3320
@label done
3321
    return CallMeta(RTEffects(rt, Union{}, effects), GlobalAccessInfo(convert(Core.Binding, gr)))
57✔
3322
end
3323

3324
function abstract_eval_isdefinedglobal(interp::AbstractInterpreter, @nospecialize(M), @nospecialize(s), @nospecialize(allow_import_arg), @nospecialize(order_arg), saw_latestworld::Bool, sv::AbsIntState)
150✔
3325
    exct = Bottom
150✔
3326
    allow_import = true
150✔
3327
    if allow_import_arg !== nothing
150✔
3328
        if !isa(allow_import_arg, Const)
150✔
3329
            allow_import = nothing
×
3330
            if widenconst(allow_import_arg) != Bool
×
3331
                exct = Union{exct, TypeError}
×
3332
            end
3333
        else
3334
            allow_import = allow_import_arg.val
150✔
3335
        end
3336
    end
3337
    if order_arg !== nothing
150✔
3338
        exct = global_order_exct(order_arg, #=loading=#true, #=storing=#false)
150✔
3339
        if !(isa(order_arg, Const) && get_atomic_order(order_arg.val, #=loading=#true, #=storing=#false).x >= MEMORY_ORDER_UNORDERED.x)
300✔
3340
            exct = Union{exct, ConcurrencyViolationError}
×
3341
        end
3342
    end
3343
    โŠ‘ = partialorder(typeinf_lattice(interp))
150✔
3344
    if M isa Const && s isa Const
150✔
3345
        M, s = M.val, s.val
57✔
3346
        if M isa Module && s isa Symbol
57✔
3347
            return merge_exct(abstract_eval_isdefinedglobal(interp, M, s, allow_import, saw_latestworld, sv), exct)
57✔
3348
        end
3349
        return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
×
3350
    elseif !hasintersect(widenconst(M), Module) || !hasintersect(widenconst(s), Symbol)
186✔
3351
        return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
×
3352
    elseif M โŠ‘ Module && s โŠ‘ Symbol
93✔
3353
        return CallMeta(Bool, Union{exct, UndefVarError}, generic_isdefinedglobal_effects, NoCallInfo())
93✔
3354
    end
3355
    return CallMeta(Bool, Union{exct, TypeError, UndefVarError}, generic_isdefinedglobal_effects, NoCallInfo())
×
3356
end
3357

3358
function abstract_eval_isdefinedglobal(interp::AbstractInterpreter, sv::AbsIntState, saw_latestworld::Bool, argtypes::Vector{Any})
3359
    if !isvarargtype(argtypes[end])
123✔
3360
        if 3 <= length(argtypes) <= 5
123✔
3361
            return abstract_eval_isdefinedglobal(interp, argtypes[2], argtypes[3],
123✔
3362
                length(argtypes) >= 4 ? argtypes[4] : Const(true),
3363
                length(argtypes) >= 5 ? argtypes[5] : Const(:unordered),
3364
                saw_latestworld, sv)
3365
        else
3366
            return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
×
3367
        end
3368
    elseif length(argtypes) > 6
×
3369
        return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
×
3370
    else
3371
        return CallMeta(Bool, Union{ConcurrencyViolationError, TypeError, UndefVarError}, generic_isdefinedglobal_effects, NoCallInfo())
×
3372
    end
3373
end
3374

3375
function abstract_eval_throw_undef_if_not(interp::AbstractInterpreter, e::Expr, sstate::StatementState, sv::AbsIntState)
×
3376
    condt = abstract_eval_value(interp, e.args[2], sstate, sv)
×
3377
    condval = maybe_extract_const_bool(condt)
×
3378
    rt = Nothing
×
3379
    exct = UndefVarError
×
3380
    effects = EFFECTS_THROWS
×
3381
    if condval isa Bool
×
3382
        if condval
×
3383
            effects = EFFECTS_TOTAL
×
3384
            exct = Union{}
×
3385
        else
3386
            rt = Union{}
×
3387
        end
3388
    elseif !hasintersect(widenconst(condt), Bool)
×
3389
        rt = Union{}
×
3390
    end
3391
    return RTEffects(rt, exct, effects)
×
3392
end
3393

3394
function abstract_eval_the_exception(::AbstractInterpreter, sv::InferenceState)
3395
    (;handler_info) = sv
1,162✔
3396
    if handler_info === nothing
1,162✔
3397
        return the_exception_info(Any)
×
3398
    end
3399
    (;handlers, handler_at) = handler_info
1,162✔
3400
    handler_id = handler_at[sv.currpc][2]
1,162✔
3401
    if handler_id === 0
1,162✔
3402
        return the_exception_info(Any)
×
3403
    end
3404
    return the_exception_info(handlers[handler_id].exct)
1,162✔
3405
end
3406
abstract_eval_the_exception(::AbstractInterpreter, ::IRInterpretationState) = the_exception_info(Any)
×
3407
the_exception_info(@nospecialize t) = RTEffects(t, Union{}, Effects(EFFECTS_TOTAL; consistent=ALWAYS_FALSE))
1,162✔
3408

3409
function abstract_eval_static_parameter(::AbstractInterpreter, e::Expr, sv::AbsIntState)
3410
    n = e.args[1]::Int
96,603✔
3411
    nothrow = false
96,234✔
3412
    if 1 <= n <= length(sv.sptypes)
96,603✔
3413
        sp = sv.sptypes[n]
96,603✔
3414
        rt = sp.typ
96,603✔
3415
        nothrow = !sp.undef
96,603✔
3416
    else
3417
        rt = Any
×
3418
    end
3419
    exct = nothrow ? Union{} : UndefVarError
96,603✔
3420
    effects = Effects(EFFECTS_TOTAL; nothrow)
96,603✔
3421
    return RTEffects(rt, exct, effects)
97,289✔
3422
end
3423

3424
function abstract_eval_statement_expr(interp::AbstractInterpreter, e::Expr, sstate::StatementState,
1,581,227✔
3425
                                      sv::AbsIntState)::Future{RTEffects}
3426
    ehead = e.head
1,581,227✔
3427
    if ehead === :call
1,581,227✔
3428
        return abstract_eval_call(interp, e, sstate, sv)
1,439,407✔
3429
    elseif ehead === :new
141,820✔
3430
        return abstract_eval_new(interp, e, sstate, sv)
22,795✔
3431
    elseif ehead === :splatnew
119,025✔
3432
        return abstract_eval_splatnew(interp, e, sstate, sv)
2,145✔
3433
    elseif ehead === :new_opaque_closure
116,880✔
3434
        return abstract_eval_new_opaque_closure(interp, e, sstate, sv)
3✔
3435
    elseif ehead === :foreigncall
116,877✔
3436
        return abstract_eval_foreigncall(interp, e, sstate, sv)
4,560✔
3437
    elseif ehead === :cfunction
112,317✔
3438
        return abstract_eval_cfunction(interp, e, sstate, sv)
90✔
3439
    elseif ehead === :method
112,227✔
3440
        rt = (length(e.args) == 1) ? Any : Method
×
3441
        return RTEffects(rt, Any, EFFECTS_UNKNOWN)
×
3442
    elseif ehead === :copyast
112,227✔
3443
        return abstract_eval_copyast(interp, e, sstate, sv)
51✔
3444
    elseif ehead === :invoke || ehead === :invoke_modify
224,352✔
3445
        error("type inference data-flow error: tried to double infer a function")
×
3446
    elseif ehead === :isdefined
112,176✔
3447
        return abstract_eval_isdefined_expr(interp, e, sstate, sv)
1,988✔
3448
    elseif ehead === :throw_undef_if_not
110,188✔
3449
        return abstract_eval_throw_undef_if_not(interp, e, sstate, sv)
×
3450
    elseif ehead === :boundscheck
110,188✔
3451
        return RTEffects(Bool, Union{}, Effects(EFFECTS_TOTAL; consistent=ALWAYS_FALSE))
8,678✔
3452
    elseif ehead === :the_exception
101,510✔
3453
        return abstract_eval_the_exception(interp, sv)
1,162✔
3454
    elseif ehead === :static_parameter
100,348✔
3455
        return abstract_eval_static_parameter(interp, e, sv)
96,603✔
3456
    elseif ehead === :gc_preserve_begin || ehead === :aliasscope
6,207✔
3457
        return RTEffects(Any, Union{}, Effects(EFFECTS_TOTAL; consistent=ALWAYS_FALSE, effect_free=EFFECT_FREE_GLOBALLY))
1,286✔
3458
    elseif ehead === :gc_preserve_end || ehead === :leave || ehead === :pop_exception || ehead === :popaliasscope
3,637✔
3459
        return RTEffects(Nothing, Union{}, Effects(EFFECTS_TOTAL; effect_free=EFFECT_FREE_GLOBALLY))
2,453✔
3460
    elseif ehead === :thunk
6✔
3461
        return RTEffects(Any, Any, Effects())
6✔
3462
    end
3463
    # N.B.: abstract_eval_value_expr can modify the global effects, but
3464
    # we move out any arguments with effects during SSA construction later
3465
    # and recompute the effects.
3466
    rt = abstract_eval_value_expr(interp, e, sv)
×
3467
    return RTEffects(rt, Any, EFFECTS_TOTAL)
×
3468
end
3469

3470
# refine the result of instantiation of partially-known type `t` if some invariant can be assumed
3471
function refine_partial_type(@nospecialize t)
3472
    tโ€ฒ = unwrap_unionall(t)
1,186✔
3473
    if isa(tโ€ฒ, DataType) && tโ€ฒ.name === _NAMEDTUPLE_NAME && length(tโ€ฒ.parameters) == 2 &&
624✔
3474
        (tโ€ฒ.parameters[1] === () || tโ€ฒ.parameters[2] === Tuple{})
3475
        # if the first/second parameter of `NamedTuple` is known to be empty,
3476
        # the second/first argument should also be empty tuple type,
3477
        # so refine it here
3478
        return Const((;))
×
3479
    end
3480
    return t
512✔
3481
end
3482

3483
abstract_eval_nonlinearized_foreigncall_name(
×
3484
        ::AbstractInterpreter, @nospecialize(e), ::StatementState, ::IRInterpretationState
3485
    ) = nothing
×
3486

3487
function abstract_eval_nonlinearized_foreigncall_name(
1,116✔
3488
        interp::AbstractInterpreter, @nospecialize(e), sstate::StatementState, sv::InferenceState
3489
    )
3490
    if isexpr(e, :call)
1,116✔
3491
        n = length(e.args)
×
3492
        argtypes = Vector{Any}(undef, n)
×
3493
        callresult = Future{CallMeta}()
×
3494
        i::Int = 1
×
3495
        nextstate::UInt8 = 0x0
×
3496
        local ai, res
3497
        function evalargs(interp, sv)
×
3498
            if nextstate === 0x1
×
3499
                @goto state1
×
3500
            elseif nextstate === 0x2
×
3501
                @goto state2
×
3502
            end
3503
            while i <= n
×
3504
                ai = abstract_eval_nonlinearized_foreigncall_name(interp, e.args[i], sstate, sv)
×
3505
                if !isready(ai)
×
3506
                    nextstate = 0x1
×
3507
                    return false
×
3508
                    @label state1
3509
                end
3510
                argtypes[i] = ai[].rt
×
3511
                i += 1
×
3512
            end
×
3513
            res = abstract_call(interp, ArgInfo(e.args, argtypes), sstate, sv)
×
3514
            if !isready(res)
×
3515
                nextstate = 0x2
×
3516
                return false
×
3517
                @label state2
3518
            end
3519
            callresult[] = res[]
×
3520
            return true
×
3521
        end
3522
        evalargs(interp, sv) || push!(sv.tasks, evalargs)
×
3523
        return callresult
×
3524
    else
3525
        return Future(abstract_eval_basic_statement(interp, e, sstate, sv))
1,116✔
3526
    end
3527
end
3528

3529
function abstract_eval_foreigncall(interp::AbstractInterpreter, e::Expr, sstate::StatementState, sv::AbsIntState)
4,557✔
3530
    callee = e.args[1]
4,557✔
3531
    if isexpr(callee, :call) && length(callee.args) > 1 && callee.args[1] == GlobalRef(Core, :tuple)
4,557✔
3532
        # NOTE these expressions are not properly linearized
3533
        abstract_eval_nonlinearized_foreigncall_name(interp, callee.args[2], sstate, sv)
558✔
3534
        if length(callee.args) > 2
558✔
3535
            abstract_eval_nonlinearized_foreigncall_name(interp, callee.args[3], sstate, sv)
558✔
3536
        end
3537
    else
3538
        abstract_eval_value(interp, callee, sstate, sv)
3,999✔
3539
    end
3540
    mi = frame_instance(sv)
4,557✔
3541
    t = sp_type_rewrap(e.args[2], mi, true)
4,557✔
3542
    for i = 3:length(e.args)
5,138✔
3543
        if abstract_eval_value(interp, e.args[i], sstate, sv) === Bottom
55,968✔
3544
            return RTEffects(Bottom, Any, EFFECTS_THROWS)
×
3545
        end
3546
    end
51,411✔
3547
    effects = foreigncall_effects(e) do @nospecialize x
4,557✔
3548
        abstract_eval_value(interp, x, sstate, sv)
3549
    end
3550
    cconv = e.args[5]
4,557✔
3551
    if isa(cconv, QuoteNode) && (v = cconv.value; isa(v, Tuple{Symbol, UInt16, Bool}))
4,557✔
3552
        override = decode_effects_override(v[2])
149✔
3553
        effects = override_effects(effects, override)
176✔
3554
    end
3555
    return RTEffects(t, Any, effects)
4,557✔
3556
end
3557

3558
function abstract_eval_phi(interp::AbstractInterpreter, phi::PhiNode, sstate::StatementState, sv::AbsIntState)
3✔
3559
    rt = Union{}
3✔
3560
    for i in 1:length(phi.values)
3✔
3561
        isassigned(phi.values, i) || continue
3✔
3562
        val = phi.values[i]
3✔
3563
        # N.B.: Phi arguments are restricted to not have effects, so we can drop
3564
        # them here safely.
3565
        thisval = abstract_eval_special_value(interp, val, sstate, sv).rt
3✔
3566
        rt = tmerge(typeinf_lattice(interp), rt, thisval)
6✔
3567
    end
3✔
3568
    return rt
3✔
3569
end
3570

3571
function stmt_taints_inbounds_consistency(sv::AbsIntState)
×
3572
    propagate_inbounds(sv) && return true
×
3573
    return has_curr_ssaflag(sv, IR_FLAG_INBOUNDS)
×
3574
end
3575

3576
function merge_override_effects!(interp::AbstractInterpreter, effects::Effects, sv::InferenceState)
3577
    # N.B.: This only applies to the effects of the statement itself.
3578
    # It is possible for arguments (GlobalRef/:static_parameter) to throw,
3579
    # but these will be recomputed during SSA construction later.
3580
    override = decode_statement_effects_override(sv)
3,555,657✔
3581
    effects = override_effects(effects, override)
7,111,314✔
3582
    set_curr_ssaflag!(sv, flags_for_effects(effects), IR_FLAGS_EFFECTS)
3,555,657✔
3583
    merge_effects!(interp, sv, effects)
6,692,546✔
3584
    return effects
3,555,657✔
3585
end
3586

3587
function override_effects(effects::Effects, override::EffectsOverride)
3588
    return Effects(effects;
7,111,490✔
3589
        consistent = override.consistent ? ALWAYS_TRUE : effects.consistent,
3590
        effect_free = override.effect_free ? ALWAYS_TRUE : effects.effect_free,
3591
        nothrow = override.nothrow ? true : effects.nothrow,
3592
        terminates = override.terminates_globally ? true : effects.terminates,
3593
        notaskstate = override.notaskstate ? true : effects.notaskstate,
3594
        inaccessiblememonly = override.inaccessiblememonly ? ALWAYS_TRUE : effects.inaccessiblememonly,
3595
        noub = override.noub ? ALWAYS_TRUE :
3596
            (override.noub_if_noinbounds && effects.noub !== ALWAYS_TRUE) ? NOUB_IF_NOINBOUNDS :
3597
            effects.noub,
3598
        nortcall = override.nortcall ? true : effects.nortcall)
3599
end
3600

3601
world_range(ir::IRCode) = ir.valid_worlds
3,020,133✔
3602
world_range(ci::CodeInfo) = WorldRange(ci.min_world, ci.max_world)
257,065✔
3603
world_range(ci::CodeInstance) = WorldRange(ci.min_world, ci.max_world)
384,005✔
3604
world_range(compact::IncrementalCompact) = world_range(compact.ir)
2,347,172✔
3605

3606
function abstract_eval_globalref_type(g::GlobalRef, src::Union{CodeInfo, IRCode, IncrementalCompact})
3607
    worlds = world_range(src)
3,020,412✔
3608
    (valid_worlds, rte) = abstract_load_all_consistent_leaf_partitions(nothing, g, WorldWithRange(min_world(worlds), worlds))
3,020,412✔
3609
    if min_world(valid_worlds) > min_world(worlds) || max_world(valid_worlds) < max_world(worlds)
6,040,824✔
3610
        return Any
×
3611
    end
3612
    return rte.rt
3,020,412✔
3613
end
3614

3615
function lookup_binding_partition!(interp::AbstractInterpreter, g::Union{GlobalRef, Core.Binding}, sv::AbsIntState)
3616
    partition = lookup_binding_partition(get_inference_world(interp), g)
18,315✔
3617
    update_valid_age!(sv, WorldRange(partition.min_world, partition.max_world))
18,315✔
3618
    partition
18,315✔
3619
end
3620

3621
function walk_binding_partition(imported_binding::Core.Binding, partition::Core.BindingPartition, world::UInt)
3,781,747✔
3622
    valid_worlds = WorldRange(partition.min_world, partition.max_world)
3,781,747✔
3623
    while is_some_binding_imported(binding_kind(partition))
8,293,019✔
3624
        imported_binding = partition_restriction(partition)::Core.Binding
722,024✔
3625
        partition = lookup_binding_partition(world, imported_binding)
722,024✔
3626
        valid_worlds = intersect(valid_worlds, WorldRange(partition.min_world, partition.max_world))
722,024✔
3627
    end
722,024✔
3628
    return Pair{WorldRange, Pair{Core.Binding, Core.BindingPartition}}(valid_worlds, imported_binding=>partition)
3,781,747✔
3629
end
3630

3631
function abstract_eval_binding_partition!(interp::AbstractInterpreter, g::GlobalRef, sv::AbsIntState)
3632
    b = convert(Core.Binding, g)
18,315✔
3633
    partition = lookup_binding_partition!(interp, b, sv)
18,315✔
3634
    valid_worlds, (_, partition) = walk_binding_partition(b, partition, get_inference_world(interp))
18,315✔
3635
    update_valid_age!(sv, valid_worlds)
18,315✔
3636
    return partition
18,315✔
3637
end
3638

3639
function abstract_eval_partition_load(interp::Union{AbstractInterpreter,Nothing}, binding::Core.Binding, partition::Core.BindingPartition)
3640
    kind = binding_kind(partition)
5,384,531✔
3641
    isdepwarn = (partition.kind & PARTITION_FLAG_DEPWARN) != 0
5,384,531✔
3642
    local_getglobal_effects = Effects(generic_getglobal_effects, effect_free=isdepwarn ? ALWAYS_FALSE : ALWAYS_TRUE)
5,384,531✔
3643
    if is_some_guard(kind)
10,644,274✔
3644
        if interp !== nothing && InferenceParams(interp).assume_bindings_static
124,794✔
3645
            return RTEffects(Union{}, UndefVarError, EFFECTS_THROWS)
21✔
3646
        else
3647
            # We do not currently assume an invalidation for guard -> defined transitions
3648
            # return RTEffects(Union{}, UndefVarError, EFFECTS_THROWS)
3649
            return RTEffects(Any, UndefVarError, local_getglobal_effects)
124,773✔
3650
        end
3651
    end
3652

3653
    if is_defined_const_binding(kind)
7,574,067✔
3654
        if kind == PARTITION_KIND_BACKDATED_CONST
5,259,056✔
3655
            # Infer this as guard. We do not want a later const definition to retroactively improve
3656
            # inference results in an earlier world.
3657
            return RTEffects(Any, UndefVarError, local_getglobal_effects)
241,366✔
3658
        end
3659
        rt = Const(partition_restriction(partition))
5,017,690✔
3660
        return RTEffects(rt, Union{}, Effects(EFFECTS_TOTAL,
5,017,690✔
3661
            inaccessiblememonly=is_mutation_free_argtype(rt) ? ALWAYS_TRUE : ALWAYS_FALSE,
3662
            effect_free=isdepwarn ? ALWAYS_FALSE : ALWAYS_TRUE))
3663
    end
3664

3665
    if kind == PARTITION_KIND_DECLARED
681✔
3666
        # Could be replaced by a backdated const which has an effect, so we can't assume it won't.
3667
        # Besides, we would prefer not to merge the world range for this into the world range for
3668
        # _GLOBAL, because that would pessimize codegen.
3669
        effects = Effects(local_getglobal_effects, effect_free=ALWAYS_FALSE)
71✔
3670
        rt = Any
71✔
3671
    else
3672
        rt = partition_restriction(partition)
610✔
3673
        effects = local_getglobal_effects
610✔
3674
    end
3675
    if (interp !== nothing && InferenceParams(interp).assume_bindings_static &&
687✔
3676
        kind in (PARTITION_KIND_GLOBAL, PARTITION_KIND_DECLARED) &&
3677
        isdefined(binding, :value))
3678
        exct = Union{}
12✔
3679
        effects = Effects(generic_getglobal_effects; nothrow=true)
12✔
3680
    else
3681
        # We do not assume in general that assigned global bindings remain assigned.
3682
        # The existence of pkgimages allows them to revert in practice.
3683
        exct = UndefVarError
669✔
3684
    end
3685
    return RTEffects(rt, exct, effects)
681✔
3686
end
3687

3688
function scan_specified_partitions(query::F1, walk_binding_partition::F2,
4,662,838✔
3689
    interp::Union{AbstractInterpreter,Nothing}, g::GlobalRef, wwr::WorldWithRange) where {F1,F2}
3690
    local total_validity, rte, binding_partition
4,662,838✔
3691
    binding = convert(Core.Binding, g)
4,662,838✔
3692
    lookup_world = max_world(wwr.valid_worlds)
4,662,838✔
3693
    while true
5,384,741✔
3694
        # Partitions are ordered newest-to-oldest so start at the top
3695
        binding_partition = @isdefined(binding_partition) ?
10,047,579✔
3696
            lookup_binding_partition(lookup_world, binding, binding_partition) :
3697
            lookup_binding_partition(lookup_world, binding)
3698
        while lookup_world >= binding_partition.min_world && (!@isdefined(total_validity) || min_world(total_validity) > min_world(wwr.valid_worlds))
11,461,562✔
3699
            partition_validity, (leaf_binding, leaf_partition) = walk_binding_partition(binding, binding_partition, lookup_world)
5,384,741✔
3700
            @assert lookup_world in partition_validity
5,384,741✔
3701
            this_rte = query(interp, leaf_binding, leaf_partition)
8,691,777✔
3702
            if @isdefined(rte)
5,384,741✔
3703
                if this_rte === rte
721,903✔
3704
                    total_validity = union(total_validity, partition_validity)
355,305✔
3705
                    lookup_world = min_world(total_validity) - 1
355,305✔
3706
                    continue
355,305✔
3707
                end
3708
                if min_world(total_validity) <= wwr.this
366,598✔
3709
                    @goto out
366,598✔
3710
                end
3711
            end
3712
            total_validity = partition_validity
4,662,838✔
3713
            lookup_world = min_world(total_validity) - 1
4,662,838✔
3714
            rte = this_rte
4,662,838✔
3715
        end
5,018,143✔
3716
        min_world(total_validity) > min_world(wwr.valid_worlds) || break
5,018,143✔
3717
    end
721,903✔
3718
@label out
3719
    return Pair{WorldRange, typeof(rte)}(total_validity, rte)
4,662,838✔
3720
end
3721

3722
scan_leaf_partitions(query::F, ::Nothing, g::GlobalRef, wwr::WorldWithRange) where F =
3,020,412✔
3723
    scan_specified_partitions(query, walk_binding_partition, nothing, g, wwr)
3724
scan_leaf_partitions(query::F, interp::AbstractInterpreter, g::GlobalRef, wwr::WorldWithRange) where F =
1,642,174✔
3725
    scan_specified_partitions(query, walk_binding_partition, interp, g, wwr)
3726

3727
function scan_partitions(query::F, interp::AbstractInterpreter, g::GlobalRef, wwr::WorldWithRange) where F
3728
    walk_binding_partition = function (b::Core.Binding, partition::Core.BindingPartition, ::UInt)
84✔
3729
        Pair{WorldRange, Pair{Core.Binding, Core.BindingPartition}}(
102✔
3730
            WorldRange(partition.min_world, partition.max_world), b=>partition)
3731
    end
3732
    return scan_specified_partitions(query, walk_binding_partition, interp, g, wwr)
84✔
3733
end
3734

3735
abstract_load_all_consistent_leaf_partitions(interp::AbstractInterpreter, g::GlobalRef, wwr::WorldWithRange) =
57✔
3736
    scan_leaf_partitions(abstract_eval_partition_load, interp, g, wwr)
3737
abstract_load_all_consistent_leaf_partitions(::Nothing, g::GlobalRef, wwr::WorldWithRange) =
3,020,412✔
3738
    scan_leaf_partitions(abstract_eval_partition_load, nothing, g, wwr)
3739

3740
function abstract_eval_globalref(interp::AbstractInterpreter, g::GlobalRef, saw_latestworld::Bool, sv::AbsIntState)
3741
    if saw_latestworld
1,642,051✔
3742
        return RTEffects(Any, Any, generic_getglobal_effects)
×
3743
    end
3744
    # For inference purposes, we don't particularly care which global binding we end up loading, we only
3745
    # care about its type. However, we would still like to terminate the world range for the particular
3746
    # binding we end up reaching such that codegen can emit a simpler pointer load.
3747
    (valid_worlds, ret) = scan_leaf_partitions(abstract_eval_partition_load, interp, g, sv.world)
1,642,051✔
3748
    update_valid_age!(sv, valid_worlds)
1,642,051✔
3749
    return ret
1,642,051✔
3750
end
3751

3752
function global_assignment_rt_exct(interp::AbstractInterpreter, sv::AbsIntState, saw_latestworld::Bool, g::GlobalRef, @nospecialize(newty))
3753
    if saw_latestworld
84✔
3754
        return Pair{Any,Any}(newty, ErrorException)
×
3755
    end
3756
    newtyโ€ฒ = RefValue{Any}(newty)
84✔
3757
    (valid_worlds, ret) = scan_partitions(interp, g, sv.world) do interp::AbstractInterpreter, ::Core.Binding, partition::Core.BindingPartition
84✔
3758
        global_assignment_binding_rt_exct(interp, partition, newtyโ€ฒ[])
102✔
3759
    end
3760
    update_valid_age!(sv, valid_worlds)
84✔
3761
    return ret
84✔
3762
end
3763

3764
function global_assignment_binding_rt_exct(interp::AbstractInterpreter, partition::Core.BindingPartition, @nospecialize(newty))
102✔
3765
    kind = binding_kind(partition)
102✔
3766
    if is_some_guard(kind)
186✔
3767
        return Pair{Any,Any}(newty, ErrorException)
24✔
3768
    elseif is_some_const_binding(kind) || is_some_imported(kind)
234✔
3769
        return Pair{Any,Any}(Bottom, ErrorException)
×
3770
    end
3771
    ty = kind == PARTITION_KIND_DECLARED ? Any : partition_restriction(partition)
156✔
3772
    wnewty = widenconst(newty)
78✔
3773
    if !hasintersect(wnewty, ty)
78✔
3774
        return Pair{Any,Any}(Bottom, ErrorException)
×
3775
    elseif !(wnewty <: ty)
78✔
3776
        retty = tmeet(typeinf_lattice(interp), newty, ty)
×
3777
        return Pair{Any,Any}(retty, ErrorException)
×
3778
    end
3779
    return Pair{Any,Any}(newty, Bottom)
78✔
3780
end
3781

3782
abstract_eval_ssavalue(s::SSAValue, sv::InferenceState) = abstract_eval_ssavalue(s, sv.ssavaluetypes)
6,025,746✔
3783

3784
function abstract_eval_ssavalue(s::SSAValue, ssavaluetypes::Vector{Any})
3785
    (1 โ‰ค s.id โ‰ค length(ssavaluetypes)) || throw(InvalidIRError())
3,012,873✔
3786
    typ = ssavaluetypes[s.id]
3,012,873✔
3787
    if typ === NOT_FOUND
3,012,873✔
3788
        return Bottom
×
3789
    end
3790
    return typ
3,012,873✔
3791
end
3792

3793
struct AbstractEvalBasicStatementResult
3794
    rt
3795
    exct
3796
    effects::Union{Nothing,Effects}
3797
    changes::Union{Nothing,StateUpdate}
3798
    refinements # ::Union{Nothing,SlotRefinement,Vector{Any}}
3799
    currsaw_latestworld::Bool
3800
    function AbstractEvalBasicStatementResult(rt, exct, effects::Union{Nothing,Effects},
3801
        changes::Union{Nothing,StateUpdate}, refinements, currsaw_latestworld::Bool)
3802
        @nospecialize rt exct refinements
836,727✔
3803
        return new(rt, exct, effects, changes, refinements, currsaw_latestworld)
836,903✔
3804
    end
3805
end
3806

3807
@inline function abstract_eval_basic_statement(
2,232✔
3808
    interp::AbstractInterpreter, @nospecialize(stmt), sstate::StatementState, frame::InferenceState,
3809
    result::Union{Nothing,Future{RTEffects}}=nothing)
3810
    rt = nothing
10,961,088✔
3811
    exct = Bottom
4,526,784✔
3812
    changes = nothing
4,526,784✔
3813
    refinements = nothing
4,526,784✔
3814
    effects = nothing
4,526,784✔
3815
    currsaw_latestworld = sstate.saw_latestworld
4,526,784✔
3816
    if result !== nothing
4,526,784✔
3817
        @goto injectresult
872,683✔
3818
    end
3819
    if isa(stmt, NewvarNode)
3,654,101✔
3820
        changes = StateUpdate(stmt.slot, VarState(Bottom, true))
97,229✔
3821
    elseif isa(stmt, PhiNode)
3,556,872✔
3822
        add_curr_ssaflag!(frame, IR_FLAGS_REMOVABLE)
×
3823
        # Implement convergence for PhiNodes. In particular, PhiNodes need to tmerge over
3824
        # the incoming values from all iterations, but `abstract_eval_phi` will only tmerge
3825
        # over the first and last iterations. By tmerging in the current old_rt, we ensure that
3826
        # we will not lose an intermediate value.
3827
        rt = abstract_eval_phi(interp, stmt, sstate, frame)
×
3828
        old_rt = frame.ssavaluetypes[frame.currpc]
×
3829
        rt = old_rt === NOT_FOUND ? rt : tmerge(typeinf_lattice(interp), old_rt, rt)
×
3830
    else
3831
        lhs = nothing
3,556,872✔
3832
        if isexpr(stmt, :(=))
3,556,872✔
3833
            lhs = stmt.args[1]
359,658✔
3834
            stmt = stmt.args[2]
359,658✔
3835
        end
3836
        if !isa(stmt, Expr)
3,556,872✔
3837
            (; rt, exct, effects, refinements) = abstract_eval_special_value(interp, stmt, sstate, frame)
1,976,539✔
3838
        else
3839
            hd = stmt.head
1,580,333✔
3840
            if hd === :method
1,580,333✔
3841
                fname = stmt.args[1]
×
3842
                if isa(fname, SlotNumber)
×
3843
                    changes = StateUpdate(fname, VarState(Any, false))
×
3844
                end
3845
            elseif (hd === :code_coverage_effect ||
4,732,321✔
3846
                    # :boundscheck can be narrowed to Bool
3847
                    (hd !== :boundscheck && is_meta_expr(stmt)))
3848
                rt = Nothing
84✔
3849
            elseif hd === :latestworld
1,580,249✔
3850
                currsaw_latestworld = true
15✔
3851
                rt = Nothing
15✔
3852
            else
3853
                result = abstract_eval_statement_expr(interp, stmt, sstate, frame)::Future{RTEffects}
1,580,234✔
3854
                if !isready(result) || !isempty(frame.tasks)
3,160,468✔
3855
                    return result
872,683✔
3856

3857
                    @label injectresult
3858
                    # reload local variables
3859
                    lhs = nothing
872,683✔
3860
                    if isexpr(stmt, :(=))
872,683✔
3861
                        lhs = stmt.args[1]
148,504✔
3862
                        stmt = stmt.args[2]
148,504✔
3863
                    end
3864
                end
3865
                result = result[]
2,452,885✔
3866
                (; rt, exct, effects, refinements) = result
1,580,234✔
3867
                if effects.noub === NOUB_IF_NOINBOUNDS
1,580,234✔
3868
                    if has_curr_ssaflag(frame, IR_FLAG_INBOUNDS)
26,436✔
3869
                        effects = Effects(effects; noub=ALWAYS_FALSE)
13,393✔
3870
                    elseif !propagate_inbounds(frame)
13,043✔
3871
                        # The callee read our inbounds flag, but unless we propagate inbounds,
3872
                        # we ourselves don't read our parent's inbounds.
3873
                        effects = Effects(effects; noub=ALWAYS_TRUE)
10,733✔
3874
                    end
3875
                end
3876
                @assert !isa(rt, TypeVar) "unhandled TypeVar"
1,580,234✔
3877
                rt = maybe_singleton_const(rt)
2,294,594✔
3878
                if !isempty(frame.pclimitations)
1,580,234✔
3879
                    if rt isa Const || rt === Union{}
386✔
3880
                        empty!(frame.pclimitations)
16✔
3881
                    else
3882
                        rt = LimitedAccuracy(rt, frame.pclimitations)
177✔
3883
                        frame.pclimitations = IdSet{InferenceState}()
177✔
3884
                    end
3885
                end
3886
            end
3887
        end
3888
        if lhs !== nothing && rt !== Bottom
3,556,872✔
3889
            changes = StateUpdate(lhs::SlotNumber, VarState(rt, false))
358,456✔
3890
        end
3891
    end
3892
    return AbstractEvalBasicStatementResult(rt, exct, effects, changes, refinements, currsaw_latestworld)
6,581,930✔
3893
end
3894

3895
struct BestguessInfo{Interp<:AbstractInterpreter}
3896
    interp::Interp
3897
    bestguess
3898
    nargs::Int
3899
    slottypes::Vector{Any}
3900
    changes::VarTable
3901
    function BestguessInfo(interp::Interp, @nospecialize(bestguess), nargs::Int,
3902
        slottypes::Vector{Any}, changes::VarTable) where Interp<:AbstractInterpreter
3903
        new{Interp}(interp, bestguess, nargs, slottypes, changes)
330,528✔
3904
    end
3905
end
3906

3907
@nospecializeinfer function widenreturn(@nospecialize(rt), info::BestguessInfo)
3908
    return widenreturn(typeinf_lattice(info.interp), rt, info)
330,840✔
3909
end
3910

3911
@nospecializeinfer function widenreturn(๐•ƒแตข::AbstractLattice, @nospecialize(rt), info::BestguessInfo)
3912
    return widenreturn(widenlattice(๐•ƒแตข), rt, info)
330,840✔
3913
end
3914
@nospecializeinfer function widenreturn_noslotwrapper(๐•ƒแตข::AbstractLattice, @nospecialize(rt), info::BestguessInfo)
98,815✔
3915
    return widenreturn_noslotwrapper(widenlattice(๐•ƒแตข), rt, info)
98,815✔
3916
end
3917

3918
@nospecializeinfer function widenreturn(๐•ƒแตข::MustAliasesLattice, @nospecialize(rt), info::BestguessInfo)
3919
    if isa(rt, MustAlias)
513✔
3920
        if 1 โ‰ค rt.slot โ‰ค info.nargs
216✔
3921
            rt = InterMustAlias(rt)
201✔
3922
        else
3923
            rt = widenmustalias(rt)
15✔
3924
        end
3925
    end
3926
    isa(rt, InterMustAlias) && return rt
513✔
3927
    return widenreturn(widenlattice(๐•ƒแตข), rt, info)
312✔
3928
end
3929

3930
@nospecializeinfer function widenreturn(๐•ƒแตข::ConditionalsLattice, @nospecialize(rt), info::BestguessInfo)
330,321✔
3931
    โŠ‘แตข = โŠ‘(๐•ƒแตข)
330,321✔
3932
    if !(โŠ‘(ipo_lattice(info.interp), info.bestguess, Bool)) || info.bestguess === Bool
636,648✔
3933
        # give up inter-procedural constraint back-propagation
3934
        # when tmerge would widen the result anyways (as an optimization)
3935
        rt = widenconditional(rt)
25,236✔
3936
    else
3937
        if isa(rt, Conditional)
305,127✔
3938
            id = rt.slot
3,433✔
3939
            if 1 โ‰ค id โ‰ค info.nargs
3,433✔
3940
                old_id_type = widenconditional(info.slottypes[id]) # same as `(states[1]::VarTable)[id].typ`
3,425✔
3941
                if (!(rt.thentype โŠ‘แตข old_id_type) || old_id_type โŠ‘แตข rt.thentype) &&
4,480✔
3942
                   (!(rt.elsetype โŠ‘แตข old_id_type) || old_id_type โŠ‘แตข rt.elsetype)
3943
                   # discard this `Conditional` since it imposes
3944
                   # no new constraint on the argument type
3945
                   # (the caller will recreate it if needed)
3946
                   rt = widenconditional(rt)
786✔
3947
               end
3948
            else
3949
                # discard this `Conditional` imposed on non-call arguments,
3950
                # since it's not interesting in inter-procedural context;
3951
                # we may give constraints on other call argument
3952
                rt = widenconditional(rt)
280✔
3953
            end
3954
        end
3955
        if isa(rt, Conditional)
305,127✔
3956
            rt = InterConditional(rt.slot, rt.thentype, rt.elsetype)
2,760✔
3957
        elseif is_lattice_bool(๐•ƒแตข, rt)
604,734✔
3958
            rt = bool_rt_to_conditional(rt, info)
29,479✔
3959
        end
3960
    end
3961
    if isa(rt, Conditional)
330,321✔
3962
        rt = InterConditional(rt)
×
3963
    end
3964
    isa(rt, InterConditional) && return rt
330,321✔
3965
    return widenreturn(widenlattice(๐•ƒแตข), rt, info)
327,453✔
3966
end
3967
@nospecializeinfer function bool_rt_to_conditional(@nospecialize(rt), info::BestguessInfo)
29,452✔
3968
    bestguess = info.bestguess
29,479✔
3969
    if isa(bestguess, InterConditional)
29,479✔
3970
        # if the bestguess so far is already `Conditional`, try to convert
3971
        # this `rt` into `Conditional` on the slot to avoid overapproximation
3972
        # due to conflict of different slots
3973
        rt = bool_rt_to_conditional(rt, bestguess.slot, info)
210✔
3974
    else
3975
        # pick up the first "interesting" slot, convert `rt` to its `Conditional`
3976
        # TODO: ideally we want `Conditional` and `InterConditional` to convey
3977
        # constraints on multiple slots
3978
        for slot_id = 1:Int(info.nargs)
35,069✔
3979
            rt = bool_rt_to_conditional(rt, slot_id, info)
171,716✔
3980
            rt isa InterConditional && break
85,894✔
3981
        end
85,810✔
3982
    end
3983
    return rt
29,479✔
3984
end
3985
@nospecializeinfer function bool_rt_to_conditional(@nospecialize(rt), slot_id::Int, info::BestguessInfo)
72✔
3986
    โŠ‘แตข = โŠ‘(typeinf_lattice(info.interp))
85,999✔
3987
    old = info.slottypes[slot_id]
85,999✔
3988
    new = widenslotwrapper(info.changes[slot_id].typ) # avoid nested conditional
86,811✔
3989
    if isvarargtype(old) || isvarargtype(new)
171,998✔
3990
        return rt
×
3991
    end
3992
    if new โŠ‘แตข old && !(old โŠ‘แตข new)
85,999✔
3993
        if isa(rt, Const)
108✔
3994
            val = rt.val
66✔
3995
            if val === true
66✔
3996
                return InterConditional(slot_id, new, Bottom)
23✔
3997
            elseif val === false
43✔
3998
                return InterConditional(slot_id, Bottom, new)
43✔
3999
            end
4000
        elseif rt === Bool
42✔
4001
            return InterConditional(slot_id, new, new)
42✔
4002
        end
4003
    end
4004
    return rt
85,891✔
4005
end
4006

4007
@nospecializeinfer function widenreturn(๐•ƒแตข::PartialsLattice, @nospecialize(rt), info::BestguessInfo)
4008
    return widenreturn_partials(๐•ƒแตข, rt, info)
327,459✔
4009
end
4010
@nospecializeinfer function widenreturn_noslotwrapper(๐•ƒแตข::PartialsLattice, @nospecialize(rt), info::BestguessInfo)
49,397✔
4011
    return widenreturn_partials(๐•ƒแตข, rt, info)
49,397✔
4012
end
4013
@nospecializeinfer function widenreturn_partials(๐•ƒแตข::PartialsLattice, @nospecialize(rt), info::BestguessInfo)
376,856✔
4014
    if isa(rt, PartialStruct)
376,856✔
4015
        fields = copy(rt.fields)
44,858✔
4016
        anyrefine = n_initialized(rt) > datatype_min_ninitialized(rt.typ)
44,858✔
4017
        ๐•ƒ = typeinf_lattice(info.interp)
22,429✔
4018
        โŠ = strictpartialorder(๐•ƒ)
22,429✔
4019
        for i in 1:length(fields)
28,712✔
4020
            a = fields[i]
49,397✔
4021
            a = isvarargtype(a) ? a : widenreturn_noslotwrapper(๐•ƒ, a, info)
98,794✔
4022
            if !anyrefine
49,397✔
4023
                # TODO: consider adding && const_prop_profitable(a) here?
4024
                anyrefine = has_extended_info(a) || a โŠ fieldtype(rt.typ, i)
49,829✔
4025
            end
4026
            fields[i] = a
49,397✔
4027
        end
76,365✔
4028
        anyrefine && return PartialStruct(๐•ƒแตข, rt.typ, _getundefs(rt), fields)
22,429✔
4029
    end
4030
    if isa(rt, PartialOpaque)
355,051✔
4031
        return rt # XXX: this case was missed in #39512
×
4032
    end
4033
    return widenreturn(widenlattice(๐•ƒแตข), rt, info)
355,051✔
4034
end
4035

4036
@nospecializeinfer function widenreturn(::ConstsLattice, @nospecialize(rt), ::BestguessInfo)
4037
    return widenreturn_consts(rt)
355,051✔
4038
end
4039
@nospecializeinfer function widenreturn_noslotwrapper(::ConstsLattice, @nospecialize(rt), ::BestguessInfo)
×
4040
    return widenreturn_consts(rt)
×
4041
end
4042
@nospecializeinfer function widenreturn_consts(@nospecialize(rt))
118,233✔
4043
    isa(rt, Const) && return rt
118,233✔
4044
    return widenconst(rt)
52,102✔
4045
end
4046

4047
@nospecializeinfer function widenreturn(::JLTypeLattice, @nospecialize(rt), ::BestguessInfo)
×
4048
    return widenconst(rt)
×
4049
end
4050
@nospecializeinfer function widenreturn_noslotwrapper(::JLTypeLattice, @nospecialize(rt), ::BestguessInfo)
×
4051
    return widenconst(rt)
×
4052
end
4053

4054
function handle_control_backedge!(interp::AbstractInterpreter, frame::InferenceState, from::Int, to::Int)
4055
    if from > to
271,398✔
4056
        if is_effect_overridden(frame, :terminates_locally)
37,767✔
4057
            # this backedge is known to terminate
4058
        else
4059
            merge_effects!(interp, frame, Effects(EFFECTS_TOTAL; terminates=false))
17,498✔
4060
        end
4061
    end
4062
    return nothing
271,398✔
4063
end
4064

4065
function update_bbstate!(๐•ƒแตข::AbstractLattice, frame::InferenceState, bb::Int, vartable::VarTable, saw_latestworld::Bool)
4066
    frame.bb_saw_latestworld[bb] |= saw_latestworld
554,974✔
4067
    bbtable = frame.bb_vartables[bb]
554,974✔
4068
    if bbtable === nothing
554,974✔
4069
        # if a basic block hasn't been analyzed yet,
4070
        # we can update its state a bit more aggressively
4071
        frame.bb_vartables[bb] = copy(vartable)
409,214✔
4072
        return true
409,214✔
4073
    else
4074
        return stupdate!(๐•ƒแตข, bbtable, vartable)
145,760✔
4075
    end
4076
end
4077

4078
function init_vartable!(vartable::VarTable, frame::InferenceState)
4079
    nargtypes = length(frame.result.argtypes)
×
4080
    for i = 1:length(vartable)
×
4081
        vartable[i] = VarState(Bottom, i > nargtypes)
×
4082
    end
×
4083
    return vartable
×
4084
end
4085

4086
function update_bestguess!(interp::AbstractInterpreter, frame::InferenceState,
330,528✔
4087
                           currstate::VarTable, @nospecialize(rt))
4088
    bestguess = frame.bestguess
330,528✔
4089
    nargs = narguments(frame, #=include_va=#false)
330,528✔
4090
    slottypes = frame.slottypes
330,528✔
4091
    rt = widenreturn(rt, BestguessInfo(interp, bestguess, nargs, slottypes, currstate))
330,840✔
4092
    # narrow representation of bestguess slightly to prepare for tmerge with rt
4093
    if rt isa InterConditional && bestguess isa Const && bestguess.val isa Bool
330,528✔
4094
        slot_id = rt.slot
×
4095
        old_id_type = widenconditional(slottypes[slot_id])
×
4096
        if bestguess.val === true && rt.elsetype !== Bottom
×
4097
            bestguess = InterConditional(slot_id, old_id_type, Bottom)
×
4098
        elseif bestguess.val === false && rt.thentype !== Bottom
×
4099
            bestguess = InterConditional(slot_id, Bottom, old_id_type)
×
4100
        end
4101
    # or narrow representation of rt slightly to prepare for tmerge with bestguess
4102
    elseif bestguess isa InterConditional && rt isa Const && rt.val isa Bool
330,528✔
4103
        slot_id = bestguess.slot
75✔
4104
        old_id_type = widenconditional(slottypes[slot_id])
75✔
4105
        if rt.val === true && bestguess.elsetype !== Bottom
75✔
4106
            rt = InterConditional(slot_id, old_id_type, Bottom)
3✔
4107
        elseif rt.val === false && bestguess.thentype !== Bottom
72✔
4108
            rt = InterConditional(slot_id, Bottom, old_id_type)
57✔
4109
        end
4110
    end
4111
    # copy limitations to return value
4112
    if !isempty(frame.pclimitations)
330,528✔
4113
        union!(frame.limitations, frame.pclimitations)
55✔
4114
        empty!(frame.pclimitations)
55✔
4115
    end
4116
    if !isempty(frame.limitations)
330,528✔
4117
        rt = LimitedAccuracy(rt, copy(frame.limitations))
103✔
4118
    end
4119
    ๐•ƒโ‚š = ipo_lattice(interp)
330,528✔
4120
    if !โŠ‘(๐•ƒโ‚š, rt, bestguess)
330,528✔
4121
        # TODO: if bestguess isa InterConditional && !interesting(bestguess); bestguess = widenconditional(bestguess); end
4122
        frame.bestguess = tmerge(๐•ƒโ‚š, bestguess, rt) # new (wider) return type for frame
312,573✔
4123
        return true
312,138✔
4124
    else
4125
        return false
18,390✔
4126
    end
4127
end
4128

4129
function update_exc_bestguess!(interp::AbstractInterpreter, @nospecialize(exct), frame::InferenceState)
273,710✔
4130
    ๐•ƒโ‚š = ipo_lattice(interp)
273,710✔
4131
    handler = gethandler(frame)
315,740✔
4132
    if handler === nothing
273,710✔
4133
        if !โŠ‘(๐•ƒโ‚š, exct, frame.exc_bestguess)
258,787✔
4134
            frame.exc_bestguess = tmerge(๐•ƒโ‚š, frame.exc_bestguess, exct)
103,228✔
4135
            update_cycle_worklists!(frame) do caller::InferenceState, caller_pc::Int
103,063✔
4136
                caller_handler = gethandler(caller, caller_pc)
45✔
4137
                caller_exct = caller_handler === nothing ?
45✔
4138
                    caller.exc_bestguess : caller_handler.exct
4139
                return caller_exct !== Any
45✔
4140
            end
4141
        end
4142
    else
4143
        if !โŠ‘(๐•ƒโ‚š, exct, handler.exct)
14,923✔
4144
            handler.exct = tmerge(๐•ƒโ‚š, handler.exct, exct)
4,764✔
4145
            enter = frame.src.code[handler.enter_idx]::EnterNode
4,764✔
4146
            exceptbb = block_for_inst(frame.cfg, enter.catch_dest)
4,764✔
4147
            push!(frame.ip, exceptbb)
4,764✔
4148
        end
4149
    end
4150
end
4151

4152
function propagate_to_error_handler!(currstate::VarTable, currsaw_latestworld::Bool, frame::InferenceState, ๐•ƒแตข::AbstractLattice)
37,190✔
4153
    # If this statement potentially threw, propagate the currstate to the
4154
    # exception handler, BEFORE applying any state changes.
4155
    curr_hand = gethandler(frame)
47,359✔
4156
    if curr_hand !== nothing
37,190✔
4157
        enter = frame.src.code[curr_hand.enter_idx]::EnterNode
2,862✔
4158
        exceptbb = block_for_inst(frame.cfg, enter.catch_dest)
2,862✔
4159
        if update_bbstate!(๐•ƒแตข, frame, exceptbb, currstate, currsaw_latestworld)
2,862✔
4160
            push!(frame.ip, exceptbb)
2,697✔
4161
        end
4162
    end
4163
end
4164

4165
function update_cycle_worklists!(callback, frame::InferenceState)
126,797✔
4166
    for (caller, caller_pc) in frame.cycle_backedges
126,797✔
4167
        if callback(caller, caller_pc)
75✔
4168
            push!(caller.ip, block_for_inst(caller.cfg, caller_pc))
60✔
4169
        end
4170
    end
75✔
4171
end
4172

4173
# make as much progress on `frame` as possible (without handling cycles)
4174
struct CurrentState
4175
    result::Future{RTEffects}
4176
    currstate::VarTable
4177
    currsaw_latestworld::Bool
4178
    bbstart::Int
4179
    bbend::Int
4180
    CurrentState(result::Future{RTEffects}, currstate::VarTable, currsaw_latestworld::Bool, bbstart::Int, bbend::Int) =
872,683✔
4181
        new(result, currstate, currsaw_latestworld, bbstart, bbend)
4182
    CurrentState() = new()
619,280✔
4183
end
4184

4185
function typeinf_local(interp::AbstractInterpreter, frame::InferenceState, nextresult::CurrentState)
1,182,406✔
4186
    @assert !is_inferred(frame)
1,182,406✔
4187
    W = frame.ip
1,182,406✔
4188
    ssavaluetypes = frame.ssavaluetypes
1,182,406✔
4189
    bbs = frame.cfg.blocks
1,182,406✔
4190
    nbbs = length(bbs)
1,182,406✔
4191
    ๐•ƒแตข = typeinf_lattice(interp)
1,182,406✔
4192
    states = frame.bb_vartables
1,182,406✔
4193
    saw_latestworld = frame.bb_saw_latestworld
1,182,406✔
4194
    currbb = frame.currbb
1,182,406✔
4195
    currpc = frame.currpc
1,182,406✔
4196

4197
    if isdefined(nextresult, :result)
1,182,406✔
4198
        # for reasons that are fairly unclear, some state is arbitrarily on the stack instead in the InferenceState as normal
4199
        bbstart = nextresult.bbstart
872,683✔
4200
        bbend = nextresult.bbend
872,683✔
4201
        currstate = nextresult.currstate
872,683✔
4202
        currsaw_latestworld = nextresult.currsaw_latestworld
872,683✔
4203
        stmt = frame.src.code[currpc]
872,683✔
4204
        result = abstract_eval_basic_statement(interp, stmt, StatementState(currstate, currsaw_latestworld), frame, nextresult.result)
1,020,309✔
4205
        @goto injected_result
872,683✔
4206
    end
4207

4208
    if currbb != 1
309,723✔
4209
        currbb = frame.currbb = _bits_findnext(W.bits, 1)::Int # next basic block
494✔
4210
    end
4211
    currstate = copy(states[currbb]::VarTable)
618,756✔
4212
    currsaw_latestworld = saw_latestworld[currbb]
309,723✔
4213
    while currbb <= nbbs
782,619✔
4214
        delete!(W, currbb)
1,565,238✔
4215
        bbstart = first(bbs[currbb].stmts)
782,619✔
4216
        bbend = last(bbs[currbb].stmts)
782,619✔
4217

4218
        currpc = bbstart - 1
782,619✔
4219
        while currpc < bbend
4,416,070✔
4220
            currpc += 1
4,368,332✔
4221
            frame.currpc = currpc
4,368,332✔
4222
            stmt = frame.src.code[currpc]
4,368,332✔
4223
            # If we're at the end of the basic block ...
4224
            if currpc == bbend
4,368,332✔
4225
                # Handle control flow
4226
                if isa(stmt, GotoNode)
770,117✔
4227
                    succs = bbs[currbb].succs
126,551✔
4228
                    @assert length(succs) == 1
126,551✔
4229
                    nextbb = succs[1]
126,551✔
4230
                    ssavaluetypes[currpc] = Any
126,551✔
4231
                    handle_control_backedge!(interp, frame, currpc, stmt.label)
144,049✔
4232
                    add_curr_ssaflag!(frame, IR_FLAG_NOTHROW)
126,551✔
4233
                    @goto branch
126,551✔
4234
                elseif isa(stmt, GotoIfNot)
643,566✔
4235
                    condx = stmt.cond
245,163✔
4236
                    condslot = ssa_def_slot(condx, frame)
245,163✔
4237
                    condt = abstract_eval_value(interp, condx, StatementState(currstate, currsaw_latestworld), frame)
490,326✔
4238
                    if condt === Bottom
245,163✔
4239
                        ssavaluetypes[currpc] = Bottom
×
4240
                        empty!(frame.pclimitations)
×
4241
                        @goto find_next_bb
×
4242
                    end
4243
                    orig_condt = condt
245,163✔
4244
                    if !(isa(condt, Const) || isa(condt, Conditional)) && isa(condslot, SlotNumber)
435,698✔
4245
                        # if this non-`Conditional` object is a slot, we form and propagate
4246
                        # the conditional constraint on it
4247
                        condt = Conditional(condslot, Const(true), Const(false))
7,103✔
4248
                    end
4249
                    condval = maybe_extract_const_bool(condt)
435,698✔
4250
                    nothrow = (condval !== nothing) || โŠ‘(๐•ƒแตข, orig_condt, Bool)
367,253✔
4251
                    if nothrow
245,163✔
4252
                        add_curr_ssaflag!(frame, IR_FLAG_NOTHROW)
243,402✔
4253
                    else
4254
                        update_exc_bestguess!(interp, TypeError, frame)
1,761✔
4255
                        propagate_to_error_handler!(currstate, currsaw_latestworld, frame, ๐•ƒแตข)
1,761✔
4256
                        merge_effects!(interp, frame, EFFECTS_THROWS)
1,761✔
4257
                    end
4258

4259
                    if !isempty(frame.pclimitations)
245,163✔
4260
                        # we can't model the possible effect of control
4261
                        # dependencies on the return
4262
                        # directly to all the return values (unless we error first)
4263
                        condval isa Bool || union!(frame.limitations, frame.pclimitations)
36✔
4264
                        empty!(frame.pclimitations)
18✔
4265
                    end
4266
                    ssavaluetypes[currpc] = Any
245,163✔
4267
                    if condval === true
245,163✔
4268
                        @goto fallthrough
88,251✔
4269
                    else
4270
                        if !nothrow && !hasintersect(widenconst(orig_condt), Bool)
156,912✔
4271
                            ssavaluetypes[currpc] = Bottom
9✔
4272
                            @goto find_next_bb
9✔
4273
                        end
4274

4275
                        succs = bbs[currbb].succs
156,903✔
4276
                        if length(succs) == 1
156,903✔
4277
                            @assert condval === false || (stmt.dest === currpc + 1)
×
4278
                            nextbb = succs[1]
×
4279
                            @goto branch
×
4280
                        end
4281
                        @assert length(succs) == 2
156,903✔
4282
                        truebb = currbb + 1
156,903✔
4283
                        falsebb = succs[1] == truebb ? succs[2] : succs[1]
156,903✔
4284
                        if condval === false
156,903✔
4285
                            nextbb = falsebb
34,822✔
4286
                            handle_control_backedge!(interp, frame, currpc, stmt.dest)
34,822✔
4287
                            @goto branch
34,822✔
4288
                        end
4289

4290
                        # We continue with the true branch, but process the false
4291
                        # branch here.
4292
                        if isa(condt, Conditional)
122,081✔
4293
                            else_change = conditional_change(๐•ƒแตข, currstate, condt, #=then_or_else=#false)
94,361✔
4294
                            if else_change !== nothing
51,311✔
4295
                                elsestate = copy(currstate)
88,152✔
4296
                                stoverwrite1!(elsestate, else_change)
44,076✔
4297
                            elseif condslot isa SlotNumber
7,235✔
4298
                                elsestate = copy(currstate)
6,716✔
4299
                            else
4300
                                elsestate = currstate
519✔
4301
                            end
4302
                            if condslot isa SlotNumber # refine the type of this conditional object itself for this else branch
51,311✔
4303
                                stoverwrite1!(elsestate, condition_object_change(currstate, condt, condslot, #=then_or_else=#false))
14,029✔
4304
                            end
4305
                            else_changed = update_bbstate!(๐•ƒแตข, frame, falsebb, elsestate, currsaw_latestworld)
51,311✔
4306
                            then_change = conditional_change(๐•ƒแตข, currstate, condt, #=then_or_else=#true)
94,421✔
4307
                            thenstate = currstate
51,311✔
4308
                            if then_change !== nothing
51,311✔
4309
                                stoverwrite1!(thenstate, then_change)
44,136✔
4310
                            end
4311
                            if condslot isa SlotNumber # refine the type of this conditional object itself for this then branch
51,311✔
4312
                                stoverwrite1!(thenstate, condition_object_change(currstate, condt, condslot, #=then_or_else=#true))
14,029✔
4313
                            end
4314
                        else
4315
                            else_changed = update_bbstate!(๐•ƒแตข, frame, falsebb, currstate, currsaw_latestworld)
70,770✔
4316
                        end
4317
                        if else_changed
122,081✔
4318
                            handle_control_backedge!(interp, frame, currpc, stmt.dest)
110,025✔
4319
                            push!(W, falsebb)
110,025✔
4320
                        end
4321
                        @goto fallthrough
122,081✔
4322
                    end
4323
                elseif isa(stmt, ReturnNode)
398,403✔
4324
                    rt = abstract_eval_value(interp, stmt.val, StatementState(currstate, currsaw_latestworld), frame)
666,084✔
4325
                    if update_bestguess!(interp, frame, currstate, rt)
333,045✔
4326
                        update_cycle_worklists!(frame) do caller::InferenceState, caller_pc::Int
314,577✔
4327
                            # no reason to revisit if that call-site doesn't affect the final result
4328
                            return caller.ssavaluetypes[caller_pc] !== Any
30✔
4329
                        end
4330
                    end
4331
                    ssavaluetypes[currpc] = Any
333,045✔
4332
                    @goto find_next_bb
333,045✔
4333
                elseif isa(stmt, EnterNode)
65,358✔
4334
                    ssavaluetypes[currpc] = Any
5,070✔
4335
                    add_curr_ssaflag!(frame, IR_FLAG_NOTHROW)
5,070✔
4336
                    if isdefined(stmt, :scope)
5,070✔
4337
                        scopet = abstract_eval_value(interp, stmt.scope, StatementState(currstate, currsaw_latestworld), frame)
4,876✔
4338
                        handler = gethandler(frame, currpc + 1)::TryCatchFrame
4,876✔
4339
                        @assert handler.scopet !== nothing
2,438✔
4340
                        if !โŠ‘(๐•ƒแตข, scopet, handler.scopet)
2,438✔
4341
                            handler.scopet = tmerge(๐•ƒแตข, scopet, handler.scopet)
4,876✔
4342
                            if isdefined(handler, :scope_uses)
2,438✔
4343
                                for bb in handler.scope_uses
×
4344
                                    push!(W, bb)
×
4345
                                end
×
4346
                            end
4347
                        end
4348
                    end
4349
                    @goto fallthrough
5,070✔
4350
                elseif isexpr(stmt, :leave)
60,288✔
4351
                    ssavaluetypes[currpc] = Any
5,518✔
4352
                    @goto fallthrough
5,518✔
4353
                end
4354
                # Fall through terminator - treat as regular stmt
4355
            end
4356
            # Process non control-flow statements
4357
            @assert isempty(frame.tasks)
3,652,985✔
4358
            sstate = StatementState(currstate, currsaw_latestworld)
3,652,985✔
4359
            result = abstract_eval_basic_statement(interp, stmt, sstate, frame)
6,433,188✔
4360
            if result isa Future{RTEffects}
3,652,985✔
4361
                return CurrentState(result, currstate, currsaw_latestworld, bbstart, bbend)
872,683✔
4362
            else
4363
                @label injected_result
4364
                (; rt, exct, effects, changes, refinements, currsaw_latestworld) = result
3,652,985✔
4365
            end
4366
            effects === nothing || merge_override_effects!(interp, effects, frame)
7,208,642✔
4367
            if !has_curr_ssaflag(frame, IR_FLAG_NOTHROW)
3,652,985✔
4368
                if exct !== Union{}
371,409✔
4369
                    update_exc_bestguess!(interp, exct, frame)
274,081✔
4370
                    # TODO: assert that these conditions match. For now, we assume the `nothrow` flag
4371
                    # to be correct, but allow the exct to be an over-approximation.
4372
                end
4373
                propagate_to_error_handler!(currstate, currsaw_latestworld, frame, ๐•ƒแตข)
371,409✔
4374
            end
4375
            if rt === Bottom
3,652,985✔
4376
                ssavaluetypes[currpc] = Bottom
19,534✔
4377
                # Special case: Bottom-typed PhiNodes do not error (but must also be unused)
4378
                if isa(stmt, PhiNode)
19,534✔
4379
                    continue
×
4380
                end
4381
                @goto find_next_bb
19,534✔
4382
            end
4383
            if changes !== nothing
3,633,451✔
4384
                stoverwrite1!(currstate, changes)
455,685✔
4385
            end
4386
            if refinements isa SlotRefinement
3,633,451✔
4387
                apply_refinement!(๐•ƒแตข, refinements.slot, refinements.typ, currstate, changes)
3,992✔
4388
            elseif refinements isa Vector{Any}
3,630,302✔
4389
                for i = 1:length(refinements)
271✔
4390
                    newtyp = refinements[i]
1,295✔
4391
                    newtyp === nothing && continue
1,295✔
4392
                    apply_refinement!(๐•ƒแตข, SlotNumber(i), newtyp, currstate, changes)
271✔
4393
                end
1,295✔
4394
            end
4395
            if rt === nothing
3,633,451✔
4396
                ssavaluetypes[currpc] = Any
97,229✔
4397
                continue
97,229✔
4398
            end
4399
            record_ssa_assign!(๐•ƒแตข, currpc, rt, frame)
3,536,222✔
4400
        end # for currpc in bbstart:bbend
3,633,451✔
4401

4402
        # Case 1: Fallthrough termination
4403
        begin @label fallthrough
4404
            nextbb = currbb + 1
268,658✔
4405
        end
4406

4407
        # Case 2: Directly branch to a different BB
4408
        begin @label branch
4409
            if update_bbstate!(๐•ƒแตข, frame, nextbb, currstate, currsaw_latestworld)
430,031✔
4410
                push!(W, nextbb)
392,221✔
4411
            end
4412
        end
4413

4414
        # Case 3: Control flow ended along the current path (converged, return or throw)
4415
        begin @label find_next_bb
4416
            currbb = frame.currbb = _bits_findnext(W.bits, 1)::Int # next basic block
1,565,238✔
4417
            currbb == -1 && break # the working set is empty
782,619✔
4418
            currbb > nbbs && break
472,896✔
4419

4420
            nexttable = states[currbb]
472,896✔
4421
            if nexttable === nothing
472,896✔
4422
                init_vartable!(currstate, frame)
×
4423
            else
4424
                stoverwrite!(currstate, nexttable)
472,896✔
4425
            end
4426
        end
4427
    end # while currbb <= nbbs
472,896✔
4428

4429
    return CurrentState()
309,723✔
4430
end
4431

4432
function apply_refinement!(๐•ƒแตข::AbstractLattice, slot::SlotNumber, @nospecialize(newtyp),
57✔
4433
                           currstate::VarTable, currchanges::Union{Nothing,StateUpdate})
4434
    if currchanges !== nothing && currchanges.var == slot
57✔
4435
        return # type propagation from statement (like assignment) should have the precedence
×
4436
    end
4437
    vtype = currstate[slot_id(slot)]
57✔
4438
    oldtyp = vtype.typ
57✔
4439
    โŠ = strictpartialorder(๐•ƒแตข)
57✔
4440
    if newtyp โŠ oldtyp
57✔
4441
        stmtupdate = StateUpdate(slot, VarState(newtyp, vtype.undef))
27✔
4442
        stoverwrite1!(currstate, stmtupdate)
27✔
4443
    end
4444
end
4445

4446
function conditional_change(๐•ƒแตข::AbstractLattice, currstate::VarTable, condt::Conditional, then_or_else::Bool)
4447
    vtype = currstate[condt.slot]
102,622✔
4448
    oldtyp = vtype.typ
102,622✔
4449
    newtyp = then_or_else ? condt.thentype : condt.elsetype
102,622✔
4450
    if iskindtype(newtyp)
205,007✔
4451
        # this code path corresponds to the special handling for `isa(x, iskindtype)` check
4452
        # implemented within `abstract_call_builtin`
4453
    elseif โŠ‘(๐•ƒแตข, ignorelimited(newtyp), ignorelimited(oldtyp))
203,228✔
4454
        # approximate test for `typ โˆฉ oldtyp` being better than `oldtyp`
4455
        # since we probably formed these types with `typesubstract`,
4456
        # the comparison is likely simple
4457
    else
4458
        return nothing
14,410✔
4459
    end
4460
    if oldtyp isa LimitedAccuracy
88,212✔
4461
        # typ is better unlimited, but we may still need to compute the tmeet with the limit
4462
        # "causes" since we ignored those in the comparison
4463
        newtyp = tmerge(๐•ƒแตข, newtyp, LimitedAccuracy(Bottom, oldtyp.causes))
36✔
4464
    end
4465
    # if this `Conditional` is from `@isdefined condt.slot`, refine its `undef` information
4466
    newundef = condt.isdefined ? !then_or_else : vtype.undef
174,372✔
4467
    return StateUpdate(SlotNumber(condt.slot), VarState(newtyp, newundef), #=conditional=#true)
88,212✔
4468
end
4469

4470
function condition_object_change(currstate::VarTable, condt::Conditional,
4471
                                 condslot::SlotNumber, then_or_else::Bool)
4472
    vtype = currstate[slot_id(condslot)]
28,058✔
4473
    newcondt = Conditional(condt.slot,
28,548✔
4474
        then_or_else ? condt.thentype : Union{},
4475
        then_or_else ? Union{} : condt.elsetype)
4476
    return StateUpdate(condslot, VarState(newcondt, vtype.undef))
28,058✔
4477
end
4478

4479
# make as much progress on `frame` as possible (by handling cycles)
4480
warnlength::Int = 2500
4481
function typeinf(interp::AbstractInterpreter, frame::InferenceState)
180,286✔
4482
    time_before = _time_ns()
180,286✔
4483
    callstack = frame.callstack::Vector{AbsIntState}
180,286✔
4484
    nextstates = CurrentState[]
180,286✔
4485
    takenext = frame.frameid
180,286✔
4486
    minwarn = warnlength
180,286✔
4487
    while takenext >= frame.frameid
3,818,930✔
4488
        callee = takenext == 0 ? frame : callstack[takenext]::InferenceState
7,256,223✔
4489
        if !isempty(callstack)
3,640,868✔
4490
            if length(callstack) - frame.frameid >= minwarn
3,616,794✔
4491
                topmethod = callstack[1].linfo
×
4492
                topmethod.def isa Method || (topmethod = callstack[2].linfo)
×
4493
                print(Core.stderr, "info: inference of ", topmethod, " exceeding ", length(callstack), " frames (may be slow).\n")
×
4494
                minwarn *= 2
×
4495
            end
4496
            topcallee = (callstack[end]::InferenceState)
3,616,794✔
4497
            if topcallee.cycleid != callee.cycleid
3,616,794✔
4498
                callee = topcallee
129,271✔
4499
                takenext = length(callstack)
129,271✔
4500
            end
4501
        end
4502
        interp = callee.interp
3,640,868✔
4503
        nextstateid = takenext + 1 - frame.frameid
3,640,868✔
4504
        while length(nextstates) < nextstateid
3,950,425✔
4505
            push!(nextstates, CurrentState())
309,557✔
4506
        end
309,557✔
4507
        if doworkloop(interp, callee)
3,640,868✔
4508
            # First drain the workloop. Note that since some scheduled work doesn't
4509
            # affect the result (e.g. cfunction or abstract_call_method on
4510
            # get_compileable_sig), but still must be finished up since it may see and
4511
            # change the local variables of the InferenceState at currpc, we do this
4512
            # even if the nextresult status is already completed.
4513
        elseif isdefined(nextstates[nextstateid], :result) || !isempty(callee.ip)
2,133,844✔
4514
            # Next make progress on this frame
4515
            prev = length(callee.tasks) + 1
1,182,604✔
4516
            nextstates[nextstateid] = typeinf_local(interp, callee, nextstates[nextstateid])
1,182,604✔
4517
            reverse!(callee.tasks, prev)
1,182,604✔
4518
        elseif callee.cycleid == length(callstack)
319,845✔
4519
            # With no active ip's and no cycles, frame is done
4520
            time_now = _time_ns()
308,757✔
4521
            callee.time_self_ns += (time_now - time_before)
308,757✔
4522
            time_before = time_now
308,757✔
4523
            finish_nocycle(interp, callee, time_before)
308,757✔
4524
            callee.frameid == 0 && break
308,757✔
4525
            takenext = length(callstack)
306,533✔
4526
            nextstateid = takenext + 1 - frame.frameid
306,533✔
4527
            #@assert length(nextstates) == nextstateid + 1
4528
            #@assert all(i -> !isdefined(nextstates[i], :result), nextstateid+1:length(nextstates))
4529
            resize!(nextstates, nextstateid)
306,533✔
4530
            continue
306,533✔
4531
        elseif callee.cycleid == callee.frameid
11,088✔
4532
            # If the current frame is the top part of a cycle, check if the whole cycle
4533
            # is done, and if not, pick the next item to work on.
4534
            time_now = _time_ns()
359✔
4535
            callee.time_self_ns += (time_now - time_before)
359✔
4536
            time_before = time_now
359✔
4537
            no_active_ips_in_cycle = true
359✔
4538
            for i = callee.cycleid:length(callstack)
389✔
4539
                caller = callstack[i]::InferenceState
1,195✔
4540
                @assert caller.cycleid == callee.cycleid
1,195✔
4541
                if !isempty(caller.tasks) || isdefined(nextstates[i+1-frame.frameid], :result) || !isempty(caller.ip)
2,585✔
4542
                    no_active_ips_in_cycle = false
143✔
4543
                    break
143✔
4544
                end
4545
            end
1,052✔
4546
            if no_active_ips_in_cycle
359✔
4547
                finish_cycle(interp, callstack, callee.cycleid, time_before)
216✔
4548
            end
4549
            takenext = length(callstack)
359✔
4550
            nextstateid = takenext + 1 - frame.frameid
359✔
4551
            if no_active_ips_in_cycle
359✔
4552
                #@assert all(i -> !isdefined(nextstates[i], :result), nextstateid+1:length(nextstates))
4553
                resize!(nextstates, nextstateid)
216✔
4554
            else
4555
                #@assert length(nextstates) == nextstateid
4556
            end
4557
            continue
359✔
4558
        else
4559
            # Continue to the next frame in this cycle
4560
            takenext = takenext - 1
10,729✔
4561
        end
4562
        time_now = _time_ns()
3,331,752✔
4563
        callee.time_self_ns += (time_now - time_before)
3,331,752✔
4564
        time_before = time_now
3,331,752✔
4565
    end
3,638,644✔
4566
    #@assert all(nextresult -> !isdefined(nextresult, :result), nextstates)
4567
    return is_inferred(frame)
180,286✔
4568
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