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

JuliaLang / julia / #37632

26 Sep 2023 06:44AM UTC coverage: 86.999% (-0.9%) from 87.914%
#37632

push

local

web-flow
inference: make `throw` block deoptimization concrete-eval friendly (#49235)

The deoptimization can sometimes destroy the effects analysis and
disable [semi-]concrete evaluation that is otherwise possible. This is
because the deoptimization was designed with the type domain
profitability in mind (#35982), and hasn't been adequately considering
the effects domain.

This commit makes the deoptimization aware of the effects domain more
and enables the `throw` block deoptimization only when the effects
already known to be ineligible for concrete-evaluation.

In our current effect system, `ALWAYS_FALSE`/`false` means that the
effect can not be refined to `ALWAYS_TRUE`/`true` anymore (unless given
user annotation later). Therefore we can enable the `throw` block
deoptimization without hindering the chance of concrete-evaluation when
any of the following conditions are met:
- `effects.consistent === ALWAYS_FALSE`
- `effects.effect_free === ALWAYS_FALSE`
- `effects.terminates === false`
- `effects.nonoverlayed === false`

Here are some numbers:

| Metric | master | this commit | #35982 reverted (set
`unoptimize_throw_blocks=false`) |

|-------------------------|-----------|-------------|--------------------------------------------|
| Base (seconds) | 15.579300 | 15.206645 | 15.296319 |
| Stdlibs (seconds) | 17.919013 | 17.667094 | 17.738128 |
| Total (seconds) | 33.499279 | 32.874737 | 33.035448 |
| Precompilation (seconds) | 49.967516 | 49.421121 | 49.999998 |
| First time `plot(rand(10,3))` [^1] | `2.476678 seconds (11.74 M
allocations)` | `2.430355 seconds (11.77 M allocations)` | `2.514874
seconds (11.64 M allocations)` |
| First time `solve(prob, QNDF())(5.0)` [^2] | `4.469492 seconds (15.32
M allocations)` | `4.499217 seconds (15.41 M allocations)` | `4.470772
seconds (15.38 M allocations)` |

[^1]: With disabling precompilation of Plots.jl.
[^2]: With disabling precompilation of OrdinaryDiffEq.

These numbers ma... (continued)

7 of 7 new or added lines in 1 file covered. (100.0%)

73407 of 84377 relevant lines covered (87.0%)

11275130.05 hits per line

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

86.39
/base/compiler/abstractinterpretation.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
# See if the inference result of the current statement's result value might affect
4
# the final answer for the method (aside from optimization potential and exceptions).
5
# To do that, we need to check both for slot assignment and SSA usage.
6
call_result_unused(sv::InferenceState, currpc::Int) =
34,264,481✔
7
    isexpr(sv.src.code[currpc], :call) && isempty(sv.ssavalue_uses[currpc])
8
call_result_unused(si::StmtInfo) = !si.used
46,054,956✔
9

10
function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
22,452,438✔
11
                                  arginfo::ArgInfo, si::StmtInfo, @nospecialize(atype),
12
                                  sv::AbsIntState, max_methods::Int)
13
    โŠ‘โ‚š = โŠ‘(ipo_lattice(interp))
22,431,452✔
14
    if !should_infer_this_call(interp, sv)
22,788,337✔
15
        add_remark!(interp, sv, "Skipped call in throw block")
92✔
16
        # At this point we are guaranteed to end up throwing on this path,
17
        # which is all that's required for :consistent-cy. Of course, we don't
18
        # know anything else about this statement.
19
        effects = Effects(; consistent=ALWAYS_TRUE)
92✔
20
        return CallMeta(Any, effects, NoCallInfo())
335,899✔
21
    end
22

23
    argtypes = arginfo.argtypes
22,116,539✔
24
    matches = find_matching_methods(typeinf_lattice(interp), argtypes, atype, method_table(interp),
22,116,539✔
25
        InferenceParams(interp).max_union_splitting, max_methods)
26
    if isa(matches, FailedMethodMatch)
22,116,539✔
27
        add_remark!(interp, sv, matches.reason)
18✔
28
        return CallMeta(Any, Effects(), NoCallInfo())
658,436✔
29
    end
30

31
    (; valid_worlds, applicable, info) = matches
21,458,103✔
32
    update_valid_age!(sv, valid_worlds)
21,458,103✔
33
    napplicable = length(applicable)
21,458,103✔
34
    rettype = Bottom
15,337✔
35
    edges = MethodInstance[]
21,458,103✔
36
    conditionals = nothing # keeps refinement information of call argument types when the return type is boolean
15,337✔
37
    seen = 0               # number of signatures actually inferred
15,337✔
38
    any_const_result = false
15,337✔
39
    const_results = Union{Nothing,ConstResult}[]
21,458,103✔
40
    multiple_matches = napplicable > 1
21,458,103✔
41
    fargs = arginfo.fargs
21,458,103✔
42
    all_effects = EFFECTS_TOTAL
15,337✔
43

44
    ๐•ƒโ‚š = ipo_lattice(interp)
42,859,223✔
45
    for i in 1:napplicable
42,908,466✔
46
        match = applicable[i]::MethodMatch
22,377,597✔
47
        method = match.method
22,377,597✔
48
        sig = match.spec_types
22,377,597✔
49
        if bail_out_toplevel_call(interp, InferenceLoopState(sig, rettype, all_effects), sv)
22,357,350✔
50
            # only infer concrete call sites in top-level expressions
51
            add_remark!(interp, sv, "Refusing to infer non-concrete call site in top-level expression")
×
52
            break
74,664✔
53
        end
54
        this_rt = Bottom
15,368✔
55
        splitunions = false
15,368✔
56
        # TODO: this used to trigger a bug in inference recursion detection, and is unmaintained now
57
        # sigtuple = unwrap_unionall(sig)::DataType
58
        # splitunions = 1 < unionsplitcost(sigtuple.parameters) * napplicable <= InferenceParams(interp).max_union_splitting
59
        if splitunions
15,368✔
60
            splitsigs = switchtupleunion(sig)
×
61
            for sig_n in splitsigs
×
62
                result = abstract_call_method(interp, method, sig_n, svec(), multiple_matches, si, sv)
×
63
                (; rt, edge, effects) = result
×
64
                this_argtypes = isa(matches, MethodMatches) ? argtypes : matches.applicable_argtypes[i]
×
65
                this_arginfo = ArgInfo(fargs, this_argtypes)
×
66
                const_call_result = abstract_call_method_with_const_args(interp,
×
67
                    result, f, this_arginfo, si, match, sv)
68
                const_result = nothing
×
69
                if const_call_result !== nothing
×
70
                    if const_call_result.rt โŠ‘โ‚š rt
×
71
                        rt = const_call_result.rt
×
72
                        (; effects, const_result, edge) = const_call_result
×
73
                    else
74
                        add_remark!(interp, sv, "[constprop] Discarded because the result was wider than inference")
×
75
                    end
76
                end
77
                all_effects = merge_effects(all_effects, effects)
×
78
                push!(const_results, const_result)
×
79
                any_const_result |= const_result !== nothing
×
80
                edge === nothing || push!(edges, edge)
×
81
                this_rt = tmerge(this_rt, rt)
×
82
                if bail_out_call(interp, this_rt, sv)
×
83
                    break
×
84
                end
85
            end
×
86
            this_conditional = ignorelimited(this_rt)
×
87
            this_rt = widenwrappedconditional(this_rt)
×
88
        else
89
            result = abstract_call_method(interp, method, sig, match.sparams, multiple_matches, si, sv)
22,302,933✔
90
            (; rt, edge, effects) = result
22,302,933✔
91
            this_conditional = ignorelimited(rt)
44,411,966✔
92
            this_rt = widenwrappedconditional(rt)
22,302,933✔
93
            # try constant propagation with argtypes for this match
94
            # this is in preparation for inlining, or improving the return result
95
            this_argtypes = isa(matches, MethodMatches) ? argtypes : matches.applicable_argtypes[i]
23,196,700✔
96
            this_arginfo = ArgInfo(fargs, this_argtypes)
43,837,778✔
97
            const_call_result = abstract_call_method_with_const_args(interp,
22,302,933✔
98
                result, f, this_arginfo, si, match, sv)
99
            const_result = nothing
15,368✔
100
            if const_call_result !== nothing
22,302,919✔
101
                this_const_conditional = ignorelimited(const_call_result.rt)
16,315,375✔
102
                this_const_rt = widenwrappedconditional(const_call_result.rt)
8,157,796✔
103
                # return type of const-prop' inference can be wider than that of non const-prop' inference
104
                # e.g. in cases when there are cycles but cached result is still accurate
105
                if this_const_rt โŠ‘โ‚š this_rt
8,157,796✔
106
                    this_conditional = this_const_conditional
8,153,184✔
107
                    this_rt = this_const_rt
7,016✔
108
                    (; effects, const_result, edge) = const_call_result
8,153,184✔
109
                else
110
                    add_remark!(interp, sv, "[constprop] Discarded because the result was wider than inference")
×
111
                end
112
            end
113
            all_effects = merge_effects(all_effects, effects)
44,155,850✔
114
            push!(const_results, const_result)
30,456,103✔
115
            any_const_result |= const_result !== nothing
22,302,919✔
116
            edge === nothing || push!(edges, edge)
44,554,859✔
117
        end
118
        @assert !(this_conditional isa Conditional || this_rt isa MustAlias) "invalid lattice element returned from inter-procedural context"
22,302,919✔
119
        seen += 1
22,302,919✔
120
        rettype = tmerge(๐•ƒโ‚š, rettype, this_rt)
22,302,919✔
121
        if has_conditional(๐•ƒโ‚š, sv) && this_conditional !== Bottom && is_lattice_bool(๐•ƒโ‚š, rettype) && fargs !== nothing
22,302,919✔
122
            if conditionals === nothing
2,685,439✔
123
                conditionals = Any[Bottom for _ in 1:length(argtypes)],
7,473,165✔
124
                               Any[Bottom for _ in 1:length(argtypes)]
125
            end
126
            for i = 1:length(argtypes)
5,370,878✔
127
                cnd = conditional_argtype(this_conditional, sig, argtypes, i)
15,025,390✔
128
                conditionals[1][i] = tmerge(conditionals[1][i], cnd.thentype)
7,543,558✔
129
                conditionals[2][i] = tmerge(conditionals[2][i], cnd.elsetype)
7,543,558✔
130
            end
12,401,677✔
131
        end
132
        if bail_out_call(interp, InferenceLoopState(sig, rettype, all_effects), sv)
22,405,897✔
133
            add_remark!(interp, sv, "Call inference reached maximally imprecise information. Bailing on.")
104✔
134
            break
505,709✔
135
        end
136
    end
21,797,210✔
137

138
    if any_const_result && seen == napplicable
21,458,089✔
139
        @assert napplicable == nmatches(info) == length(const_results)
8,105,872✔
140
        info = ConstCallInfo(info, const_results)
8,140,813✔
141
    end
142

143
    if seen โ‰  napplicable
21,458,089✔
144
        # there is unanalyzed candidate, widen type and effects to the top
145
        rettype = Any
1✔
146
        all_effects = Effects()
162,403✔
147
    elseif isa(matches, MethodMatches) ? (!matches.fullmatch || any_ambig(matches)) :
42,155,843✔
148
            (!all(matches.fullmatches) || any_ambig(matches))
149
        # Account for the fact that we may encounter a MethodError with a non-covered or ambiguous signature.
150
        all_effects = Effects(all_effects; nothrow=false)
162,902✔
151
    end
152

153
    rettype = from_interprocedural!(interp, rettype, sv, arginfo, conditionals)
24,115,408✔
154

155
    # Also considering inferring the compilation signature for this method, so
156
    # it is available to the compiler in case it ends up needing it.
157
    if (isa(sv, InferenceState) && infer_compilation_signature(interp) &&
21,445,432✔
158
        (1 == seen == napplicable) && rettype !== Any && rettype !== Bottom &&
159
        !is_removable_if_unused(all_effects))
160
        match = applicable[1]::MethodMatch
12,616,763✔
161
        method = match.method
12,616,763✔
162
        sig = match.spec_types
12,616,763✔
163
        mi = specialize_method(match; preexisting=true)
12,616,763✔
164
        if mi !== nothing && !const_prop_methodinstance_heuristic(interp, mi, arginfo, sv)
12,616,763✔
165
            csig = get_compileable_sig(method, sig, match.sparams)
1,551,960✔
166
            if csig !== nothing && csig !== sig
777,600✔
167
                abstract_call_method(interp, method, csig, match.sparams, multiple_matches, StmtInfo(false), sv)
49,931✔
168
            end
169
        end
170
    end
171

172
    if call_result_unused(si) && !(rettype === Bottom)
21,458,089✔
173
        add_remark!(interp, sv, "Call result type was widened because the return value is unused")
553✔
174
        # We're mainly only here because the optimizer might want this code,
175
        # but we ourselves locally don't typically care about it locally
176
        # (beyond checking if it always throws).
177
        # So avoid adding an edge, since we don't want to bother attempting
178
        # to improve our result even if it does change (to always throw),
179
        # and avoid keeping track of a more complex result type.
180
        rettype = Any
553✔
181
    end
182
    add_call_backedges!(interp, rettype, all_effects, edges, matches, atype, sv)
21,753,558✔
183
    if isa(sv, InferenceState)
15,337✔
184
        # TODO (#48913) implement a proper recursion handling for irinterp:
185
        # This works just because currently the `:terminate` condition guarantees that
186
        # irinterp doesn't fail into unresolved cycles, but it's not a good solution.
187
        # We should revisit this once we have a better story for handling cycles in irinterp.
188
        if !isempty(sv.pclimitations) # remove self, if present
21,814,951✔
189
            delete!(sv.pclimitations, sv)
369,079✔
190
            for caller in callers_in_cycle(sv)
707,492✔
191
                delete!(sv.pclimitations, caller)
22,580✔
192
            end
28,695✔
193
        end
194
    end
195
    return CallMeta(rettype, all_effects, info)
21,458,089✔
196
end
197

198
struct FailedMethodMatch
199
    reason::String
658,579✔
200
end
201

202
struct MethodMatches
203
    applicable::Vector{Any}
21,162,913✔
204
    info::MethodMatchInfo
205
    valid_worlds::WorldRange
206
    mt::MethodTable
207
    fullmatch::Bool
208
end
209
any_ambig(info::MethodMatchInfo) = info.results.ambig
21,721,322✔
210
any_ambig(m::MethodMatches) = any_ambig(m.info)
20,860,295✔
211

212
struct UnionSplitMethodMatches
213
    applicable::Vector{Any}
295,472✔
214
    applicable_argtypes::Vector{Vector{Any}}
215
    info::UnionSplitInfo
216
    valid_worlds::WorldRange
217
    mts::Vector{MethodTable}
218
    fullmatches::Vector{Bool}
219
end
220
any_ambig(m::UnionSplitMethodMatches) = any(any_ambig, m.info.matches)
273,089✔
221

222
function find_matching_methods(๐•ƒ::AbstractLattice,
22,116,862✔
223
                               argtypes::Vector{Any}, @nospecialize(atype), method_table::MethodTableView,
224
                               max_union_splitting::Int, max_methods::Int)
225
    # NOTE this is valid as far as any "constant" lattice element doesn't represent `Union` type
226
    if 1 < unionsplitcost(๐•ƒ, argtypes) <= max_union_splitting
22,116,862✔
227
        split_argtypes = switchtupleunion(๐•ƒ, argtypes)
299,763✔
228
        infos = MethodMatchInfo[]
299,763✔
229
        applicable = Any[]
299,763✔
230
        applicable_argtypes = Vector{Any}[] # arrays like `argtypes`, including constants, for each match
299,763✔
231
        valid_worlds = WorldRange()
×
232
        mts = MethodTable[]
299,763✔
233
        fullmatches = Bool[]
299,763✔
234
        for i in 1:length(split_argtypes)
599,526✔
235
            arg_n = split_argtypes[i]::Vector{Any}
921,980✔
236
            sig_n = argtypes_to_type(arg_n)
921,980✔
237
            mt = ccall(:jl_method_table_for, Any, (Any,), sig_n)
921,980✔
238
            mt === nothing && return FailedMethodMatch("Could not identify method table for call")
921,980✔
239
            mt = mt::MethodTable
921,980✔
240
            matches = findall(sig_n, method_table; limit = max_methods)
921,982✔
241
            if matches === nothing
921,980✔
242
                return FailedMethodMatch("For one of the union split cases, too many methods matched")
4,291✔
243
            end
244
            push!(infos, MethodMatchInfo(matches))
917,689✔
245
            for m in matches
1,828,415✔
246
                push!(applicable, m)
936,128✔
247
                push!(applicable_argtypes, arg_n)
936,128✔
248
            end
961,530✔
249
            valid_worlds = intersect(valid_worlds, matches.valid_worlds)
917,689✔
250
            thisfullmatch = any(match::MethodMatch->match.fully_covers, matches)
1,899,202✔
251
            found = false
×
252
            for (i, mtโ€ฒ) in enumerate(mts)
1,539,208✔
253
                if mtโ€ฒ === mt
621,774✔
254
                    fullmatches[i] &= thisfullmatch
619,928✔
255
                    found = true
×
256
                    break
619,928✔
257
                end
258
            end
1,846✔
259
            if !found
917,689✔
260
                push!(mts, mt)
297,761✔
261
                push!(fullmatches, thisfullmatch)
297,761✔
262
            end
263
        end
1,539,906✔
264
        return UnionSplitMethodMatches(applicable,
295,472✔
265
                                       applicable_argtypes,
266
                                       UnionSplitInfo(infos),
267
                                       valid_worlds,
268
                                       mts,
269
                                       fullmatches)
270
    else
271
        mt = ccall(:jl_method_table_for, Any, (Any,), atype)
21,817,099✔
272
        if mt === nothing
21,817,099✔
273
            return FailedMethodMatch("Could not identify method table for call")
23✔
274
        end
275
        mt = mt::MethodTable
21,817,076✔
276
        matches = findall(atype, method_table; limit = max_methods)
21,826,533✔
277
        if matches === nothing
21,817,076✔
278
            # this means too many methods matched
279
            # (assume this will always be true, so we don't compute / update valid age in this case)
280
            return FailedMethodMatch("Too many methods matched")
654,163✔
281
        end
282
        fullmatch = any(match::MethodMatch->match.fully_covers, matches)
43,322,423✔
283
        return MethodMatches(matches.matches,
21,162,913✔
284
                             MethodMatchInfo(matches),
285
                             matches.valid_worlds,
286
                             mt,
287
                             fullmatch)
288
    end
289
end
290

291
"""
292
    from_interprocedural!(interp::AbstractInterpreter, rt, sv::AbsIntState,
293
                          arginfo::ArgInfo, maybecondinfo) -> newrt
294

295
Converts inter-procedural return type `rt` into a local lattice element `newrt`,
296
that is appropriate in the context of current local analysis frame `sv`, especially:
297
- unwraps `rt::LimitedAccuracy` and collects its limitations into the current frame `sv`
298
- converts boolean `rt` to new boolean `newrt` in a way `newrt` can propagate extra conditional
299
  refinement information, e.g. translating `rt::InterConditional` into `newrt::Conditional`
300
  that holds a type constraint information about a variable in `sv`
301

302
This function _should_ be used wherever we propagate results returned from
303
`abstract_call_method` or `abstract_call_method_with_const_args`.
304

305
When `maybecondinfo !== nothing`, this function also tries extra conditional argument type refinement.
306
In such cases `maybecondinfo` should be either of:
307
- `maybecondinfo::Tuple{Vector{Any},Vector{Any}}`: precomputed argument type refinement information
308
- method call signature tuple type
309
When we deal with multiple `MethodMatch`es, it's better to precompute `maybecondinfo` by
310
`tmerge`ing argument signature type of each method call.
311
"""
312
function from_interprocedural!(interp::AbstractInterpreter, @nospecialize(rt), sv::AbsIntState,
21,467,574✔
313
                               arginfo::ArgInfo, @nospecialize(maybecondinfo))
314
    rt = collect_limitations!(rt, sv)
42,764,370✔
315
    if isa(rt, InterMustAlias)
21,467,574✔
316
        rt = from_intermustalias(rt, arginfo)
×
317
    elseif is_lattice_bool(ipo_lattice(interp), rt)
21,693,521✔
318
        if maybecondinfo === nothing
2,780,492✔
319
            rt = widenconditional(rt)
127,902✔
320
        else
321
            rt = from_interconditional(typeinf_lattice(interp), rt, sv, arginfo, maybecondinfo)
2,652,590✔
322
        end
323
    end
324
    @assert !(rt isa InterConditional || rt isa InterMustAlias) "invalid lattice element returned from inter-procedural context"
21,467,574✔
325
    return rt
21,467,574✔
326
end
327

328
function collect_limitations!(@nospecialize(typ), sv::InferenceState)
121,047✔
329
    if isa(typ, LimitedAccuracy)
134,126,327✔
330
        union!(sv.pclimitations, typ.causes)
623,876✔
331
        return typ.typ
623,876✔
332
    end
333
    return typ
133,502,451✔
334
end
335

336
function from_intermustalias(rt::InterMustAlias, arginfo::ArgInfo)
×
337
    fargs = arginfo.fargs
×
338
    if fargs !== nothing && 1 โ‰ค rt.slot โ‰ค length(fargs)
×
339
        arg = fargs[rt.slot]
×
340
        if isa(arg, SlotNumber)
×
341
            argtyp = widenslotwrapper(arginfo.argtypes[rt.slot])
×
342
            if rt.vartyp โŠ‘ argtyp
×
343
                return MustAlias(arg, rt.vartyp, rt.fldidx, rt.fldtyp)
×
344
            else
345
                # TODO optimize this case?
346
            end
×
347
        end
348
    end
349
    return widenmustalias(rt)
×
350
end
351

352
function from_interconditional(๐•ƒแตข::AbstractLattice, @nospecialize(rt), sv::AbsIntState,
2,652,590✔
353
                               arginfo::ArgInfo, @nospecialize(maybecondinfo))
354
    has_conditional(๐•ƒแตข, sv) || return widenconditional(rt)
×
355
    (; fargs, argtypes) = arginfo
2,652,590✔
356
    fargs === nothing && return widenconditional(rt)
2,652,590✔
357
    slot = 0
2,652,590✔
358
    alias = nothing
×
359
    thentype = elsetype = Any
×
360
    condval = maybe_extract_const_bool(rt)
2,652,590✔
361
    for i in 1:length(fargs)
5,305,180✔
362
        # find the first argument which supports refinement,
363
        # and intersect all equivalent arguments with it
364
        argtyp = argtypes[i]
7,458,158✔
365
        if alias === nothing
7,458,158✔
366
            arg = ssa_def_slot(fargs[i], sv)
7,458,158✔
367
            if isa(arg, SlotNumber) && widenslotwrapper(argtyp) isa Type
7,462,333✔
368
                old = argtyp
1,804,947✔
369
                id = slot_id(arg)
1,804,947✔
370
            elseif argtyp isa MustAlias
5,653,211✔
371
                old = argtyp.fldtyp
×
372
                id = argtyp.slot
×
373
            else
374
                continue # unlikely to refine
7,458,158✔
375
            end
376
        elseif argtyp isa MustAlias && issubalias(argtyp, alias)
×
377
            arg = nothing
×
378
            old = alias.fldtyp
×
379
            id = alias.slot
×
380
        else
381
            continue
×
382
        end
383
        if slot == 0 || id == slot
1,805,199✔
384
            if isa(maybecondinfo, Tuple{Vector{Any},Vector{Any}})
1,804,695✔
385
                # if we have already computed argument refinement information, apply that now to get the result
386
                new_thentype = maybecondinfo[1][i]
1,804,673✔
387
                new_elsetype = maybecondinfo[2][i]
1,804,673✔
388
            else
389
                # otherwise compute it on the fly
390
                cnd = conditional_argtype(rt, maybecondinfo, argtypes, i)
44✔
391
                new_thentype = cnd.thentype
22✔
392
                new_elsetype = cnd.elsetype
22✔
393
            end
394
            if condval === false
1,804,695✔
395
                thentype = Bottom
123,164✔
396
            elseif โŠ‘(๐•ƒแตข, new_thentype, thentype)
1,681,531✔
397
                thentype = new_thentype
1,681,531✔
398
            else
399
                thentype = tmeet(๐•ƒแตข, thentype, widenconst(new_thentype))
×
400
            end
401
            if condval === true
1,804,695✔
402
                elsetype = Bottom
114,848✔
403
            elseif โŠ‘(๐•ƒแตข, new_elsetype, elsetype)
1,689,847✔
404
                elsetype = new_elsetype
1,689,847✔
405
            else
406
                elsetype = tmeet(๐•ƒแตข, elsetype, widenconst(new_elsetype))
×
407
            end
408
            if (slot > 0 || condval !== false) && โ‹ค(๐•ƒแตข, thentype, old)
3,609,390✔
409
                slot = id
×
410
                if !(arg isa SlotNumber) && argtyp isa MustAlias
19,974✔
411
                    alias = argtyp
×
412
                end
413
            elseif (slot > 0 || condval !== true) && โ‹ค(๐•ƒแตข, elsetype, old)
3,569,442✔
414
                slot = id
×
415
                if !(arg isa SlotNumber) && argtyp isa MustAlias
3,519✔
416
                    alias = argtyp
×
417
                end
418
            else # reset: no new useful information for this slot
419
                slot = 0
×
420
                alias = nothing
×
421
                thentype = elsetype = Any
×
422
            end
423
        end
424
    end
12,263,726✔
425
    if thentype === Bottom && elsetype === Bottom
2,652,590✔
426
        return Bottom # accidentally proved this call to be dead / throw !
×
427
    elseif slot > 0
2,652,590✔
428
        if alias !== nothing
23,493✔
429
            return form_mustalias_conditional(alias, thentype, elsetype)
×
430
        end
431
        return Conditional(slot, thentype, elsetype) # record a Conditional improvement to this slot
23,493✔
432
    end
433
    return widenconditional(rt)
2,629,097✔
434
end
435

436
function conditional_argtype(@nospecialize(rt), @nospecialize(sig), argtypes::Vector{Any}, i::Int)
5,793✔
437
    if isa(rt, InterConditional) && rt.slot == i
7,543,580✔
438
        return rt
61,726✔
439
    else
440
        thentype = elsetype = tmeet(widenslotwrapper(argtypes[i]), fieldtype(sig, i))
7,482,563✔
441
        condval = maybe_extract_const_bool(rt)
7,481,854✔
442
        condval === true && (elsetype = Bottom)
7,481,854✔
443
        condval === false && (thentype = Bottom)
7,481,854✔
444
        return InterConditional(i, thentype, elsetype)
7,481,854✔
445
    end
446
end
447

448
function add_call_backedges!(interp::AbstractInterpreter, @nospecialize(rettype), all_effects::Effects,
21,458,089✔
449
    edges::Vector{MethodInstance}, matches::Union{MethodMatches,UnionSplitMethodMatches}, @nospecialize(atype),
450
    sv::AbsIntState)
451
    # don't bother to add backedges when both type and effects information are already
452
    # maximized to the top since a new method couldn't refine or widen them anyway
453
    if rettype === Any
21,458,089✔
454
        # ignore the `:nonoverlayed` property if `interp` doesn't use overlayed method table
455
        # since it will never be tainted anyway
456
        if !isoverlayed(method_table(interp))
684✔
457
            all_effects = Effects(all_effects; nonoverlayed=false)
1,866,241✔
458
        end
459
        all_effects === Effects() && return nothing
1,866,457✔
460
    end
461
    for edge in edges
20,596,868✔
462
        add_backedge!(sv, edge)
21,352,811✔
463
    end
41,704,914✔
464
    # also need an edge to the method table in case something gets
465
    # added that did not intersect with any existing method
466
    if isa(matches, MethodMatches)
15,252✔
467
        matches.fullmatch || add_mt_backedge!(sv, matches.mt, atype)
20,453,010✔
468
    else
469
        for (thisfullmatch, mt) in zip(matches.fullmatches, matches.mts)
406,288✔
470
            thisfullmatch || add_mt_backedge!(sv, mt, atype)
208,570✔
471
        end
205,282✔
472
    end
473
    return nothing
20,566,318✔
474
end
475

476
const RECURSION_UNUSED_MSG = "Bounded recursion detected with unused result. Annotated return type may be wider than true result."
477
const RECURSION_MSG = "Bounded recursion detected. Call was widened to force convergence."
478
const RECURSION_MSG_HARDLIMIT = "Bounded recursion detected under hardlimit. Call was widened to force convergence."
479

480
function abstract_call_method(interp::AbstractInterpreter,
22,362,349✔
481
                              method::Method, @nospecialize(sig), sparams::SimpleVector,
482
                              hardlimit::Bool, si::StmtInfo, sv::AbsIntState)
483
    if method.name === :depwarn && isdefined(Main, :Base) && method.module === Main.Base
22,362,349✔
484
        add_remark!(interp, sv, "Refusing to infer into `depwarn`")
×
485
        return MethodCallResult(Any, false, false, nothing, Effects())
23✔
486
    end
487
    sigtuple = unwrap_unionall(sig)
22,484,574✔
488
    sigtuple isa DataType || return MethodCallResult(Any, false, false, nothing, Effects())
22,362,326✔
489

490
    if is_nospecializeinfer(method)
44,717,526✔
491
        sig = get_nospecializeinfer_sig(method, sig, sparams)
14,252✔
492
    end
493

494
    # Limit argument type tuple growth of functions:
495
    # look through the parents list to see if there's a call to the same method
496
    # and from the same method.
497
    # Returns the topmost occurrence of that repeated edge.
498
    edgecycle = edgelimited = false
22,362,326✔
499
    topmost = nothing
15,449✔
500

501
    for svโ€ฒ in AbsIntStackUnwind(sv)
165,706,172✔
502
        infmi = frame_instance(svโ€ฒ)
331,611,080✔
503
        if method === infmi.def
165,805,540✔
504
            if infmi.specTypes::Type == sig::Type
519,216✔
505
                # avoid widening when detecting self-recursion
506
                # TODO: merge call cycle and return right away
507
                if call_result_unused(si)
48,275✔
508
                    add_remark!(interp, sv, RECURSION_UNUSED_MSG)
1✔
509
                    # since we don't use the result (typically),
510
                    # we have a self-cycle in the call-graph, but not in the inference graph (typically):
511
                    # break this edge now (before we record it) by returning early
512
                    # (non-typically, this means that we lose the ability to detect a guaranteed StackOverflow in some cases)
513
                    return MethodCallResult(Any, true, true, nothing, Effects())
6,933✔
514
                end
515
                topmost = nothing
27✔
516
                edgecycle = true
27✔
517
                break
41,342✔
518
            end
519
            topmost === nothing || continue
470,941✔
520
            if edge_matches_sv(interp, svโ€ฒ, method, sig, sparams, hardlimit, sv)
745,028✔
521
                topmost = svโ€ฒ
×
522
                edgecycle = true
×
523
            end
524
        end
525
    end
165,757,265✔
526
    washardlimit = hardlimit
22,355,393✔
527

528
    if topmost !== nothing
22,355,393✔
529
        msig = unwrap_unionall(method.sig)::DataType
224,272✔
530
        spec_len = length(msig.parameters) + 1
224,272✔
531
        mi = frame_instance(sv)
224,272✔
532

533
        if isdefined(method, :recursion_relation)
224,272✔
534
            # We don't require the recursion_relation to be transitive, so
535
            # apply a hard limit
536
            hardlimit = true
×
537
        end
538

539
        if method === mi.def
224,272✔
540
            # Under direct self-recursion, permit much greater use of reducers.
541
            # here we assume that complexity(specTypes) :>= complexity(sig)
542
            comparison = mi.specTypes
36,156✔
543
            l_comparison = length((unwrap_unionall(comparison)::DataType).parameters)
36,300✔
544
            spec_len = max(spec_len, l_comparison)
36,156✔
545
        elseif !hardlimit && isa(topmost, InferenceState)
188,116✔
546
            # Without a hardlimit, permit use of reducers too.
547
            comparison = frame_instance(topmost).specTypes
66,560✔
548
            # n.b. currently don't allow vararg reducers
549
            #l_comparison = length((unwrap_unionall(comparison)::DataType).parameters)
550
            #spec_len = max(spec_len, l_comparison)
551
        else
552
            comparison = method.sig
121,556✔
553
        end
554

555
        # see if the type is actually too big (relative to the caller), and limit it if required
556
        newsig = limit_type_size(sig, comparison, hardlimit ? comparison : mi.specTypes, InferenceParams(interp).tuple_complexity_limit_depth, spec_len)
314,087✔
557

558
        if newsig !== sig
224,272✔
559
            # continue inference, but note that we've limited parameter complexity
560
            # on this call (to ensure convergence), so that we don't cache this result
561
            if call_result_unused(si)
176,087✔
562
                add_remark!(interp, sv, RECURSION_UNUSED_MSG)
×
563
                # if we don't (typically) actually care about this result,
564
                # don't bother trying to examine some complex abstract signature
565
                # since it's very unlikely that we'll try to inline this,
566
                # or want make an invoke edge to its calling convention return type.
567
                # (non-typically, this means that we lose the ability to detect a guaranteed StackOverflow in some cases)
568
                return MethodCallResult(Any, true, true, nothing, Effects())
637✔
569
            end
570
            add_remark!(interp, sv, washardlimit ? RECURSION_MSG_HARDLIMIT : RECURSION_MSG)
175,450✔
571
            # TODO (#48913) implement a proper recursion handling for irinterp:
572
            # This works just because currently the `:terminate` condition guarantees that
573
            # irinterp doesn't fail into unresolved cycles, but it's not a good solution.
574
            # We should revisit this once we have a better story for handling cycles in irinterp.
575
            if isa(topmost, InferenceState)
175,450✔
576
                parentframe = frame_parent(topmost)
175,450✔
577
                if isa(sv, InferenceState) && isa(parentframe, InferenceState)
175,450✔
578
                    poison_callstack!(sv, parentframe === nothing ? topmost : parentframe)
136,966✔
579
                end
580
            end
581
            # n.b. this heuristic depends on the non-local state, so we must record the limit later
582
            sig = newsig
×
583
            sparams = svec()
175,450✔
584
            edgelimited = true
×
585
        end
586
    end
587

588
    # if sig changed, may need to recompute the sparams environment
589
    if isa(method.sig, UnionAll) && isempty(sparams)
22,354,756✔
590
        recomputed = ccall(:jl_type_intersection_with_env, Any, (Any, Any), sig, method.sig)::SimpleVector
163,646✔
591
        #@assert recomputed[1] !== Bottom
592
        # We must not use `sig` here, since that may re-introduce structural complexity that
593
        # our limiting heuristic sought to eliminate. The alternative would be to not increment depth over covariant contexts,
594
        # but we prefer to permit inference of tuple-destructuring, so we don't do that right now
595
        # For example, with a signature such as `Tuple{T, Ref{T}} where {T <: S}`
596
        # we might want to limit this to `Tuple{S, Ref}`, while type-intersection can instead give us back the original type
597
        # (which moves `S` back up to a lower comparison depth)
598
        # Optionally, we could try to drive this to a fixed point, but I think this is getting too complex,
599
        # and this would only cause more questions and more problems
600
        # (the following is only an example, most of the statements are probable in the wrong order):
601
        #     newsig = sig
602
        #     seen = IdSet()
603
        #     while !(newsig in seen)
604
        #         push!(seen, newsig)
605
        #         lsig = length((unwrap_unionall(sig)::DataType).parameters)
606
        #         newsig = limit_type_size(newsig, sig, sv.linfo.specTypes, InferenceParams(interp).tuple_complexity_limit_depth, lsig)
607
        #         recomputed = ccall(:jl_type_intersection_with_env, Any, (Any, Any), newsig, method.sig)::SimpleVector
608
        #         newsig = recomputed[2]
609
        #     end
610
        #     sig = ?
611
        sparams = recomputed[2]::SimpleVector
163,646✔
612
    end
613

614
    (; rt, edge, effects) = typeinf_edge(interp, method, sig, sparams, sv)
22,354,756✔
615

616
    if edge === nothing
22,354,756✔
617
        edgecycle = edgelimited = true
28✔
618
    end
619

620
    # we look for the termination effect override here as well, since the :terminates effect
621
    # may have been tainted due to recursion at this point even if it's overridden
622
    if is_effect_overridden(sv, :terminates_globally)
22,557,904✔
623
        # this frame is known to terminate
624
        effects = Effects(effects, terminates=true)
106,285✔
625
    elseif is_effect_overridden(method, :terminates_globally)
22,248,471✔
626
        # this edge is known to terminate
627
        effects = Effects(effects; terminates=true)
79,017✔
628
    elseif edgecycle
22,169,454✔
629
        # Some sort of recursion was detected.
630
        if edge !== nothing && !edgelimited && !is_edge_recursed(edge, sv)
759,741✔
631
            # no `MethodInstance` cycles -- don't taint :terminate
632
        else
633
            # we cannot guarantee that the call will terminate
634
            effects = Effects(effects; terminates=false)
223,266✔
635
        end
636
    end
637

638
    return MethodCallResult(rt, edgecycle, edgelimited, edge, effects)
22,354,756✔
639
end
640

641
function edge_matches_sv(interp::AbstractInterpreter, frame::AbsIntState,
372,514✔
642
                         method::Method, @nospecialize(sig), sparams::SimpleVector,
643
                         hardlimit::Bool, sv::AbsIntState)
644
    # The `method_for_inference_heuristics` will expand the given method's generator if
645
    # necessary in order to retrieve this field from the generated `CodeInfo`, if it exists.
646
    # The other `CodeInfo`s we inspect will already have this field inflated, so we just
647
    # access it directly instead (to avoid regeneration).
648
    world = get_world_counter(interp)
372,514✔
649
    callee_method2 = method_for_inference_heuristics(method, sig, sparams, world) # Union{Method, Nothing}
372,514✔
650

651
    inf_method2 = method_for_inference_limit_heuristics(frame) # limit only if user token match
372,514✔
652
    inf_method2 isa Method || (inf_method2 = nothing)
372,514✔
653
    if callee_method2 !== inf_method2
372,514✔
654
        return false
×
655
    end
656
    if !hardlimit || InferenceParams(interp).ignore_recursion_hardlimit
507,140✔
657
        # if this is a soft limit,
658
        # also inspect the parent of this edge,
659
        # to see if they are the same Method as sv
660
        # in which case we'll need to ensure it is convergent
661
        # otherwise, we don't
662

663
        # check in the cycle list first
664
        # all items in here are mutual parents of all others
665
        if !any(p::AbsIntState->matches_sv(p, sv), callers_in_cycle(frame))
361,073✔
666
            let parent = frame_parent(frame)
235,528✔
667
                parent !== nothing || return false
241,626✔
668
                (is_cached(parent) || frame_parent(parent) !== nothing) || return false
291,078✔
669
                matches_sv(parent, sv) || return false
370,230✔
670
            end
671
        end
672

673
        # If the method defines a recursion relation, give it a chance
674
        # to tell us that this recursion is actually ok.
675
        if isdefined(method, :recursion_relation)
90,990✔
676
            if Core._apply_pure(method.recursion_relation, Any[method, callee_method2, sig, frame_instance(frame).specTypes])
×
677
                return false
×
678
            end
679
        end
680
    end
681
    return true
225,616✔
682
end
683

684
# This function is used for computing alternate limit heuristics
685
function method_for_inference_heuristics(method::Method, @nospecialize(sig), sparams::SimpleVector, world::UInt)
372,514✔
686
    if isdefined(method, :generator) && !(method.generator isa Core.GeneratedFunctionStub) && may_invoke_generator(method, sig, sparams)
372,514✔
687
        method_instance = specialize_method(method, sig, sparams)
238✔
688
        if isa(method_instance, MethodInstance)
×
689
            cinfo = get_staged(method_instance, world)
238✔
690
            if isa(cinfo, CodeInfo)
238✔
691
                method2 = cinfo.method_for_inference_limit_heuristics
234✔
692
                if method2 isa Method
234✔
693
                    return method2
×
694
                end
695
            end
696
        end
697
    end
698
    return nothing
372,514✔
699
end
700

701
function matches_sv(parent::AbsIntState, sv::AbsIntState)
28✔
702
    sv_method2 = method_for_inference_limit_heuristics(sv) # limit only if user token match
272,065✔
703
    sv_method2 isa Method || (sv_method2 = nothing)
272,065✔
704
    parent_method2 = method_for_inference_limit_heuristics(parent) # limit only if user token match
272,065✔
705
    parent_method2 isa Method || (parent_method2 = nothing)
272,065✔
706
    return frame_instance(parent).def === frame_instance(sv).def && sv_method2 === parent_method2
453,140✔
707
end
708

709
function is_edge_recursed(edge::MethodInstance, caller::AbsIntState)
×
710
    return any(AbsIntStackUnwind(caller)) do sv::AbsIntState
984,011✔
711
        return edge === frame_instance(sv)
493,895✔
712
    end
713
end
714

715
function is_method_recursed(method::Method, caller::AbsIntState)
×
716
    return any(AbsIntStackUnwind(caller)) do sv::AbsIntState
×
717
        return method === frame_instance(sv).def
×
718
    end
719
end
720

721
function is_constprop_edge_recursed(edge::MethodInstance, caller::AbsIntState)
1✔
722
    return any(AbsIntStackUnwind(caller)) do sv::AbsIntState
23,487✔
723
        return edge === frame_instance(sv) && is_constproped(sv)
225,233✔
724
    end
725
end
726

727
function is_constprop_method_recursed(method::Method, caller::AbsIntState)
×
728
    return any(AbsIntStackUnwind(caller)) do sv::AbsIntState
3,050✔
729
        return method === frame_instance(sv).def && is_constproped(sv)
23,052✔
730
    end
731
end
732

733
# keeps result and context information of abstract_method_call, which will later be used for
734
# backedge computation, and concrete evaluation or constant-propagation
735
struct MethodCallResult
736
    rt
737
    edgecycle::Bool
738
    edgelimited::Bool
739
    edge::Union{Nothing,MethodInstance}
740
    effects::Effects
741
    function MethodCallResult(@nospecialize(rt),
192✔
742
                              edgecycle::Bool,
743
                              edgelimited::Bool,
744
                              edge::Union{Nothing,MethodInstance},
745
                              effects::Effects)
746
        return new(rt, edgecycle, edgelimited, edge, effects)
22,355,103✔
747
    end
748
end
749

750
struct InvokeCall
751
    types     # ::Type
752
    lookupsig # ::Type
753
    InvokeCall(@nospecialize(types), @nospecialize(lookupsig)) = new(types, lookupsig)
9,446✔
754
end
755

756
struct ConstCallResults
757
    rt::Any
758
    const_result::ConstResult
759
    effects::Effects
760
    edge::MethodInstance
761
    function ConstCallResults(
×
762
        @nospecialize(rt),
763
        const_result::ConstResult,
764
        effects::Effects,
765
        edge::MethodInstance)
766
        return new(rt, const_result, effects, edge)
8,172,995✔
767
    end
768
end
769

770
function abstract_call_method_with_const_args(interp::AbstractInterpreter,
44,615,390✔
771
    result::MethodCallResult, @nospecialize(f), arginfo::ArgInfo, si::StmtInfo,
772
    match::MethodMatch, sv::AbsIntState, invokecall::Union{Nothing,InvokeCall}=nothing)
773

774
    if !const_prop_enabled(interp, sv, match)
66,927,808✔
775
        return nothing
11,165✔
776
    end
777
    if bail_out_const_call(interp, result, si)
28,323,982✔
778
        add_remark!(interp, sv, "[constprop] No more information to be gained")
55✔
779
        return nothing
1,000,918✔
780
    end
781
    eligibility = concrete_eval_eligible(interp, f, result, arginfo, sv)
21,301,780✔
782
    concrete_eval_result = nothing
15,391✔
783
    if eligibility === :concrete_eval
21,300,335✔
784
        concrete_eval_result = concrete_eval_call(interp, f, result, arginfo, sv, invokecall)
1,444,645✔
785
        # if we don't inline the result of this concrete evaluation,
786
        # give const-prop' a chance to inline a better method body
787
        if !may_optimize(interp) || (
1,487,752✔
788
            may_inline_concrete_result(concrete_eval_result.const_result::ConcreteResult) ||
789
            concrete_eval_result.rt === Bottom) # unless this call deterministically throws and thus is non-inlineable
790
            return concrete_eval_result
1,422,662✔
791
        end
792
        # TODO allow semi-concrete interp for this call?
793
    end
794
    mi = maybe_get_const_prop_profitable(interp, result, f, arginfo, si, match, sv)
19,877,673✔
795
    mi === nothing && return concrete_eval_result
19,877,673✔
796
    if is_constprop_recursed(result, mi, sv)
6,751,047✔
797
        add_remark!(interp, sv, "[constprop] Edge cycle encountered")
×
798
        return nothing
3,356✔
799
    end
800
    # try semi-concrete evaluation
801
    if eligibility === :semi_concrete_eval
6,728,364✔
802
        irinterp_result = semi_concrete_eval_call(interp, mi, result, arginfo, sv)
2,079,865✔
803
        if irinterp_result !== nothing
2,079,858✔
804
            return irinterp_result
1,882,699✔
805
        end
806
    end
807
    # try constant prop'
808
    return const_prop_call(interp, mi, result, arginfo, sv, concrete_eval_result)
4,845,658✔
809
end
810

811
function const_prop_enabled(interp::AbstractInterpreter, sv::AbsIntState, match::MethodMatch)
15,449✔
812
    if !InferenceParams(interp).ipo_constant_propagation
22,312,418✔
813
        add_remark!(interp, sv, "[constprop] Disabled by parameter")
×
814
        return false
×
815
    end
816
    if is_no_constprop(match.method)
22,312,418✔
817
        add_remark!(interp, sv, "[constprop] Disabled by method parameter")
3✔
818
        return false
11,165✔
819
    end
820
    return true
22,301,253✔
821
end
822

823
function bail_out_const_call(interp::AbstractInterpreter, result::MethodCallResult, si::StmtInfo)
15,446✔
824
    if is_removable_if_unused(result.effects)
22,316,512✔
825
        if isa(result.rt, Const) || call_result_unused(si)
13,046,237✔
826
            return true
1,000,918✔
827
        end
828
    end
829
    return false
21,300,335✔
830
end
831

832
function concrete_eval_eligible(interp::AbstractInterpreter,
21,300,335✔
833
    @nospecialize(f), result::MethodCallResult, arginfo::ArgInfo, sv::AbsIntState)
834
    (;effects) = result
21,300,335✔
835
    if inbounds_option() === :off
42,198,137✔
836
        if !is_nothrow(effects)
×
837
            # Disable concrete evaluation in `--check-bounds=no` mode,
838
            # unless it is known to not throw.
839
            return :none
×
840
        end
841
    end
842
    mi = result.edge
21,300,335✔
843
    if mi !== nothing && is_foldable(effects)
28,277,644✔
844
        if f !== nothing && is_all_const_arg(arginfo, #=start=#2)
6,911,333✔
845
            if is_nonoverlayed(interp) || is_nonoverlayed(effects)
610✔
846
                return :concrete_eval
1,444,645✔
847
            end
848
            # disable concrete-evaluation if this function call is tainted by some overlayed
849
            # method since currently there is no easy way to execute overlayed methods
850
            add_remark!(interp, sv, "[constprop] Concrete eval disabled for overlayed methods")
3✔
851
        end
852
        if !any_conditional(arginfo)
21,082,739✔
853
            return :semi_concrete_eval
5,464,330✔
854
        end
855
    end
856
    return :none
14,391,360✔
857
end
858

859
is_all_const_arg(arginfo::ArgInfo, start::Int) = is_all_const_arg(arginfo.argtypes, start::Int)
6,909,636✔
860
function is_all_const_arg(argtypes::Vector{Any}, start::Int)
6,913,412✔
861
    for i = start:length(argtypes)
13,826,084✔
862
        a = widenslotwrapper(argtypes[i])
8,904,644✔
863
        isa(a, Const) || isconstType(a) || issingletontype(a) || return false
14,383,151✔
864
    end
5,423,811✔
865
    return true
1,444,839✔
866
end
867

868
any_conditional(argtypes::Vector{Any}) = any(@nospecialize(x)->isa(x, Conditional), argtypes)
36,701,148✔
869
any_conditional(arginfo::ArgInfo) = any_conditional(arginfo.argtypes)
21,082,739✔
870

871
collect_const_args(arginfo::ArgInfo, start::Int) = collect_const_args(arginfo.argtypes, start)
1,444,645✔
872
function collect_const_args(argtypes::Vector{Any}, start::Int)
1,444,836✔
873
    return Any[ let a = widenslotwrapper(argtypes[i])
1,445,066✔
874
                    isa(a, Const) ? a.val :
2,544,866✔
875
                    isconstType(a) ? (a::DataType).parameters[1] :
876
                    (a::DataType).instance
877
                end for i = start:length(argtypes) ]
878
end
879

880
function concrete_eval_call(interp::AbstractInterpreter,
1,444,645✔
881
    @nospecialize(f), result::MethodCallResult, arginfo::ArgInfo, sv::AbsIntState,
882
    invokecall::Union{InvokeCall,Nothing}=nothing)
883
    args = collect_const_args(arginfo, #=start=#2)
1,444,645✔
884
    if invokecall !== nothing
607✔
885
        # this call should be `invoke`d, rewrite `args` back now
886
        pushfirst!(args, f, invokecall.types)
1,464✔
887
        f = invoke
×
888
    end
889
    world = get_world_counter(interp)
1,444,645✔
890
    edge = result.edge::MethodInstance
1,444,645✔
891
    value = try
1,444,645✔
892
        Core._call_in_world_total(world, f, args...)
1,455,296✔
893
    catch
894
        # The evaluation threw. By :consistent-cy, we're guaranteed this would have happened at runtime
895
        return ConstCallResults(Bottom, ConcreteResult(edge, result.effects), result.effects, edge)
10,651✔
896
    end
897
    return ConstCallResults(Const(value), ConcreteResult(edge, EFFECTS_TOTAL, value), EFFECTS_TOTAL, edge)
1,433,994✔
898
end
899

900
# check if there is a cycle and duplicated inference of `mi`
901
function is_constprop_recursed(result::MethodCallResult, mi::MethodInstance, sv::AbsIntState)
6,487✔
902
    result.edgecycle || return false
13,441,063✔
903
    if result.edgelimited
22,377✔
904
        return is_constprop_method_recursed(mi.def::Method, sv)
3,050✔
905
    else
906
        # if the type complexity limiting didn't decide to limit the call signature (as
907
        # indicated by `result.edgelimited === false`), we can relax the cycle detection
908
        # by comparing `MethodInstance`s and allow inference to propagate different
909
        # constant elements if the recursion is finite over the lattice
910
        return is_constprop_edge_recursed(mi, sv)
19,327✔
911
    end
912
end
913

914
# if there's a possibility we could get a better result with these constant arguments
915
# (hopefully without doing too much work), returns `MethodInstance`, or nothing otherwise
916
function maybe_get_const_prop_profitable(interp::AbstractInterpreter,
19,877,673✔
917
    result::MethodCallResult, @nospecialize(f), arginfo::ArgInfo, si::StmtInfo,
918
    match::MethodMatch, sv::AbsIntState)
919
    method = match.method
19,877,673✔
920
    force = force_const_prop(interp, f, method)
39,747,822✔
921
    force || const_prop_entry_heuristic(interp, result, si, sv) || return nothing
38,227,449✔
922
    nargs::Int = method.nargs
18,007,447✔
923
    method.isva && (nargs -= 1)
18,007,447✔
924
    length(arginfo.argtypes) < nargs && return nothing
18,007,447✔
925
    if !const_prop_argument_heuristic(interp, arginfo, sv)
18,007,099✔
926
        add_remark!(interp, sv, "[constprop] Disabled by argument and rettype heuristics")
5,179✔
927
        return nothing
8,646,046✔
928
    end
929
    all_overridden = is_all_overridden(interp, arginfo, sv)
9,361,053✔
930
    if !force && !const_prop_function_heuristic(interp, f, arginfo, nargs, all_overridden, sv)
9,361,053✔
931
        add_remark!(interp, sv, "[constprop] Disabled by function heuristic")
1,615✔
932
        return nothing
2,309,672✔
933
    end
934
    force |= all_overridden
7,051,381✔
935
    mi = specialize_method(match; preexisting=!force)
7,051,381✔
936
    if mi === nothing
7,051,381✔
937
        add_remark!(interp, sv, "[constprop] Failed to specialize")
×
938
        return nothing
2,497✔
939
    end
940
    mi = mi::MethodInstance
7,048,884✔
941
    if !force && !const_prop_methodinstance_heuristic(interp, mi, arginfo, sv)
7,048,884✔
942
        add_remark!(interp, sv, "[constprop] Disabled by method instance heuristic")
9✔
943
        return nothing
317,164✔
944
    end
945
    return mi
6,731,720✔
946
end
947

948
function const_prop_entry_heuristic(interp::AbstractInterpreter, result::MethodCallResult, si::StmtInfo, sv::AbsIntState)
14,166✔
949
    if call_result_unused(si) && result.edgecycle
18,349,776✔
950
        add_remark!(interp, sv, "[constprop] Disabled by entry heuristic (edgecycle with unused result)")
1✔
951
        return false
9,352✔
952
    end
953
    # check if this return type is improvable (i.e. whether it's possible that with more
954
    # information, we might get a more precise type)
955
    rt = result.rt
18,340,424✔
956
    if isa(rt, Type)
18,340,424✔
957
        # could always be improved to `Const`, `PartialStruct` or just a more precise type,
958
        # unless we're already at `Bottom`
959
        if rt === Bottom
15,863,620✔
960
            add_remark!(interp, sv, "[constprop] Disabled by entry heuristic (erroneous result)")
90✔
961
            return false
219,510✔
962
        else
963
            return true
15,644,110✔
964
        end
965
    elseif isa(rt, PartialStruct) || isa(rt, InterConditional) || isa(rt, InterMustAlias)
4,650,790✔
966
        # could be improved to `Const` or a more precise wrapper
967
        return true
366,660✔
968
    elseif isa(rt, LimitedAccuracy)
2,110,144✔
969
        # optimizations like inlining are disabled for limited frames,
970
        # thus there won't be much benefit in constant-prop' here
971
        add_remark!(interp, sv, "[constprop] Disabled by entry heuristic (limited accuracy)")
×
972
        return false
193,876✔
973
    else
974
        if isa(rt, Const)
1,916,268✔
975
            if !is_nothrow(result.effects)
1,916,264✔
976
                # Could still be improved to Bottom (or at least could see the effects improved)
977
                return true
468,780✔
978
            end
979
        end
980
        add_remark!(interp, sv, "[constprop] Disabled by entry heuristic (unimprovable result)")
1,403✔
981
        return false
1,447,488✔
982
    end
983
end
984

985
# determines heuristically whether if constant propagation can be worthwhile
986
# by checking if any of given `argtypes` is "interesting" enough to be propagated
987
function const_prop_argument_heuristic(interp::AbstractInterpreter, arginfo::ArgInfo, sv::AbsIntState)
18,007,099✔
988
    ๐•ƒแตข = typeinf_lattice(interp)
35,962,350✔
989
    argtypes = arginfo.argtypes
18,007,099✔
990
    for i in 1:length(argtypes)
36,014,198✔
991
        a = argtypes[i]
49,735,602✔
992
        if has_conditional(๐•ƒแตข, sv) && isa(a, Conditional) && arginfo.fargs !== nothing
49,735,602✔
993
            is_const_prop_profitable_conditional(a, arginfo.fargs, sv) && return true
7,376✔
994
        else
995
            a = widenslotwrapper(a)
49,731,909✔
996
            has_nontrivial_extended_info(๐•ƒแตข, a) && is_const_prop_profitable_arg(๐•ƒแตข, a) && return true
49,731,909✔
997
        end
998
    end
72,103,052✔
999
    return false
8,646,046✔
1000
end
1001

1002
function is_const_prop_profitable_conditional(cnd::Conditional, fargs::Vector{Any}, sv::InferenceState)
×
1003
    slotid = find_constrained_arg(cnd, fargs, sv)
27,683✔
1004
    if slotid !== nothing
6,809✔
1005
        return true
13✔
1006
    end
1007
    # as a minor optimization, we just check the result is a constant or not,
1008
    # since both `has_nontrivial_extended_info`/`is_const_prop_profitable_arg` return `true`
1009
    # for `Const(::Bool)`
1010
    return isa(widenconditional(cnd), Const)
6,796✔
1011
end
1012

1013
function find_constrained_arg(cnd::Conditional, fargs::Vector{Any}, sv::InferenceState)
×
1014
    slot = cnd.slot
10,479✔
1015
    for i in 1:length(fargs)
20,958✔
1016
        arg = ssa_def_slot(fargs[i], sv)
32,388✔
1017
        if isa(arg, SlotNumber) && slot_id(arg) == slot
32,388✔
1018
            return i
16✔
1019
        end
1020
    end
54,281✔
1021
    return nothing
10,463✔
1022
end
1023

1024
# checks if all argtypes has additional information other than what `Type` can provide
1025
function is_all_overridden(interp::AbstractInterpreter, (; fargs, argtypes)::ArgInfo, sv::AbsIntState)
9,361,053✔
1026
    ๐•ƒแตข = typeinf_lattice(interp)
18,703,846✔
1027
    for i in 1:length(argtypes)
18,722,106✔
1028
        a = argtypes[i]
22,035,971✔
1029
        if has_conditional(๐•ƒแตข, sv) && isa(a, Conditional) && fargs !== nothing
22,035,971✔
1030
            is_const_prop_profitable_conditional(a, fargs, sv) || return false
6,207✔
1031
        else
1032
            is_forwardable_argtype(๐•ƒแตข, widenslotwrapper(a)) || return false
22,032,855✔
1033
        end
1034
    end
27,470,231✔
1035
    return true
2,120,395✔
1036
end
1037

1038
function force_const_prop(interp::AbstractInterpreter, @nospecialize(f), method::Method)
14,784✔
1039
    return is_aggressive_constprop(method) ||
39,747,822✔
1040
           InferenceParams(interp).aggressive_constant_propagation ||
1041
           istopfunction(f, :getproperty) ||
1042
           istopfunction(f, :setproperty!)
1043
end
1044

1045
function const_prop_function_heuristic(interp::AbstractInterpreter, @nospecialize(f),
7,840,136✔
1046
    arginfo::ArgInfo, nargs::Int, all_overridden::Bool, sv::AbsIntState)
1047
    argtypes = arginfo.argtypes
7,840,136✔
1048
    if nargs > 1
7,840,136✔
1049
        ๐•ƒแตข = typeinf_lattice(interp)
15,504,679✔
1050
        if istopfunction(f, :getindex) || istopfunction(f, :setindex!)
13,950,408✔
1051
            arrty = argtypes[2]
1,727,514✔
1052
            # don't propagate constant index into indexing of non-constant array
1053
            if arrty isa Type && arrty <: AbstractArray && !issingletontype(arrty)
1,753,355✔
1054
                # For static arrays, allow the constprop if we could possibly
1055
                # deduce nothrow as a result.
1056
                still_nothrow = isa(sv, InferenceState) ? is_nothrow(sv.ipo_effects) : false
987,824✔
1057
                if !still_nothrow || ismutabletype(arrty)
1,054,576✔
1058
                    return false
987,824✔
1059
                end
1060
            elseif โŠ‘(๐•ƒแตข, arrty, Array)
739,690✔
1061
                return false
192✔
1062
            end
1063
        elseif istopfunction(f, :iterate)
6,037,043✔
1064
            itrty = argtypes[2]
645,629✔
1065
            if โŠ‘(๐•ƒแตข, itrty, Array)
645,629✔
1066
                return false
1,749✔
1067
            end
1068
        end
1069
    end
1070
    if !all_overridden && (istopfunction(f, :+) || istopfunction(f, :-) || istopfunction(f, :*) ||
11,730,607✔
1071
                           istopfunction(f, :(==)) || istopfunction(f, :!=) ||
1072
                           istopfunction(f, :<=) || istopfunction(f, :>=) || istopfunction(f, :<) || istopfunction(f, :>) ||
1073
                           istopfunction(f, :<<) || istopfunction(f, :>>))
1074
        # it is almost useless to inline the op when all the same type,
1075
        # but highly worthwhile to inline promote of a constant
1076
        length(argtypes) > 2 || return false
1,454,735✔
1077
        t1 = widenconst(argtypes[2])
1,454,735✔
1078
        for i in 3:length(argtypes)
2,909,470✔
1079
            at = argtypes[i]
1,457,901✔
1080
            ty = isvarargtype(at) ? unwraptv(at) : widenconst(at)
2,915,802✔
1081
            if ty !== t1
1,457,901✔
1082
                return true
112,949✔
1083
            end
1084
        end
1,348,118✔
1085
        return false
1,341,786✔
1086
    end
1087
    return true
5,417,515✔
1088
end
1089

1090
# This is a heuristic to avoid trying to const prop through complicated functions
1091
# where we would spend a lot of time, but are probably unlikely to get an improved
1092
# result anyway.
1093
function const_prop_methodinstance_heuristic(interp::AbstractInterpreter,
16,519,590✔
1094
    mi::MethodInstance, arginfo::ArgInfo, sv::AbsIntState)
1095
    method = mi.def::Method
16,519,590✔
1096
    if method.is_for_opaque_closure
16,519,590✔
1097
        # Not inlining an opaque closure can be very expensive, so be generous
1098
        # with the const-prop-ability. It is quite possible that we can't infer
1099
        # anything at all without const-propping, so the inlining check below
1100
        # isn't particularly helpful here.
1101
        return true
3✔
1102
    end
1103
    # now check if the source of this method instance is inlineable, since the extended type
1104
    # information we have here would be discarded if it is not inlined into a callee context
1105
    # (modulo the inferred return type that can be potentially refined)
1106
    if is_declared_inline(method)
33,037,538✔
1107
        # this method is declared as `@inline` and will be inlined
1108
        return true
6,208,940✔
1109
    end
1110
    flag = get_curr_ssaflag(sv)
10,310,647✔
1111
    if is_stmt_inline(flag)
10,310,647✔
1112
        # force constant propagation for a call that is going to be inlined
1113
        # since the inliner will try to find this constant result
1114
        # if these constant arguments arrive there
1115
        return true
2,819✔
1116
    elseif is_stmt_noinline(flag)
10,307,828✔
1117
        # this call won't be inlined, thus this constant-prop' will most likely be unfruitful
1118
        return false
142✔
1119
    else
1120
        # Peek at the inferred result for the method to determine if the optimizer
1121
        # was able to cut it down to something simple (inlineable in particular).
1122
        # If so, there will be a good chance we might be able to const prop
1123
        # all the way through and learn something new.
1124
        code = get(code_cache(interp), mi, nothing)
20,567,870✔
1125
        if isa(code, CodeInstance)
10,307,686✔
1126
            inferred = @atomic :monotonic code.inferred
10,260,184✔
1127
            # TODO propagate a specific `CallInfo` that conveys information about this call
1128
            if inlining_policy(interp, inferred, NoCallInfo(), IR_FLAG_NULL, mi, arginfo.argtypes) !== nothing
10,260,184✔
1129
                return true
9,213,064✔
1130
            end
1131
        end
1132
    end
1133
    return false # the cache isn't inlineable, so this constant-prop' will most likely be unfruitful
1,094,622✔
1134
end
1135

1136
function semi_concrete_eval_call(interp::AbstractInterpreter,
2,079,865✔
1137
    mi::MethodInstance, result::MethodCallResult, arginfo::ArgInfo, sv::AbsIntState)
1138
    world = frame_world(sv)
2,079,865✔
1139
    mi_cache = WorldView(code_cache(interp), world)
6✔
1140
    code = get(mi_cache, mi, nothing)
4,159,730✔
1141
    if code !== nothing
2,079,865✔
1142
        irsv = IRInterpretationState(interp, code, mi, arginfo.argtypes, world)
2,079,865✔
1143
        if irsv !== nothing
2,079,865✔
1144
            irsv.parent = sv
2,079,860✔
1145
            rt, (nothrow, noub) = ir_abstract_constant_propagation(interp, irsv)
2,079,860✔
1146
            @assert !(rt isa Conditional || rt isa MustAlias) "invalid lattice element returned from irinterp"
2,079,853✔
1147
            if !(isa(rt, Type) && hasintersect(rt, Bool))
2,079,853✔
1148
                ir = irsv.ir
1,882,699✔
1149
                # TODO (#48913) enable double inlining pass when there are any calls
1150
                # that are newly resovled by irinterp
1151
                # state = InliningState(interp)
1152
                # ir = ssa_inlining_pass!(irsv.ir, state, propagate_inbounds(irsv))
1153
                effects = result.effects
1,882,699✔
1154
                if !is_nothrow(effects)
1,882,699✔
1155
                    effects = Effects(effects; nothrow)
673,149✔
1156
                end
1157
                if noub
1,882,699✔
1158
                    effects = Effects(effects; noub = ALWAYS_TRUE)
1,773,826✔
1159
                end
1160
                return ConstCallResults(rt, SemiConcreteResult(mi, ir, effects), effects, mi)
1,882,699✔
1161
            end
1162
        end
1163
    end
1164
    return nothing
197,159✔
1165
end
1166

1167
function const_prop_call(interp::AbstractInterpreter,
4,845,658✔
1168
    mi::MethodInstance, result::MethodCallResult, arginfo::ArgInfo, sv::AbsIntState,
1169
    concrete_eval_result::Union{Nothing,ConstCallResults}=nothing)
1170
    inf_cache = get_inference_cache(interp)
4,845,658✔
1171
    ๐•ƒแตข = typeinf_lattice(interp)
9,674,392✔
1172
    inf_result = cache_lookup(๐•ƒแตข, mi, arginfo.argtypes, inf_cache)
4,845,658✔
1173
    if inf_result === nothing
4,845,658✔
1174
        # fresh constant prop'
1175
        argtypes = has_conditional(๐•ƒแตข, sv) ? ConditionalArgtypes(arginfo, sv) : SimpleArgtypes(arginfo.argtypes)
2,812,756✔
1176
        inf_result = InferenceResult(mi, argtypes, typeinf_lattice(interp))
2,812,756✔
1177
        if !any(inf_result.overridden_by_const)
5,625,512✔
1178
            add_remark!(interp, sv, "[constprop] Could not handle constant info in matching_cache_argtypes")
×
1179
            return nothing
×
1180
        end
1181
        frame = InferenceState(inf_result, #=cache=#:local, interp)
2,812,756✔
1182
        if frame === nothing
2,812,756✔
1183
            add_remark!(interp, sv, "[constprop] Could not retrieve the source")
×
1184
            return nothing # this is probably a bad generated function (unsound), but just ignore it
×
1185
        end
1186
        frame.parent = sv
2,812,756✔
1187
        if !typeinf(interp, frame)
2,812,756✔
1188
            add_remark!(interp, sv, "[constprop] Fresh constant inference hit a cycle")
×
1189
            return nothing
×
1190
        end
1191
        @assert inf_result.result !== nothing
2,812,749✔
1192
        if concrete_eval_result !== nothing
4,747✔
1193
            # override return type and effects with concrete evaluation result if available
1194
            inf_result.result = concrete_eval_result.rt
7,043✔
1195
            inf_result.ipo_effects = concrete_eval_result.effects
2,812,749✔
1196
        end
1197
    else
1198
        # found the cache for this constant prop'
1199
        if inf_result.result === nothing
2,032,902✔
1200
            add_remark!(interp, sv, "[constprop] Found cached constant inference in a cycle")
×
1201
            return nothing
×
1202
        end
1203
    end
1204
    return ConstCallResults(inf_result.result, ConstPropResult(inf_result), inf_result.ipo_effects, mi)
4,845,651✔
1205
end
1206

1207
# TODO implement MustAlias forwarding
1208

1209
struct ConditionalArgtypes <: ForwardableArgtypes
1210
    arginfo::ArgInfo
2,812,756✔
1211
    sv::InferenceState
1212
end
1213

1214
"""
1215
    matching_cache_argtypes(๐•ƒ::AbstractLattice, linfo::MethodInstance,
1216
                            conditional_argtypes::ConditionalArgtypes)
1217

1218
The implementation is able to forward `Conditional` of `conditional_argtypes`,
1219
as well as the other general extended lattice inforamtion.
1220
"""
1221
function matching_cache_argtypes(๐•ƒ::AbstractLattice, linfo::MethodInstance,
2,812,756✔
1222
                                 conditional_argtypes::ConditionalArgtypes)
1223
    (; arginfo, sv) = conditional_argtypes
2,812,756✔
1224
    (; fargs, argtypes) = arginfo
2,812,756✔
1225
    given_argtypes = Vector{Any}(undef, length(argtypes))
2,812,756✔
1226
    def = linfo.def::Method
2,812,756✔
1227
    nargs = Int(def.nargs)
2,812,756✔
1228
    cache_argtypes, overridden_by_const = matching_cache_argtypes(๐•ƒ, linfo)
5,625,512✔
1229
    local condargs = nothing
×
1230
    for i in 1:length(argtypes)
5,625,512✔
1231
        argtype = argtypes[i]
9,255,458✔
1232
        # forward `Conditional` if it conveys a constraint on any other argument
1233
        if isa(argtype, Conditional) && fargs !== nothing
9,255,458✔
1234
            cnd = argtype
3,670✔
1235
            slotid = find_constrained_arg(cnd, fargs, sv)
15,168✔
1236
            if slotid !== nothing
3,670✔
1237
                # using union-split signature, we may be able to narrow down `Conditional`
1238
                sigt = widenconst(slotid > nargs ? argtypes[slotid] : cache_argtypes[slotid])
6✔
1239
                thentype = tmeet(cnd.thentype, sigt)
3✔
1240
                elsetype = tmeet(cnd.elsetype, sigt)
3✔
1241
                if thentype === Bottom && elsetype === Bottom
3✔
1242
                    # we accidentally proved this method match is impossible
1243
                    # TODO bail out here immediately rather than just propagating Bottom ?
1244
                    given_argtypes[i] = Bottom
×
1245
                else
1246
                    if condargs === nothing
3✔
1247
                        condargs = Tuple{Int,Int}[]
3✔
1248
                    end
1249
                    push!(condargs, (slotid, i))
3✔
1250
                    given_argtypes[i] = Conditional(slotid, thentype, elsetype)
3✔
1251
                end
1252
                continue
3✔
1253
            end
1254
        end
1255
        given_argtypes[i] = widenslotwrapper(argtype)
9,255,455✔
1256
    end
15,698,160✔
1257
    if condargs !== nothing
2,812,756✔
1258
        given_argtypes = let condargs=condargs
×
1259
            va_process_argtypes(๐•ƒ, given_argtypes, linfo) do isva_given_argtypes::Vector{Any}, last::Int
3✔
1260
                # invalidate `Conditional` imposed on varargs
1261
                for (slotid, i) in condargs
×
1262
                    if slotid โ‰ฅ last && (1 โ‰ค i โ‰ค length(isva_given_argtypes)) # `Conditional` is already widened to vararg-tuple otherwise
×
1263
                        isva_given_argtypes[i] = widenconditional(isva_given_argtypes[i])
×
1264
                    end
1265
                end
×
1266
            end
1267
        end
1268
    else
1269
        given_argtypes = va_process_argtypes(๐•ƒ, given_argtypes, linfo)
2,812,753✔
1270
    end
1271
    return pick_const_args!(๐•ƒ, cache_argtypes, overridden_by_const, given_argtypes)
2,812,756✔
1272
end
1273

1274
# This is only for use with `Conditional`.
1275
# In general, usage of this is wrong.
1276
function ssa_def_slot(@nospecialize(arg), sv::InferenceState)
11,603,220✔
1277
    code = sv.src.code
11,603,220✔
1278
    init = sv.currpc
11,603,220✔
1279
    while isa(arg, SSAValue)
13,439,486✔
1280
        init = arg.id
1,836,266✔
1281
        arg = code[init]
1,836,266✔
1282
    end
1,836,266✔
1283
    if arg isa SlotNumber
11,603,220✔
1284
        # found this kind of pattern:
1285
        # %init = SlotNumber(x)
1286
        # [...]
1287
        # goto if not isa(%init, T)
1288
        # now conservatively make sure there isn't potentially another conflicting assignment
1289
        # to the same slot between the def and usage
1290
        # we can assume the IR is sorted, since the front-end only creates SSA values in order
1291
        for i = init:(sv.currpc-1)
5,195,791✔
1292
            e = code[i]
281,296✔
1293
            if isexpr(e, :(=)) && e.args[1] === arg
421,269✔
1294
                return nothing
281✔
1295
            end
1296
        end
431,964✔
1297
    else
1298
        # there might still be the following kind of pattern (see #45499):
1299
        # %init = ...
1300
        # [...]
1301
        # SlotNumber(x) = %init
1302
        # [...]
1303
        # goto if not isa(%init, T)
1304
        # let's check if there is a slot assigned to the def SSA value but also there isn't
1305
        # any potentially conflicting assignment to the same slot
1306
        arg = nothing
×
1307
        def = SSAValue(init)
6,537,776✔
1308
        for i = (init+1):(sv.currpc-1)
7,045,050✔
1309
            e = code[i]
919,032✔
1310
            if isexpr(e, :(=))
1,021,541✔
1311
                lhs = e.args[1]
16,085✔
1312
                if isa(lhs, SlotNumber)
16,085✔
1313
                    lhs === arg && return nothing
16,085✔
1314
                    rhs = e.args[2]
16,085✔
1315
                    if rhs === def
16,085✔
1316
                        arg = lhs
15,651✔
1317
                    end
1318
                end
1319
            end
1320
        end
919,032✔
1321
    end
1322
    return arg
11,602,939✔
1323
end
1324

1325
struct AbstractIterationResult
1326
    cti::Vector{Any}
1,646,818✔
1327
    info::MaybeAbstractIterationInfo
1328
    ai_effects::Effects
1329
end
1330
AbstractIterationResult(cti::Vector{Any}, info::MaybeAbstractIterationInfo) =
1,639,577✔
1331
    AbstractIterationResult(cti, info, EFFECTS_TOTAL)
1332

1333
# `typ` is the inferred type for expression `arg`.
1334
# if the expression constructs a container (e.g. `svec(x,y,z)`),
1335
# refine its type to an array of element types.
1336
# Union of Tuples of the same length is converted to Tuple of Unions.
1337
# returns an array of types
1338
function precise_container_type(interp::AbstractInterpreter, @nospecialize(itft), @nospecialize(typ),
1,646,818✔
1339
                                sv::AbsIntState)
1340
    if isa(typ, PartialStruct)
1,646,818✔
1341
        widet = typ.typ
273,082✔
1342
        if isa(widet, DataType)
273,082✔
1343
            if widet.name === Tuple.name
273,082✔
1344
                return AbstractIterationResult(typ.fields, nothing)
272,841✔
1345
            elseif widet.name === _NAMEDTUPLE_NAME
241✔
1346
                return AbstractIterationResult(typ.fields, nothing)
×
1347
            end
1348
        end
1349
    end
1350

1351
    if isa(typ, Const)
1,373,977✔
1352
        val = typ.val
377,735✔
1353
        if isa(val, SimpleVector) || isa(val, Tuple) || isa(val, NamedTuple)
754,916✔
1354
            return AbstractIterationResult(Any[ Const(val[i]) for i in 1:length(val) ], nothing) # avoid making a tuple Generator here!
377,255✔
1355
        end
1356
    end
1357

1358
    tti0 = widenconst(typ)
996,722✔
1359
    tti = unwrap_unionall(tti0)
1,000,396✔
1360
    if isa(tti, DataType) && tti.name === _NAMEDTUPLE_NAME
996,722✔
1361
        # A NamedTuple iteration is the same as the iteration of its Tuple parameter:
1362
        # compute a new `tti == unwrap_unionall(tti0)` based on that Tuple type
1363
        tti = unwraptv(tti.parameters[2])
538✔
1364
        tti0 = rewrap_unionall(tti, tti0)
538✔
1365
    end
1366
    if isa(tti, Union)
996,722✔
1367
        utis = uniontypes(tti)
4✔
1368
        if any(@nospecialize(t) -> !isa(t, DataType) || !(t <: Tuple) || !isknownlength(t), utis)
28✔
1369
            return AbstractIterationResult(Any[Vararg{Any}], nothing, Effects())
×
1370
        end
1371
        ltp = length((utis[1]::DataType).parameters)
4✔
1372
        for t in utis
4✔
1373
            if length((t::DataType).parameters) != ltp
12✔
1374
                return AbstractIterationResult(Any[Vararg{Any}], nothing)
×
1375
            end
1376
        end
16✔
1377
        result = Any[ Union{} for _ in 1:ltp ]
12✔
1378
        for t in utis
4✔
1379
            tps = (t::DataType).parameters
12✔
1380
            _all(valid_as_lattice, tps) || continue
12✔
1381
            for j in 1:ltp
24✔
1382
                result[j] = tmerge(result[j], rewrap_unionall(tps[j], tti0))
36✔
1383
            end
60✔
1384
        end
16✔
1385
        return AbstractIterationResult(result, nothing)
4✔
1386
    elseif tti0 <: Tuple
996,718✔
1387
        if isa(tti0, DataType)
974,870✔
1388
            return AbstractIterationResult(Any[ p for p in tti0.parameters ], nothing)
974,651✔
1389
        elseif !isa(tti, DataType)
219✔
1390
            return AbstractIterationResult(Any[Vararg{Any}], nothing)
×
1391
        else
1392
            len = length(tti.parameters)
219✔
1393
            last = tti.parameters[len]
219✔
1394
            va = isvarargtype(last)
219✔
1395
            elts = Any[ fieldtype(tti0, i) for i = 1:len ]
347✔
1396
            if va
219✔
1397
                if elts[len] === Union{}
201✔
1398
                    pop!(elts)
×
1399
                else
1400
                    elts[len] = Vararg{elts[len]}
201✔
1401
                end
1402
            end
1403
            return AbstractIterationResult(elts, nothing)
219✔
1404
        end
1405
    elseif tti0 === SimpleVector
21,848✔
1406
        return AbstractIterationResult(Any[Vararg{Any}], nothing)
530✔
1407
    elseif tti0 === Any
21,318✔
1408
        return AbstractIterationResult(Any[Vararg{Any}], nothing, Effects())
7,240✔
1409
    elseif tti0 <: Array
14,078✔
1410
        if eltype(tti0) === Union{}
13,004✔
1411
            return AbstractIterationResult(Any[], nothing)
30✔
1412
        end
1413
        return AbstractIterationResult(Any[Vararg{eltype(tti0)}], nothing)
12,974✔
1414
    else
1415
        return abstract_iteration(interp, itft, typ, sv)
1,074✔
1416
    end
1417
end
1418

1419
# simulate iteration protocol on container type up to fixpoint
1420
function abstract_iteration(interp::AbstractInterpreter, @nospecialize(itft), @nospecialize(itertype), sv::AbsIntState)
1,074✔
1421
    if isa(itft, Const)
1,074✔
1422
        iteratef = itft.val
1,074✔
1423
    else
1424
        return AbstractIterationResult(Any[Vararg{Any}], nothing, Effects())
×
1425
    end
1426
    @assert !isvarargtype(itertype)
1,074✔
1427
    call = abstract_call_known(interp, iteratef, ArgInfo(nothing, Any[itft, itertype]), StmtInfo(true), sv)
2,148✔
1428
    stateordonet = call.rt
1,074✔
1429
    info = call.info
1,074✔
1430
    # Return Bottom if this is not an iterator.
1431
    # WARNING: Changes to the iteration protocol must be reflected here,
1432
    # this is not just an optimization.
1433
    # TODO: this doesn't realize that Array, SimpleVector, Tuple, and NamedTuple do not use the iterate protocol
1434
    stateordonet === Bottom && return AbstractIterationResult(Any[Bottom], AbstractIterationInfo(CallMeta[CallMeta(Bottom, call.effects, info)], true))
1,074✔
1435
    valtype = statetype = Bottom
×
1436
    ret = Any[]
1,071✔
1437
    calls = CallMeta[call]
1,071✔
1438
    stateordonet_widened = widenconst(stateordonet)
1,071✔
1439
    ๐•ƒแตข = typeinf_lattice(interp)
2,142✔
1440

1441
    # Try to unroll the iteration up to max_tuple_splat, which covers any finite
1442
    # length iterators, or interesting prefix
1443
    while true
3,740✔
1444
        if stateordonet_widened === Nothing
3,740✔
1445
            return AbstractIterationResult(ret, AbstractIterationInfo(calls, true))
908✔
1446
        end
1447
        if Nothing <: stateordonet_widened || length(ret) >= InferenceParams(interp).max_tuple_splat
5,512✔
1448
            break
×
1449
        end
1450
        if !isa(stateordonet_widened, DataType) || !(stateordonet_widened <: Tuple) || isvatuple(stateordonet_widened) || length(stateordonet_widened.parameters) != 2
5,339✔
1451
            break
1✔
1452
        end
1453
        nstatetype = getfield_tfunc(๐•ƒแตข, stateordonet, Const(2))
2,669✔
1454
        # If there's no new information in this statetype, don't bother continuing,
1455
        # the iterator won't be finite.
1456
        if โŠ‘(๐•ƒแตข, nstatetype, statetype)
2,669✔
1457
            return AbstractIterationResult(Any[Bottom], AbstractIterationInfo(calls, false), EFFECTS_THROWS)
×
1458
        end
1459
        valtype = getfield_tfunc(๐•ƒแตข, stateordonet, Const(1))
2,669✔
1460
        push!(ret, valtype)
2,669✔
1461
        statetype = nstatetype
×
1462
        call = abstract_call_known(interp, iteratef, ArgInfo(nothing, Any[Const(iteratef), itertype, statetype]), StmtInfo(true), sv)
8,007✔
1463
        stateordonet = call.rt
2,669✔
1464
        stateordonet_widened = widenconst(stateordonet)
2,669✔
1465
        push!(calls, call)
2,669✔
1466
    end
2,669✔
1467
    # From here on, we start asking for results on the widened types, rather than
1468
    # the precise (potentially const) state type
1469
    # statetype and valtype are reinitialized in the first iteration below from the
1470
    # (widened) stateordonet, which has not yet been fully analyzed in the loop above
1471
    valtype = statetype = Bottom
×
1472
    may_have_terminated = Nothing <: stateordonet_widened
163✔
1473
    while valtype !== Any
325✔
1474
        nounion = typeintersect(stateordonet_widened, Tuple{Any,Any})
225✔
1475
        if nounion !== Union{} && !isa(nounion, DataType)
225✔
1476
            # nounion is of a type we cannot handle
1477
            valtype = Any
×
1478
            break
×
1479
        end
1480
        if nounion === Union{} || (nounion.parameters[1] <: valtype && nounion.parameters[2] <: statetype)
449✔
1481
            # reached a fixpoint or iterator failed/gave invalid answer
1482
            if !hasintersect(stateordonet_widened, Nothing)
63✔
1483
                # ... but cannot terminate
1484
                if !may_have_terminated
1✔
1485
                    #  ... and cannot have terminated prior to this loop
1486
                    return AbstractIterationResult(Any[Bottom], AbstractIterationInfo(calls, false), Effects())
1✔
1487
                else
1488
                    # iterator may have terminated prior to this loop, but not during it
1489
                    valtype = Bottom
×
1490
                end
1491
            end
1492
            break
62✔
1493
        end
1494
        valtype = tmerge(valtype, nounion.parameters[1])
162✔
1495
        statetype = tmerge(statetype, nounion.parameters[2])
162✔
1496
        call = abstract_call_known(interp, iteratef, ArgInfo(nothing, Any[Const(iteratef), itertype, statetype]), StmtInfo(true), sv)
486✔
1497
        push!(calls, call)
162✔
1498
        stateordonet = call.rt
162✔
1499
        stateordonet_widened = widenconst(stateordonet)
162✔
1500
    end
162✔
1501
    if valtype !== Union{}
162✔
1502
        push!(ret, Vararg{valtype})
162✔
1503
    end
1504
    return AbstractIterationResult(ret, AbstractIterationInfo(calls, false))
162✔
1505
end
1506

1507
# do apply(af, fargs...), where af is a function value
1508
function abstract_apply(interp::AbstractInterpreter, argtypes::Vector{Any}, si::StmtInfo,
947,410✔
1509
                        sv::AbsIntState, max_methods::Int=get_max_methods(interp, sv))
1510
    itft = argtype_by_index(argtypes, 2)
947,410✔
1511
    aft = argtype_by_index(argtypes, 3)
947,410✔
1512
    (itft === Bottom || aft === Bottom) && return CallMeta(Bottom, EFFECTS_THROWS, NoCallInfo())
947,410✔
1513
    aargtypes = argtype_tail(argtypes, 4)
947,410✔
1514
    aftw = widenconst(aft)
947,410✔
1515
    if !isa(aft, Const) && !isa(aft, PartialOpaque) && (!isType(aftw) || has_free_typevars(aftw))
947,577✔
1516
        if !isconcretetype(aftw) || (aftw <: Builtin)
12,228✔
1517
            add_remark!(interp, sv, "Core._apply_iterate called on a function of a non-concrete type")
×
1518
            # bail now, since it seems unlikely that abstract_call will be able to do any better after splitting
1519
            # this also ensures we don't call abstract_call_gf_by_type below on an IntrinsicFunction or Builtin
1520
            return CallMeta(Any, Effects(), NoCallInfo())
2,768✔
1521
        end
1522
    end
1523
    res = Union{}
297✔
1524
    nargs = length(aargtypes)
944,642✔
1525
    splitunions = 1 < unionsplitcost(typeinf_lattice(interp), aargtypes) <= InferenceParams(interp).max_apply_union_enum
944,642✔
1526
    ctypes = [Any[aft]]
944,642✔
1527
    infos = Vector{MaybeAbstractIterationInfo}[MaybeAbstractIterationInfo[]]
944,642✔
1528
    effects = EFFECTS_TOTAL
297✔
1529
    for i = 1:nargs
1,889,284✔
1530
        ctypesยด = Vector{Any}[]
1,642,059✔
1531
        infosโ€ฒ = Vector{MaybeAbstractIterationInfo}[]
1,642,059✔
1532
        for ti in (splitunions ? uniontypes(aargtypes[i]) : Any[aargtypes[i]])
1,642,059✔
1533
            if !isvarargtype(ti)
1,646,818✔
1534
                (;cti, info, ai_effects) = precise_container_type(interp, itft, ti, sv)
1,646,742✔
1535
            else
1536
                (;cti, info, ai_effects) = precise_container_type(interp, itft, unwrapva(ti), sv)
76✔
1537
                # We can't represent a repeating sequence of the same types,
1538
                # so tmerge everything together to get one type that represents
1539
                # everything.
1540
                argt = cti[end]
76✔
1541
                if isvarargtype(argt)
76✔
1542
                    argt = unwrapva(argt)
25✔
1543
                end
1544
                for i in 1:(length(cti)-1)
84✔
1545
                    argt = tmerge(argt, cti[i])
14✔
1546
                end
20✔
1547
                cti = Any[Vararg{argt}]
76✔
1548
            end
1549
            effects = merge_effects(effects, ai_effects)
3,292,197✔
1550
            if info !== nothing
1,646,818✔
1551
                for call in info.each
1,074✔
1552
                    effects = merge_effects(effects, call.effects)
7,689✔
1553
                end
4,979✔
1554
            end
1555
            if any(@nospecialize(t) -> t === Bottom, cti)
6,910,568✔
1556
                continue
4✔
1557
            end
1558
            for j = 1:length(ctypes)
3,293,628✔
1559
                ct = ctypes[j]::Vector{Any}
1,647,009✔
1560
                if isvarargtype(ct[end])
1,647,009✔
1561
                    # This is vararg, we're not gonna be able to do any inlining,
1562
                    # drop the info
1563
                    info = nothing
×
1564
                    tail = tuple_tail_elem(typeinf_lattice(interp), unwrapva(ct[end]), cti)
26,572✔
1565
                    push!(ctypesยด, push!(ct[1:(end - 1)], tail))
26,572✔
1566
                else
1567
                    push!(ctypesยด, append!(ct[:], cti))
1,620,437✔
1568
                end
1569
                push!(infosโ€ฒ, push!(copy(infos[j]), info))
1,648,062✔
1570
            end
1,647,009✔
1571
        end
3,288,877✔
1572
        ctypes = ctypesยด
1,642,059✔
1573
        infos = infosโ€ฒ
363✔
1574
    end
2,339,476✔
1575
    retinfos = ApplyCallInfo[]
944,642✔
1576
    retinfo = UnionSplitApplyCallInfo(retinfos)
944,642✔
1577
    napplicable = length(ctypes)
944,642✔
1578
    seen = 0
297✔
1579
    for i = 1:napplicable
1,889,282✔
1580
        ct = ctypes[i]
948,913✔
1581
        arginfo = infos[i]
948,913✔
1582
        lct = length(ct)
948,913✔
1583
        # truncate argument list at the first Vararg
1584
        for i = 1:lct-1
1,894,868✔
1585
            cti = ct[i]
2,607,038✔
1586
            if isvarargtype(cti)
2,607,038✔
1587
                ct[i] = tuple_tail_elem(typeinf_lattice(interp), unwrapva(cti), ct[(i+1):lct])
×
1588
                resize!(ct, i)
×
1589
                break
×
1590
            end
1591
        end
2,607,038✔
1592
        call = abstract_call(interp, ArgInfo(nothing, ct), si, sv, max_methods)
948,913✔
1593
        seen += 1
948,913✔
1594
        push!(retinfos, ApplyCallInfo(call.info, arginfo))
948,913✔
1595
        res = tmerge(typeinf_lattice(interp), res, call.rt)
1,897,826✔
1596
        effects = merge_effects(effects, call.effects)
1,889,698✔
1597
        if bail_out_apply(interp, InferenceLoopState(ct, res, effects), sv)
948,913✔
1598
            add_remark!(interp, sv, "_apply_iterate inference reached maximally imprecise information. Bailing on.")
25✔
1599
            break
136,238✔
1600
        end
1601
    end
812,675✔
1602
    if seen โ‰  napplicable
944,642✔
1603
        # there is unanalyzed candidate, widen type and effects to the top
1604
        res = Any
×
1605
        effects = Effects()
×
1606
        retinfo = NoCallInfo() # NOTE this is necessary to prevent the inlining processing
×
1607
    end
1608
    # TODO: Add a special info type to capture all the iteration info.
1609
    # For now, only propagate info if we don't also union-split the iteration
1610
    return CallMeta(res, effects, retinfo)
944,642✔
1611
end
1612

1613
function argtype_by_index(argtypes::Vector{Any}, i::Int)
756✔
1614
    n = length(argtypes)
2,542,464✔
1615
    na = argtypes[n]
2,542,464✔
1616
    if isvarargtype(na)
2,542,464✔
1617
        return i >= n ? unwrapva(na) : argtypes[i]
12,305✔
1618
    else
1619
        return i > n ? Bottom : argtypes[i]
2,530,159✔
1620
    end
1621
end
1622

1623
function argtype_tail(argtypes::Vector{Any}, i::Int)
378✔
1624
    n = length(argtypes)
956,857✔
1625
    if isvarargtype(argtypes[n]) && i > n
956,857✔
1626
        i = n
×
1627
    end
1628
    return argtypes[i:n]
956,857✔
1629
end
1630

1631
struct ConditionalTypes
1632
    thentype
1633
    elsetype
1634
    ConditionalTypes(thentype, elsetype) = (@nospecialize; new(thentype, elsetype))
×
1635
end
1636

1637
@inline function isa_condition(@nospecialize(xt), @nospecialize(ty), max_union_splitting::Int,
479✔
1638
    @nospecialize(rt))
1639
    if isa(rt, Const)
947,251✔
1640
        xt = widenslotwrapper(xt)
836,533✔
1641
        if rt.val === false
836,509✔
1642
            return ConditionalTypes(Bottom, xt)
117,280✔
1643
        elseif rt.val === true
719,229✔
1644
            return ConditionalTypes(xt, Bottom)
719,229✔
1645
        end
1646
    end
1647
    return isa_condition(xt, ty, max_union_splitting)
110,742✔
1648
end
1649
@inline function isa_condition(@nospecialize(xt), @nospecialize(ty), max_union_splitting::Int)
15✔
1650
    tty_ub, isexact_tty = instanceof_tfunc(ty)
110,742✔
1651
    tty = widenconst(xt)
110,742✔
1652
    if isexact_tty && !isa(tty_ub, TypeVar)
110,742✔
1653
        tty_lb = tty_ub # TODO: this would be wrong if !isexact_tty, but instanceof_tfunc doesn't preserve this info
15✔
1654
        if !has_free_typevars(tty_lb) && !has_free_typevars(tty_ub)
82,664✔
1655
            thentype = typeintersect(tty, tty_ub)
82,664✔
1656
            if iskindtype(tty_ub) && thentype !== Bottom
164,238✔
1657
                # `typeintersect` may be unable narrow down `Type`-type
1658
                thentype = tty_ub
4,766✔
1659
            end
1660
            valid_as_lattice(thentype) || (thentype = Bottom)
165,328✔
1661
            elsetype = typesubtract(tty, tty_lb, max_union_splitting)
82,664✔
1662
            return ConditionalTypes(thentype, elsetype)
82,664✔
1663
        end
1664
    end
1665
    return nothing
28,078✔
1666
end
1667

1668
@inline function egal_condition(c::Const, @nospecialize(xt), max_union_splitting::Int,
152✔
1669
    @nospecialize(rt))
1670
    thentype = c
14✔
1671
    elsetype = widenslotwrapper(xt)
1,195,092✔
1672
    if rt === Const(false)
1,195,092✔
1673
        thentype = Bottom
43,850✔
1674
    elseif rt === Const(true)
1,151,242✔
1675
        elsetype = Bottom
334✔
1676
    elseif elsetype isa Type && isdefined(typeof(c.val), :instance) # can only widen a if it is a singleton
1,150,908✔
1677
        elsetype = typesubtract(elsetype, typeof(c.val), max_union_splitting)
1,099,386✔
1678
    end
1679
    return ConditionalTypes(thentype, elsetype)
1,238,942✔
1680
end
1681
@inline function egal_condition(c::Const, @nospecialize(xt), max_union_splitting::Int)
×
1682
    thentype = c
×
1683
    elsetype = widenslotwrapper(xt)
×
1684
    if elsetype isa Type && issingletontype(typeof(c.val)) # can only widen a if it is a singleton
×
1685
        elsetype = typesubtract(elsetype, typeof(c.val), max_union_splitting)
×
1686
    end
1687
    return ConditionalTypes(thentype, elsetype)
×
1688
end
1689

1690
function abstract_call_builtin(interp::AbstractInterpreter, f::Builtin, (; fargs, argtypes)::ArgInfo,
17,098,066✔
1691
                               sv::AbsIntState)
1692
    @nospecialize f
9,967✔
1693
    la = length(argtypes)
17,098,066✔
1694
    ๐•ƒแตข = typeinf_lattice(interp)
23,653,659✔
1695
    โŠ‘แตข = โŠ‘(๐•ƒแตข)
11,831,813✔
1696
    if has_conditional(๐•ƒแตข, sv) && f === Core.ifelse && fargs isa Vector{Any} && la == 4
11,843,527✔
1697
        cnd = argtypes[2]
3,886✔
1698
        if isa(cnd, Conditional)
3,886✔
1699
            newcnd = widenconditional(cnd)
6✔
1700
            tx = argtypes[3]
3✔
1701
            ty = argtypes[4]
3✔
1702
            if isa(newcnd, Const)
3✔
1703
                # if `cnd` is constant, we should just respect its constantness to keep inference accuracy
1704
                return newcnd.val::Bool ? tx : ty
1✔
1705
            else
1706
                # try to simulate this as a real conditional (`cnd ? x : y`), so that the penalty for using `ifelse` instead isn't too high
1707
                a = ssa_def_slot(fargs[3], sv)
2✔
1708
                b = ssa_def_slot(fargs[4], sv)
2✔
1709
                if isa(a, SlotNumber) && cnd.slot == slot_id(a)
2✔
1710
                    tx = (cnd.thentype โŠ‘แตข tx ? cnd.thentype : tmeet(๐•ƒแตข, tx, widenconst(cnd.thentype)))
1✔
1711
                end
1712
                if isa(b, SlotNumber) && cnd.slot == slot_id(b)
2✔
1713
                    ty = (cnd.elsetype โŠ‘แตข ty ? cnd.elsetype : tmeet(๐•ƒแตข, ty, widenconst(cnd.elsetype)))
1✔
1714
                end
1715
                return tmerge(๐•ƒแตข, tx, ty)
2✔
1716
            end
1717
        end
1718
    end
1719
    rt = builtin_tfunction(interp, f, argtypes[2:end], sv)
17,098,063✔
1720
    if has_mustalias(๐•ƒแตข) && f === getfield && isa(fargs, Vector{Any}) && la โ‰ฅ 3
9,967✔
1721
        a3 = argtypes[3]
×
1722
        if isa(a3, Const)
×
1723
            if rt !== Bottom && !isalreadyconst(rt)
×
1724
                var = fargs[2]
×
1725
                if isa(var, SlotNumber)
×
1726
                    vartyp = widenslotwrapper(argtypes[2])
×
1727
                    fldidx = maybe_const_fldidx(vartyp, a3.val)
×
1728
                    if fldidx !== nothing
×
1729
                        # wrap this aliasable field into `MustAlias` for possible constraint propagations
1730
                        return MustAlias(var, vartyp, fldidx, rt)
×
1731
                    end
1732
                end
1733
            end
1734
        end
1735
    elseif has_conditional(๐•ƒแตข, sv) && (rt === Bool || (isa(rt, Const) && isa(rt.val, Bool))) && isa(fargs, Vector{Any})
21,226,629✔
1736
        # perform very limited back-propagation of type information for `is` and `isa`
1737
        if f === isa
3,812,318✔
1738
            # try splitting value argument, based on types
1739
            a = ssa_def_slot(fargs[2], sv)
1,017,997✔
1740
            a2 = argtypes[2]
1,017,997✔
1741
            a3 = argtypes[3]
1,017,997✔
1742
            if isa(a, SlotNumber)
1,017,997✔
1743
                cndt = isa_condition(a2, a3, InferenceParams(interp).max_union_splitting, rt)
1,666,480✔
1744
                if cndt !== nothing
947,251✔
1745
                    return Conditional(a, cndt.thentype, cndt.elsetype)
919,173✔
1746
                end
1747
            end
1748
            if isa(a2, MustAlias)
98,824✔
1749
                if !isa(rt, Const) # skip refinement when the field is known precisely (just optimization)
×
1750
                    cndt = isa_condition(a2, a3, InferenceParams(interp).max_union_splitting)
×
1751
                    if cndt !== nothing
×
1752
                        return form_mustalias_conditional(a2, cndt.thentype, cndt.elsetype)
×
1753
                    end
1754
                end
1755
            end
1756
            # try splitting type argument, based on value
1757
            if isdispatchelem(widenconst(a2)) && a3 isa Union && !has_free_typevars(a3) && !isa(rt, Const)
197,648✔
1758
                b = ssa_def_slot(fargs[3], sv)
847✔
1759
                if isa(b, SlotNumber)
847✔
1760
                    # !(x isa T) implies !(Type{a2} <: T)
1761
                    # TODO: complete splitting, based on which portions of the Union a3 for which isa_tfunc returns Const(true) or Const(false) instead of Bool
1762
                    elsetype = typesubtract(a3, Type{widenconst(a2)}, InferenceParams(interp).max_union_splitting)
842✔
1763
                    return Conditional(b, a3, elsetype)
842✔
1764
                end
1765
            end
1766
        elseif f === (===)
2,794,321✔
1767
            a = ssa_def_slot(fargs[2], sv)
1,496,474✔
1768
            b = ssa_def_slot(fargs[3], sv)
1,496,474✔
1769
            aty = argtypes[2]
1,496,474✔
1770
            bty = argtypes[3]
1,496,474✔
1771
            # if doing a comparison to a singleton, consider returning a `Conditional` instead
1772
            if isa(aty, Const)
1,496,474✔
1773
                if isa(b, SlotNumber)
255,027✔
1774
                    cndt = egal_condition(aty, bty, InferenceParams(interp).max_union_splitting, rt)
10,655✔
1775
                    return Conditional(b, cndt.thentype, cndt.elsetype)
10,065✔
1776
                elseif isa(bty, MustAlias) && !isa(rt, Const) # skip refinement when the field is known precisely (just optimization)
244,962✔
1777
                    cndt = egal_condition(aty, bty.fldtyp, InferenceParams(interp).max_union_splitting)
×
1778
                    return form_mustalias_conditional(bty, cndt.thentype, cndt.elsetype)
244,962✔
1779
                end
1780
            elseif isa(bty, Const)
1,241,447✔
1781
                if isa(a, SlotNumber)
1,209,993✔
1782
                    cndt = egal_condition(bty, aty, InferenceParams(interp).max_union_splitting, rt)
1,228,287✔
1783
                    return Conditional(a, cndt.thentype, cndt.elsetype)
1,185,027✔
1784
                elseif isa(aty, MustAlias) && !isa(rt, Const) # skip refinement when the field is known precisely (just optimization)
24,966✔
1785
                    cndt = egal_condition(bty, aty.fldtyp, InferenceParams(interp).max_union_splitting)
×
1786
                    return form_mustalias_conditional(aty, cndt.thentype, cndt.elsetype)
×
1787
                end
1788
            end
1789
            # TODO enable multiple constraints propagation here, there are two possible improvements:
1790
            # 1. propagate constraints for both lhs and rhs
1791
            # 2. we can propagate both constraints on aliased fields and slots
1792
            # As for 2, for now, we prioritize constraints on aliased fields, since currently
1793
            # different slots that represent the same object can't share same field constraint,
1794
            # and thus binding `MustAlias` to the other slot is less likely useful
1795
            if !isa(rt, Const) # skip refinement when the field is known precisely (just optimization)
301,382✔
1796
                if isa(bty, MustAlias)
45,575✔
1797
                    thentype = widenslotwrapper(aty)
×
1798
                    elsetype = bty.fldtyp
×
1799
                    if thentype โŠ elsetype
×
1800
                        return form_mustalias_conditional(bty, thentype, elsetype)
×
1801
                    end
1802
                elseif isa(aty, MustAlias)
45,575✔
1803
                    thentype = widenslotwrapper(bty)
×
1804
                    elsetype = aty.fldtyp
×
1805
                    if thentype โŠ elsetype
×
1806
                        return form_mustalias_conditional(aty, thentype, elsetype)
×
1807
                    end
1808
                end
1809
            end
1810
            # narrow the lattice slightly (noting the dependency on one of the slots), to promote more effective smerge
1811
            if isa(b, SlotNumber)
301,382✔
1812
                thentype = rt === Const(false) ? Bottom : widenslotwrapper(bty)
52,109✔
1813
                elsetype = rt === Const(true)  ? Bottom : widenslotwrapper(bty)
61,356✔
1814
                return Conditional(b, thentype, elsetype)
30,678✔
1815
            elseif isa(a, SlotNumber)
270,704✔
1816
                thentype = rt === Const(false) ? Bottom : widenslotwrapper(aty)
291,520✔
1817
                elsetype = rt === Const(true)  ? Bottom : widenslotwrapper(aty)
397,072✔
1818
                return Conditional(a, thentype, elsetype)
270,704✔
1819
            end
1820
        elseif f === Core.Compiler.not_int
1,297,847✔
1821
            aty = argtypes[2]
1,020,797✔
1822
            if isa(aty, Conditional)
1,020,797✔
1823
                thentype = rt === Const(false) ? Bottom : aty.elsetype
2,041,560✔
1824
                elsetype = rt === Const(true)  ? Bottom : aty.thentype
2,041,560✔
1825
                return Conditional(aty.slot, thentype, elsetype)
1,020,797✔
1826
            end
1827
        elseif f === isdefined
277,050✔
1828
            uty = argtypes[2]
100,807✔
1829
            a = ssa_def_slot(fargs[2], sv)
100,807✔
1830
            if isa(uty, Union) && isa(a, SlotNumber)
100,807✔
1831
                fld = argtypes[3]
8✔
1832
                thentype = Bottom
×
1833
                elsetype = Bottom
×
1834
                for ty in uniontypes(uty)
8✔
1835
                    cnd = isdefined_tfunc(๐•ƒแตข, ty, fld)
16✔
1836
                    if isa(cnd, Const)
16✔
1837
                        if cnd.val::Bool
16✔
1838
                            thentype = tmerge(thentype, ty)
8✔
1839
                        else
1840
                            elsetype = tmerge(elsetype, ty)
24✔
1841
                        end
1842
                    else
1843
                        thentype = tmerge(thentype, ty)
×
1844
                        elsetype = tmerge(elsetype, ty)
×
1845
                    end
1846
                end
24✔
1847
                return Conditional(a, thentype, elsetype)
8✔
1848
            end
1849
        end
1850
    end
1851
    @assert !isa(rt, TypeVar) "unhandled TypeVar"
13,703,632✔
1852
    return rt
13,703,632✔
1853
end
1854

1855
function abstract_call_unionall(interp::AbstractInterpreter, argtypes::Vector{Any}, call::CallMeta)
15,610✔
1856
    na = length(argtypes)
15,610✔
1857
    if isvarargtype(argtypes[end])
15,610✔
1858
        if na โ‰ค 2
×
1859
            return CallMeta(Any, EFFECTS_THROWS, call.info)
×
1860
        elseif na > 4
×
1861
            return CallMeta(Bottom, EFFECTS_THROWS, NoCallInfo())
×
1862
        end
1863
        a2 = argtypes[2]
×
1864
        a3 = unwrapva(argtypes[3])
×
1865
        nothrow = false
×
1866
    elseif na == 3
15,610✔
1867
        a2 = argtypes[2]
15,610✔
1868
        a3 = argtypes[3]
15,610✔
1869
        โŠ‘แตข = โŠ‘(typeinf_lattice(interp))
15,603✔
1870
        nothrow = a2 โŠ‘แตข TypeVar && (a3 โŠ‘แตข Type || a3 โŠ‘แตข TypeVar)
15,610✔
1871
    else
1872
        return CallMeta(Bottom, EFFECTS_THROWS, NoCallInfo())
×
1873
    end
1874
    canconst = true
15,610✔
1875
    if isa(a3, Const)
15,610✔
1876
        body = a3.val
2✔
1877
    elseif isType(a3)
19,519✔
1878
        body = a3.parameters[1]
10,818✔
1879
        canconst = false
10,818✔
1880
    else
1881
        return CallMeta(Any, Effects(EFFECTS_TOTAL; nothrow), call.info)
4,790✔
1882
    end
1883
    if !(isa(body, Type) || isa(body, TypeVar))
10,820✔
1884
        return CallMeta(Any, EFFECTS_THROWS, call.info)
×
1885
    end
1886
    if has_free_typevars(body)
21,640✔
1887
        if isa(a2, Const)
10,818✔
1888
            tv = a2.val
×
1889
        elseif isa(a2, PartialTypeVar)
10,818✔
1890
            tv = a2.tv
10,818✔
1891
            canconst = false
10,818✔
1892
        else
1893
            return CallMeta(Any, EFFECTS_THROWS, call.info)
×
1894
        end
1895
        isa(tv, TypeVar) || return CallMeta(Any, EFFECTS_THROWS, call.info)
10,818✔
1896
        body = UnionAll(tv, body)
10,818✔
1897
    end
1898
    ret = canconst ? Const(body) : Type{body}
21,638✔
1899
    return CallMeta(ret, Effects(EFFECTS_TOTAL; nothrow), call.info)
10,820✔
1900
end
1901

1902
function abstract_invoke(interp::AbstractInterpreter, (; fargs, argtypes)::ArgInfo, si::StmtInfo, sv::AbsIntState)
9,476✔
1903
    ftโ€ฒ = argtype_by_index(argtypes, 2)
9,476✔
1904
    ft = widenconst(ftโ€ฒ)
9,476✔
1905
    ft === Bottom && return CallMeta(Bottom, EFFECTS_THROWS, NoCallInfo())
9,476✔
1906
    (types, isexact, isconcrete, istype) = instanceof_tfunc(argtype_by_index(argtypes, 3))
9,476✔
1907
    isexact || return CallMeta(Any, Effects(), NoCallInfo())
9,504✔
1908
    unwrapped = unwrap_unionall(types)
9,449✔
1909
    if types === Bottom || !(unwrapped isa DataType) || unwrapped.name !== Tuple.name
18,895✔
1910
        return CallMeta(Bottom, EFFECTS_THROWS, NoCallInfo())
1✔
1911
    end
1912
    argtype = argtypes_to_type(argtype_tail(argtypes, 4))
9,447✔
1913
    nargtype = typeintersect(types, argtype)
9,447✔
1914
    nargtype === Bottom && return CallMeta(Bottom, EFFECTS_THROWS, NoCallInfo())
9,447✔
1915
    nargtype isa DataType || return CallMeta(Any, Effects(), NoCallInfo()) # other cases are not implemented below
9,447✔
1916
    isdispatchelem(ft) || return CallMeta(Any, Effects(), NoCallInfo()) # check that we might not have a subtype of `ft` at runtime, before doing supertype lookup below
9,448✔
1917
    ft = ft::DataType
9,446✔
1918
    lookupsig = rewrap_unionall(Tuple{ft, unwrapped.parameters...}, types)::Type
9,447✔
1919
    nargtype = Tuple{ft, nargtype.parameters...}
9,446✔
1920
    argtype = Tuple{ft, argtype.parameters...}
9,446✔
1921
    match, valid_worlds = findsup(lookupsig, method_table(interp))
9,509✔
1922
    match === nothing && return CallMeta(Any, Effects(), NoCallInfo())
9,446✔
1923
    update_valid_age!(sv, valid_worlds)
9,446✔
1924
    method = match.method
9,446✔
1925
    tienv = ccall(:jl_type_intersection_with_env, Any, (Any, Any), nargtype, method.sig)::SimpleVector
9,446✔
1926
    ti = tienv[1]; env = tienv[2]::SimpleVector
18,892✔
1927
    result = abstract_call_method(interp, method, ti, env, false, si, sv)
9,446✔
1928
    (; rt, edge, effects) = result
9,446✔
1929
    match = MethodMatch(ti, env, method, argtype <: method.sig)
9,446✔
1930
    res = nothing
81✔
1931
    sig = match.spec_types
81✔
1932
    argtypesโ€ฒ = invoke_rewrite(argtypes)
9,446✔
1933
    fargsโ€ฒ = fargs === nothing ? nothing : invoke_rewrite(fargs)
18,778✔
1934
    arginfo = ArgInfo(fargsโ€ฒ, argtypesโ€ฒ)
18,778✔
1935
    # # typeintersect might have narrowed signature, but the accuracy gain doesn't seem worth the cost involved with the lattice comparisons
1936
    # for i in 1:length(argtypesโ€ฒ)
1937
    #     t, a = ti.parameters[i], argtypesโ€ฒ[i]
1938
    #     argtypesโ€ฒ[i] = t โŠ‘ a ? t : a
1939
    # end
1940
    ๐•ƒโ‚š = ipo_lattice(interp)
18,799✔
1941
    f = singleton_type(ftโ€ฒ)
9,518✔
1942
    invokecall = InvokeCall(types, lookupsig)
9,446✔
1943
    const_call_result = abstract_call_method_with_const_args(interp,
9,446✔
1944
        result, f, arginfo, si, match, sv, invokecall)
1945
    const_result = nothing
81✔
1946
    if const_call_result !== nothing
9,446✔
1947
        if โŠ‘(๐•ƒโ‚š, const_call_result.rt, rt)
3,050✔
1948
            (; rt, effects, const_result, edge) = const_call_result
3,050✔
1949
        end
1950
    end
1951
    rt = from_interprocedural!(interp, rt, sv, arginfo, sig)
9,446✔
1952
    info = InvokeCallInfo(match, const_result)
12,496✔
1953
    edge !== nothing && add_invoke_backedge!(sv, lookupsig, edge)
9,446✔
1954
    return CallMeta(rt, effects, info)
9,446✔
1955
end
1956

1957
function invoke_rewrite(xs::Vector{Any})
240✔
1958
    x0 = xs[2]
35,806✔
1959
    newxs = xs[3:end]
35,806✔
1960
    newxs[1] = x0
35,806✔
1961
    return newxs
35,806✔
1962
end
1963

1964
function abstract_finalizer(interp::AbstractInterpreter, argtypes::Vector{Any}, sv::AbsIntState)
871✔
1965
    if length(argtypes) == 3
896✔
1966
        finalizer_argvec = Any[argtypes[2], argtypes[3]]
1,792✔
1967
        call = abstract_call(interp, ArgInfo(nothing, finalizer_argvec), StmtInfo(false), sv, #=max_methods=#1)
896✔
1968
        return CallMeta(Nothing, Effects(), FinalizerInfo(call.info, call.effects))
896✔
1969
    end
1970
    return CallMeta(Nothing, Effects(), NoCallInfo())
×
1971
end
1972

1973
# call where the function is known exactly
1974
function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f),
40,265,187✔
1975
        arginfo::ArgInfo, si::StmtInfo, sv::AbsIntState,
1976
        max_methods::Int = get_max_methods(interp, f, sv))
1977
    (; fargs, argtypes) = arginfo
40,209,128✔
1978
    la = length(argtypes)
40,205,223✔
1979

1980
    ๐•ƒแตข = typeinf_lattice(interp)
74,957,084✔
1981
    if isa(f, Builtin)
40,205,223✔
1982
        if f === _apply_iterate
18,000,087✔
1983
            return abstract_apply(interp, argtypes, si, sv, max_methods)
947,410✔
1984
        elseif f === invoke
17,052,677✔
1985
            return abstract_invoke(interp, arginfo, si, sv)
9,476✔
1986
        elseif f === modifyfield!
17,043,201✔
1987
            return abstract_modifyfield!(interp, argtypes, si, sv)
579✔
1988
        elseif f === Core.finalizer
17,042,622✔
1989
            return abstract_finalizer(interp, argtypes, sv)
896✔
1990
        elseif f === applicable
17,041,726✔
1991
            return abstract_applicable(interp, argtypes, sv, max_methods)
323✔
1992
        end
1993
        rt = abstract_call_builtin(interp, f, arginfo, sv)
17,098,066✔
1994
        effects = builtin_effects(๐•ƒแตข, f, arginfo, rt)
22,344,358✔
1995
        return CallMeta(rt, effects, NoCallInfo())
17,097,971✔
1996
    elseif isa(f, Core.OpaqueClosure)
22,205,136✔
1997
        # calling an OpaqueClosure about which we have no information returns no information
1998
        return CallMeta(typeof(f).parameters[2], Effects(), NoCallInfo())
2✔
1999
    elseif f === TypeVar
22,205,134✔
2000
        # Manually look through the definition of TypeVar to
2001
        # make sure to be able to get `PartialTypeVar`s out.
2002
        (la < 2 || la > 4) && return CallMeta(Bottom, EFFECTS_THROWS, NoCallInfo())
15,036✔
2003
        n = argtypes[2]
15,036✔
2004
        ub_var = Const(Any)
15,000✔
2005
        lb_var = Const(Union{})
15,000✔
2006
        if la == 4
15,036✔
2007
            ub_var = argtypes[4]
180✔
2008
            lb_var = argtypes[3]
180✔
2009
        elseif la == 3
14,856✔
2010
            ub_var = argtypes[3]
13,972✔
2011
        end
2012
        # make sure generic code is prepared for inlining if needed later
2013
        call = let T = Any[Type{TypeVar}, Any, Any, Any]
60,144✔
2014
            resize!(T, la)
30,072✔
2015
            atype = Tuple{T...}
15,036✔
2016
            T[1] = Const(TypeVar)
15,036✔
2017
            abstract_call_gf_by_type(interp, f, ArgInfo(nothing, T), si, atype, sv, max_methods)
15,036✔
2018
        end
2019
        pT = typevar_tfunc(๐•ƒแตข, n, lb_var, ub_var)
15,036✔
2020
        effects = builtin_effects(๐•ƒแตข, Core._typevar, ArgInfo(nothing,
18,450✔
2021
            Any[Const(Core._typevar), n, lb_var, ub_var]), pT)
2022
        return CallMeta(pT, effects, call.info)
15,036✔
2023
    elseif f === UnionAll
22,190,098✔
2024
        call = abstract_call_gf_by_type(interp, f, ArgInfo(nothing, Any[Const(UnionAll), Any, Any]), si, Tuple{Type{UnionAll}, Any, Any}, sv, max_methods)
46,830✔
2025
        return abstract_call_unionall(interp, argtypes, call)
15,610✔
2026
    elseif f === Tuple && la == 2
22,174,488✔
2027
        aty = argtypes[2]
6,255✔
2028
        ty = isvarargtype(aty) ? unwrapva(aty) : widenconst(aty)
6,255✔
2029
        if !isconcretetype(ty)
6,362✔
2030
            return CallMeta(Tuple, EFFECTS_UNKNOWN, NoCallInfo())
147✔
2031
        end
2032
    elseif is_return_type(f)
22,168,233✔
2033
        return return_type_tfunc(interp, argtypes, si, sv)
28,740✔
2034
    elseif la == 2 && istopfunction(f, :!)
22,139,493✔
2035
        # handle Conditional propagation through !Bool
2036
        aty = argtypes[2]
158,781✔
2037
        if isa(aty, Conditional)
158,781✔
2038
            call = abstract_call_gf_by_type(interp, f, ArgInfo(fargs, Any[Const(f), Bool]), si, Tuple{typeof(f), Bool}, sv, max_methods) # make sure we've inferred `!(::Bool)`
36,662✔
2039
            return CallMeta(Conditional(aty.slot, aty.elsetype, aty.thentype), call.effects, call.info)
157,957✔
2040
        end
2041
    elseif la == 3 && istopfunction(f, :!==)
21,980,712✔
2042
        # mark !== as exactly a negated call to ===
2043
        call = abstract_call_gf_by_type(interp, f, ArgInfo(fargs, Any[Const(f), Any, Any]), si, Tuple{typeof(f), Any, Any}, sv, max_methods)
107,894✔
2044
        rty = abstract_call_known(interp, (===), arginfo, si, sv, max_methods).rt
54,359✔
2045
        if isa(rty, Conditional)
54,359✔
2046
            return CallMeta(Conditional(rty.slot, rty.elsetype, rty.thentype), EFFECTS_TOTAL, NoCallInfo()) # swap if-else
49,596✔
2047
        elseif isa(rty, Const)
4,763✔
2048
            return CallMeta(Const(rty.val === false), EFFECTS_TOTAL, MethodResultPure())
792✔
2049
        end
2050
        return call
3,971✔
2051
    elseif la == 3 && istopfunction(f, :(>:))
21,926,353✔
2052
        # mark issupertype as a exact alias for issubtype
2053
        # swap T1 and T2 arguments and call <:
2054
        if fargs !== nothing && length(fargs) == 3
3,156✔
2055
            fargs = Any[<:, fargs[3], fargs[2]]
9,459✔
2056
        else
2057
            fargs = nothing
3✔
2058
        end
2059
        argtypes = Any[typeof(<:), argtypes[3], argtypes[2]]
9,468✔
2060
        return abstract_call_known(interp, <:, ArgInfo(fargs, argtypes), si, sv, max_methods)
3,156✔
2061
    elseif la == 2 && istopfunction(f, :typename)
21,923,197✔
2062
        return CallMeta(typename_static(argtypes[2]), EFFECTS_TOTAL, MethodResultPure())
1,362✔
2063
    elseif f === Core._hasmethod
21,921,835✔
2064
        return _hasmethod_tfunc(interp, argtypes, sv)
266✔
2065
    end
2066
    atype = argtypes_to_type(argtypes)
22,067,715✔
2067
    return abstract_call_gf_by_type(interp, f, arginfo, si, atype, sv, max_methods)
22,067,715✔
2068
end
2069

2070
function abstract_call_opaque_closure(interp::AbstractInterpreter,
39✔
2071
    closure::PartialOpaque, arginfo::ArgInfo, si::StmtInfo, sv::AbsIntState, check::Bool=true)
2072
    sig = argtypes_to_type(arginfo.argtypes)
39✔
2073
    result = abstract_call_method(interp, closure.source::Method, sig, Core.svec(), false, si, sv)
39✔
2074
    (; rt, edge, effects) = result
39✔
2075
    tt = closure.typ
39✔
2076
    sigT = (unwrap_unionall(tt)::DataType).parameters[1]
66✔
2077
    match = MethodMatch(sig, Core.svec(), closure.source, sig <: rewrap_unionall(sigT, tt))
39✔
2078
    ๐•ƒโ‚š = ipo_lattice(interp)
78✔
2079
    โŠ‘โ‚š = โŠ‘(๐•ƒโ‚š)
39✔
2080
    const_result = nothing
×
2081
    if !result.edgecycle
39✔
2082
        const_call_result = abstract_call_method_with_const_args(interp, result,
39✔
2083
            nothing, arginfo, si, match, sv)
2084
        if const_call_result !== nothing
39✔
2085
            if const_call_result.rt โŠ‘โ‚š rt
9✔
2086
                (; rt, effects, const_result, edge) = const_call_result
9✔
2087
            end
2088
        end
2089
    end
2090
    if check # analyze implicit type asserts on argument and return type
39✔
2091
        ftt = closure.typ
11✔
2092
        (aty, rty) = (unwrap_unionall(ftt)::DataType).parameters
28✔
2093
        rty = rewrap_unionall(rty isa TypeVar ? rty.lb : rty, ftt)
22✔
2094
        if !(rt โŠ‘โ‚š rty && tuple_tfunc(๐•ƒโ‚š, arginfo.argtypes[2:end]) โŠ‘โ‚š rewrap_unionall(aty, ftt))
14✔
2095
            effects = Effects(effects; nothrow=false)
6✔
2096
        end
2097
    end
2098
    rt = from_interprocedural!(interp, rt, sv, arginfo, match.spec_types)
39✔
2099
    info = OpaqueClosureCallInfo(match, const_result)
48✔
2100
    edge !== nothing && add_backedge!(sv, edge)
40✔
2101
    return CallMeta(rt, effects, info)
39✔
2102
end
2103

2104
function most_general_argtypes(closure::PartialOpaque)
×
2105
    ret = Any[]
×
2106
    cc = widenconst(closure)
28✔
2107
    argt = (unwrap_unionall(cc)::DataType).parameters[1]
49✔
2108
    if !isa(argt, DataType) || argt.name !== typename(Tuple)
55✔
2109
        argt = Tuple
×
2110
    end
2111
    return Any[argt.parameters...]
28✔
2112
end
2113

2114
function abstract_call_unknown(interp::AbstractInterpreter, @nospecialize(ft),
295,880✔
2115
                               arginfo::ArgInfo, si::StmtInfo, sv::AbsIntState,
2116
                               max_methods::Int)
2117
    if isa(ft, PartialOpaque)
295,880✔
2118
        newargtypes = copy(arginfo.argtypes)
11✔
2119
        newargtypes[1] = ft.env
11✔
2120
        return abstract_call_opaque_closure(interp,
11✔
2121
            ft, ArgInfo(arginfo.fargs, newargtypes), si, sv, #=check=#true)
2122
    end
2123
    wft = widenconst(ft)
295,869✔
2124
    if hasintersect(wft, Builtin)
295,869✔
2125
        add_remark!(interp, sv, "Could not identify method table for call")
1✔
2126
        return CallMeta(Any, Effects(), NoCallInfo())
15,064✔
2127
    elseif hasintersect(wft, Core.OpaqueClosure)
280,805✔
2128
        uft = unwrap_unionall(wft)
5✔
2129
        if isa(uft, DataType)
3✔
2130
            return CallMeta(rewrap_unionall(uft.parameters[2], wft), Effects(), NoCallInfo())
3✔
2131
        end
2132
        return CallMeta(Any, Effects(), NoCallInfo())
×
2133
    end
2134
    # non-constant function, but the number of arguments is known and the `f` is not a builtin or intrinsic
2135
    atype = argtypes_to_type(arginfo.argtypes)
280,802✔
2136
    return abstract_call_gf_by_type(interp, nothing, arginfo, si, atype, sv, max_methods)
280,802✔
2137
end
2138

2139
# call where the function is any lattice element
2140
function abstract_call(interp::AbstractInterpreter, arginfo::ArgInfo, si::StmtInfo,
80,016,766✔
2141
                       sv::AbsIntState, max_methods::Int=typemin(Int))
2142
    ft = widenslotwrapper(arginfo.argtypes[1])
80,016,766✔
2143
    f = singleton_type(ft)
40,792,635✔
2144
    if f === nothing
40,496,749✔
2145
        max_methods = max_methods == typemin(Int) ? get_max_methods(interp, sv) : max_methods
586,200✔
2146
        return abstract_call_unknown(interp, ft, arginfo, si, sv, max_methods)
295,880✔
2147
    end
2148
    max_methods = max_methods == typemin(Int) ? get_max_methods(interp, f, sv) : max_methods
79,141,511✔
2149
    return abstract_call_known(interp, f, arginfo, si, sv, max_methods)
40,200,869✔
2150
end
2151

2152
function sp_type_rewrap(@nospecialize(T), linfo::MethodInstance, isreturn::Bool)
92,871✔
2153
    isref = false
×
2154
    if unwrapva(T) === Bottom
92,871✔
2155
        return Bottom
6✔
2156
    elseif isa(T, Type)
92,865✔
2157
        if isa(T, DataType) && (T::DataType).name === Ref.body.name
91,956✔
2158
            isref = true
10,160✔
2159
            T = T.parameters[1]
10,160✔
2160
            if isreturn && T === Any
10,160✔
2161
                return Bottom # a return type of Ref{Any} is invalid
×
2162
            end
2163
        end
2164
    else
2165
        return Any
909✔
2166
    end
2167
    if isa(linfo.def, Method)
91,956✔
2168
        spsig = linfo.def.sig
91,756✔
2169
        if isa(spsig, UnionAll)
91,756✔
2170
            if !isempty(linfo.sparam_vals)
32,365✔
2171
                sparam_vals = Any[isvarargtype(v) ? TypeVar(:N, Union{}, Any) :
44,461✔
2172
                                  v for v in  linfo.sparam_vals]
2173
                T = ccall(:jl_instantiate_type_in_env, Any, (Any, Any, Ptr{Any}), T, spsig, sparam_vals)
32,365✔
2174
                isref && isreturn && T === Any && return Bottom # catch invalid return Ref{T} where T = Any
32,365✔
2175
                for v in sparam_vals
32,365✔
2176
                    if isa(v, TypeVar)
44,461✔
2177
                        T = UnionAll(v, T)
809✔
2178
                    end
2179
                end
76,826✔
2180
                if has_free_typevars(T)
32,365✔
2181
                    fv = ccall(:jl_find_free_typevars, Vector{Any}, (Any,), T)
×
2182
                    for v in fv
×
2183
                        T = UnionAll(v, T)
×
2184
                    end
×
2185
                end
2186
            else
2187
                T = rewrap_unionall(T, spsig)
×
2188
            end
2189
        end
2190
    end
2191
    return unwraptv(T)
91,956✔
2192
end
2193

2194
function abstract_eval_cfunction(interp::AbstractInterpreter, e::Expr, vtypes::Union{VarTable,Nothing}, sv::AbsIntState)
950✔
2195
    f = abstract_eval_value(interp, e.args[2], vtypes, sv)
1,898✔
2196
    # rt = sp_type_rewrap(e.args[3], sv.linfo, true)
2197
    atv = e.args[4]::SimpleVector
950✔
2198
    at = Vector{Any}(undef, length(atv) + 1)
950✔
2199
    at[1] = f
950✔
2200
    for i = 1:length(atv)
1,892✔
2201
        at[i + 1] = sp_type_rewrap(at[i], frame_instance(sv), false)
1,942✔
2202
        at[i + 1] === Bottom && return
1,942✔
2203
    end
2,942✔
2204
    # this may be the wrong world for the call,
2205
    # but some of the result is likely to be valid anyways
2206
    # and that may help generate better codegen
2207
    abstract_call(interp, ArgInfo(nothing, at), StmtInfo(false), sv)
950✔
2208
    nothing
950✔
2209
end
2210

2211
function abstract_eval_special_value(interp::AbstractInterpreter, @nospecialize(e), vtypes::Union{VarTable,Nothing}, sv::AbsIntState)
91,623✔
2212
    if isa(e, QuoteNode)
141,784,673✔
2213
        return Const(e.value)
4,221,634✔
2214
    elseif isa(e, SSAValue)
137,563,039✔
2215
        return abstract_eval_ssavalue(e, sv)
38,599,720✔
2216
    elseif isa(e, SlotNumber)
98,963,319✔
2217
        if vtypes !== nothing
26,747✔
2218
            vtyp = vtypes[slot_id(e)]
33,457,568✔
2219
            if vtyp.undef
33,457,568✔
2220
                merge_effects!(interp, sv, Effects(EFFECTS_TOTAL; nothrow=false))
29,807✔
2221
            end
2222
            return vtyp.typ
33,457,568✔
2223
        end
2224
        merge_effects!(interp, sv, Effects(EFFECTS_TOTAL; nothrow=false))
×
2225
        return Any
×
2226
    elseif isa(e, Argument)
65,505,751✔
2227
        if vtypes !== nothing
8✔
2228
            return vtypes[slot_id(e)].typ
×
2229
        else
2230
            @assert isa(sv, IRInterpretationState)
8✔
2231
            return sv.ir.argtypes[e.n] # TODO frame_argtypes(sv)[e.n] and remove the assertion
6,417,639✔
2232
        end
2233
    elseif isa(e, GlobalRef)
59,088,112✔
2234
        return abstract_eval_globalref(interp, e, sv)
44,066,599✔
2235
    end
2236

2237
    return Const(e)
15,021,513✔
2238
end
2239

2240
function abstract_eval_value_expr(interp::AbstractInterpreter, e::Expr, vtypes::Union{VarTable,Nothing}, sv::AbsIntState)
1,446,573✔
2241
    head = e.head
1,446,573✔
2242
    if head === :static_parameter
1,446,573✔
2243
        n = e.args[1]::Int
1,446,536✔
2244
        nothrow = false
2,551✔
2245
        if 1 <= n <= length(sv.sptypes)
1,446,536✔
2246
            sp = sv.sptypes[n]
1,446,536✔
2247
            rt = sp.typ
1,446,536✔
2248
            nothrow = !sp.undef
1,446,536✔
2249
        else
2250
            rt = Any
×
2251
        end
2252
        merge_effects!(interp, sv, Effects(EFFECTS_TOTAL; nothrow))
2,720,711✔
2253
        return rt
1,446,536✔
2254
    elseif head === :call
37✔
2255
        # TODO: We still have non-linearized cglobal
2256
        @assert e.args[1] === Core.tuple ||
72✔
2257
                e.args[1] === GlobalRef(Core, :tuple)
2258
    else
2259
        # Some of our tests expect us to handle invalid IR here and error later
2260
        # - permit that for now.
2261
        # @assert false "Unexpected EXPR head in value position"
2262
        merge_effects!(interp, sv, EFFECTS_UNKNOWN)
1✔
2263
    end
2264
    return Any
37✔
2265
end
2266

2267
function abstract_eval_value(interp::AbstractInterpreter, @nospecialize(e), vtypes::Union{VarTable,Nothing}, sv::AbsIntState)
200,243✔
2268
    if isa(e, Expr)
131,606,746✔
2269
        return abstract_eval_value_expr(interp, e, vtypes, sv)
1,446,573✔
2270
    else
2271
        typ = abstract_eval_special_value(interp, e, vtypes, sv)
256,111,020✔
2272
        return collect_limitations!(typ, sv)
130,160,173✔
2273
    end
2274
end
2275

2276
function collect_argtypes(interp::AbstractInterpreter, ea::Vector{Any}, vtypes::Union{VarTable,Nothing}, sv::AbsIntState)
39,490,848✔
2277
    n = length(ea)
39,523,465✔
2278
    argtypes = Vector{Any}(undef, n)
39,523,465✔
2279
    @inbounds for i = 1:n
79,046,930✔
2280
        ai = abstract_eval_value(interp, ea[i], vtypes, sv)
233,629,154✔
2281
        if ai === Bottom
117,565,735✔
2282
            return nothing
19✔
2283
        end
2284
        argtypes[i] = ai
117,565,716✔
2285
    end
195,607,986✔
2286
    return argtypes
39,523,446✔
2287
end
2288

2289
struct RTEffects
2290
    rt
2291
    effects::Effects
2292
    RTEffects(@nospecialize(rt), effects::Effects) = new(rt, effects)
80,854,353✔
2293
end
2294

2295
function abstract_call(interp::AbstractInterpreter, arginfo::ArgInfo, sv::InferenceState)
34,264,453✔
2296
    si = StmtInfo(!call_result_unused(sv, sv.currpc))
34,264,453✔
2297
    (; rt, effects, info) = abstract_call(interp, arginfo, si, sv)
34,264,453✔
2298
    sv.stmt_info[sv.currpc] = info
34,264,432✔
2299
    # mark this call statement as DCE-elgible
2300
    # TODO better to do this in a single pass based on the `info` object at the end of abstractinterpret?
2301
    return RTEffects(rt, effects)
34,264,432✔
2302
end
2303

2304
function abstract_eval_call(interp::AbstractInterpreter, e::Expr, vtypes::Union{VarTable,Nothing},
39,519,086✔
2305
                            sv::AbsIntState)
2306
    ea = e.args
39,519,086✔
2307
    argtypes = collect_argtypes(interp, ea, vtypes, sv)
39,615,424✔
2308
    if argtypes === nothing
39,519,086✔
2309
        return RTEffects(Bottom, Effects())
19✔
2310
    end
2311
    arginfo = ArgInfo(ea, argtypes)
39,519,067✔
2312
    return abstract_call(interp, arginfo, sv)
39,519,067✔
2313
end
2314

2315
function abstract_eval_statement_expr(interp::AbstractInterpreter, e::Expr, vtypes::Union{VarTable,Nothing},
41,244,381✔
2316
                                      sv::AbsIntState)
2317
    effects = Effects()
26,527✔
2318
    ehead = e.head
41,244,381✔
2319
    ๐•ƒแตข = typeinf_lattice(interp)
76,716,338✔
2320
    โŠ‘แตข = โŠ‘(๐•ƒแตข)
46,888,812✔
2321
    if ehead === :call
41,244,381✔
2322
        (; rt, effects) = abstract_eval_call(interp, e, vtypes, sv)
39,519,086✔
2323
        t = rt
39,519,058✔
2324
    elseif ehead === :new
1,725,295✔
2325
        t, isexact = instanceof_tfunc(abstract_eval_value(interp, e.args[1], vtypes, sv))
1,668,948✔
2326
        ut = unwrap_unionall(t)
916,346✔
2327
        consistent = noub = ALWAYS_FALSE
164✔
2328
        nothrow = false
164✔
2329
        if isa(ut, DataType) && !isabstracttype(ut)
834,611✔
2330
            ismutable = ismutabletype(ut)
834,597✔
2331
            fcount = datatype_fieldcount(ut)
834,597✔
2332
            nargs = length(e.args) - 1
834,597✔
2333
            if (fcount === nothing || (fcount > nargs && (let t = t
1,669,194✔
2334
                    any(i::Int -> !is_undefref_fieldtype(fieldtype(t, i)), (nargs+1):fcount)
11,721✔
2335
                end)))
2336
                # allocation with undefined field leads to undefined behavior and should taint `:noub`
2337
            elseif ismutable
834,011✔
2338
                # mutable object isn't `:consistent`, but we still have a chance that
2339
                # return type information later refines the `:consistent`-cy of the method
2340
                consistent = CONSISTENT_IF_NOTRETURNED
87✔
2341
                noub = ALWAYS_TRUE
11,699✔
2342
            else
2343
                consistent = ALWAYS_TRUE
74✔
2344
                noub = ALWAYS_TRUE
74✔
2345
            end
2346
            if isconcretedispatch(t)
1,596,631✔
2347
                nothrow = true
157✔
2348
                @assert fcount !== nothing && fcount โ‰ฅ nargs "malformed :new expression" # syntactically enforced by the front-end
762,034✔
2349
                ats = Vector{Any}(undef, nargs)
762,034✔
2350
                local anyrefine = false
157✔
2351
                local allconst = true
157✔
2352
                for i = 1:nargs
1,467,557✔
2353
                    at = widenslotwrapper(abstract_eval_value(interp, e.args[i+1], vtypes, sv))
1,625,068✔
2354
                    ft = fieldtype(t, i)
1,625,044✔
2355
                    nothrow && (nothrow = at โŠ‘แตข ft)
2,517,116✔
2356
                    at = tmeet(๐•ƒแตข, at, ft)
2,517,300✔
2357
                    at === Bottom && @goto always_throw
1,625,044✔
2358
                    if ismutable && !isconst(t, i)
1,625,039✔
2359
                        ats[i] = ft # can't constrain this field (as it may be modified later)
40,049✔
2360
                        continue
40,049✔
2361
                    end
2362
                    allconst &= isa(at, Const)
1,584,990✔
2363
                    if !anyrefine
1,584,990✔
2364
                        anyrefine = has_nontrivial_extended_info(๐•ƒแตข, at) || # extended lattice information
1,606,236✔
2365
                                    โ‹ค(๐•ƒแตข, at, ft) # just a type-level information, but more precise than the declared type
2366
                    end
2367
                    ats[i] = at
1,584,990✔
2368
                end
2,544,560✔
2369
                # For now, don't allow:
2370
                # - Const/PartialStruct of mutables (but still allow PartialStruct of mutables
2371
                #   with `const` fields if anything refined)
2372
                # - partially initialized Const/PartialStruct
2373
                if fcount == nargs
762,029✔
2374
                    if consistent === ALWAYS_TRUE && allconst
760,634✔
2375
                        argvals = Vector{Any}(undef, nargs)
97,615✔
2376
                        for j in 1:nargs
139,234✔
2377
                            argvals[j] = (ats[j]::Const).val
66,867✔
2378
                        end
92,115✔
2379
                        t = Const(ccall(:jl_new_structv, Any, (Any, Ptr{Cvoid}, UInt32), t, argvals, nargs))
97,615✔
2380
                    elseif anyrefine
663,019✔
2381
                        t = PartialStruct(t, ats)
1,260,681✔
2382
                    end
2383
                end
2384
            else
2385
                t = refine_partial_type(t)
72,563✔
2386
            end
2387
        end
2388
        effects = Effects(EFFECTS_TOTAL; consistent, nothrow, noub)
834,606✔
2389
    elseif ehead === :splatnew
890,684✔
2390
        t, isexact = instanceof_tfunc(abstract_eval_value(interp, e.args[1], vtypes, sv))
29,556✔
2391
        nothrow = false # TODO: More precision
23✔
2392
        if length(e.args) == 2 && isconcretedispatch(t) && !ismutabletype(t)
28,193✔
2393
            at = abstract_eval_value(interp, e.args[2], vtypes, sv)
26,739✔
2394
            n = fieldcount(t)
13,392✔
2395
            if (isa(at, Const) && isa(at.val, Tuple) && n == length(at.val::Tuple) &&
13,392✔
2396
                (let t = t, at = at
2397
                    all(i::Int->getfield(at.val::Tuple, i) isa fieldtype(t, i), 1:n)
12,374✔
2398
                end))
2399
                nothrow = isexact
4,054✔
2400
                t = Const(ccall(:jl_new_structt, Any, (Any, Any), t, at.val))
4,054✔
2401
            elseif (isa(at, PartialStruct) && at โŠ‘แตข Tuple && n > 0 && n == length(at.fields::Vector{Any}) && !isvarargtype(at.fields[end]) &&
9,338✔
2402
                    (let t = t, at = at, โŠ‘แตข = โŠ‘แตข
2403
                        all(i::Int->(at.fields::Vector{Any})[i] โŠ‘แตข fieldtype(t, i), 1:n)
3,988✔
2404
                    end))
2405
                nothrow = isexact
1,143✔
2406
                t = PartialStruct(t, at.fields::Vector{Any})
14,535✔
2407
            end
2408
        else
2409
            t = refine_partial_type(t)
1,409✔
2410
        end
2411
        consistent = !ismutabletype(t) ? ALWAYS_TRUE : CONSISTENT_IF_NOTRETURNED
19,998✔
2412
        effects = Effects(EFFECTS_TOTAL; consistent, nothrow)
14,801✔
2413
    elseif ehead === :new_opaque_closure
875,883✔
2414
        t = Union{}
×
2415
        effects = Effects() # TODO
×
2416
        merge_effects!(interp, sv, effects)
28✔
2417
        if length(e.args) >= 4
28✔
2418
            ea = e.args
28✔
2419
            argtypes = collect_argtypes(interp, ea, vtypes, sv)
28✔
2420
            if argtypes === nothing
28✔
2421
                t = Bottom
×
2422
            else
2423
                mi = frame_instance(sv)
28✔
2424
                t = opaque_closure_tfunc(๐•ƒแตข, argtypes[1], argtypes[2], argtypes[3],
28✔
2425
                    argtypes[4], argtypes[5:end], mi)
2426
                if isa(t, PartialOpaque) && isa(sv, InferenceState) && !call_result_unused(sv, sv.currpc)
28✔
2427
                    # Infer this now so that the specialization is available to
2428
                    # optimization.
2429
                    argtypes = most_general_argtypes(t)
55✔
2430
                    pushfirst!(argtypes, t.env)
28✔
2431
                    callinfo = abstract_call_opaque_closure(interp, t,
28✔
2432
                        ArgInfo(nothing, argtypes), StmtInfo(true), sv, #=check=#false)
2433
                    sv.stmt_info[sv.currpc] = OpaqueClosureCreateInfo(callinfo)
56✔
2434
                end
2435
            end
2436
        end
2437
    elseif ehead === :foreigncall
875,855✔
2438
        (; rt, effects) = abstract_eval_foreigncall(interp, e, vtypes, sv)
90,929✔
2439
        t = rt
90,929✔
2440
    elseif ehead === :cfunction
784,926✔
2441
        effects = EFFECTS_UNKNOWN
×
2442
        t = e.args[1]
950✔
2443
        isa(t, Type) || (t = Any)
950✔
2444
        abstract_eval_cfunction(interp, e, vtypes, sv)
950✔
2445
    elseif ehead === :method
783,976✔
2446
        t = (length(e.args) == 1) ? Any : Nothing
×
2447
        effects = EFFECTS_UNKNOWN
×
2448
    elseif ehead === :copyast
783,976✔
2449
        effects = EFFECTS_UNKNOWN
×
2450
        t = abstract_eval_value(interp, e.args[1], vtypes, sv)
10,642✔
2451
        if t isa Const && t.val isa Expr
5,322✔
2452
            # `copyast` makes copies of Exprs
2453
            t = Expr
5,322✔
2454
        end
2455
    elseif ehead === :invoke || ehead === :invoke_modify
1,557,308✔
2456
        error("type inference data-flow error: tried to double infer a function")
×
2457
    elseif ehead === :isdefined
778,654✔
2458
        sym = e.args[1]
8,958✔
2459
        t = Bool
4✔
2460
        effects = EFFECTS_TOTAL
4✔
2461
        if isa(sym, SlotNumber) && vtypes !== nothing
8,958✔
2462
            vtyp = vtypes[slot_id(sym)]
843✔
2463
            if vtyp.typ === Bottom
843✔
2464
                t = Const(false) # never assigned previously
115✔
2465
            elseif !vtyp.undef
728✔
2466
                t = Const(true) # definitely assigned previously
843✔
2467
            end
2468
        elseif isa(sym, Symbol)
8,115✔
2469
            if isdefined(frame_module(sv), sym)
×
2470
                t = Const(true)
×
2471
            elseif InferenceParams(interp).assume_bindings_static
×
2472
                t = Const(false)
×
2473
            else
2474
                effects = Effects(EFFECTS_TOTAL; consistent=ALWAYS_FALSE)
×
2475
            end
2476
        elseif isa(sym, GlobalRef)
8,115✔
2477
            if isdefined(sym.mod, sym.name)
92✔
2478
                t = Const(true)
76✔
2479
            elseif InferenceParams(interp).assume_bindings_static
16✔
2480
                t = Const(false)
×
2481
            else
2482
                effects = Effects(EFFECTS_TOTAL; consistent=ALWAYS_FALSE)
92✔
2483
            end
2484
        elseif isexpr(sym, :static_parameter)
8,023✔
2485
            n = sym.args[1]::Int
8,023✔
2486
            if 1 <= n <= length(sv.sptypes)
8,023✔
2487
                sp = sv.sptypes[n]
8,023✔
2488
                if !sp.undef
8,023✔
2489
                    t = Const(true)
7,896✔
2490
                elseif sp.typ === Bottom
127✔
2491
                    t = Const(false)
8,023✔
2492
                end
2493
            end
2494
        else
2495
            effects = EFFECTS_UNKNOWN
8,958✔
2496
        end
2497
    elseif ehead === :throw_undef_if_not
769,696✔
2498
        condt = argextype(stmt.args[2], ir)
×
2499
        condval = maybe_extract_const_bool(condt)
×
2500
        t = Nothing
×
2501
        effects = EFFECTS_THROWS
×
2502
        if condval isa Bool
×
2503
            if condval
×
2504
                effects = EFFECTS_TOTAL
×
2505
            else
2506
                t = Union{}
×
2507
            end
2508
        elseif !hasintersect(windenconst(condt), Bool)
×
2509
            t = Union{}
×
2510
        end
2511
    elseif ehead === :boundscheck
769,696✔
2512
        t = Bool
304✔
2513
        effects = Effects(EFFECTS_TOTAL; consistent=ALWAYS_FALSE)
336,134✔
2514
    elseif ehead === :the_exception
433,562✔
2515
        t = Any
20✔
2516
        effects = Effects(EFFECTS_TOTAL; consistent=ALWAYS_FALSE)
41,745✔
2517
    elseif ehead === :static_parameter
391,817✔
2518
        n = e.args[1]::Int
211,545✔
2519
        nothrow = false
274✔
2520
        if 1 <= n <= length(sv.sptypes)
211,545✔
2521
            sp = sv.sptypes[n]
211,545✔
2522
            t = sp.typ
211,545✔
2523
            nothrow = !sp.undef
211,545✔
2524
        else
2525
            t = Any
×
2526
        end
2527
        effects = Effects(EFFECTS_TOTAL; nothrow)
211,545✔
2528
    elseif ehead === :gc_preserve_begin || ehead === :aliasscope
349,481✔
2529
        t = Any
14✔
2530
        effects = Effects(EFFECTS_TOTAL; consistent=ALWAYS_FALSE, effect_free=EFFECT_FREE_GLOBALLY)
11,064✔
2531
    elseif ehead === :gc_preserve_end || ehead === :leave || ehead === :pop_exception || ehead === :global || ehead === :popaliasscope
327,619✔
2532
        t = Nothing
113✔
2533
        effects = Effects(EFFECTS_TOTAL; effect_free=EFFECT_FREE_GLOBALLY)
169,207✔
2534
    elseif ehead === :method
1✔
2535
        t = Method
×
2536
        effects = Effects(EFFECTS_TOTAL; effect_free=EFFECT_FREE_GLOBALLY)
×
2537
    elseif ehead === :thunk
1✔
2538
        t = Any
×
2539
        effects = EFFECTS_UNKNOWN
1✔
2540
    elseif false
×
2541
        @label always_throw
×
2542
        t = Bottom
×
2543
        effects = EFFECTS_THROWS
×
2544
    else
2545
        t = abstract_eval_value_expr(interp, e, vtypes, sv)
×
2546
        # N.B.: abstract_eval_value_expr can modify the global effects, but
2547
        # we move out any arguments with effects during SSA construction later
2548
        # and recompute the effects.
2549
        effects = EFFECTS_TOTAL
×
2550
    end
2551
    return RTEffects(t, effects)
41,244,353✔
2552
end
2553

2554
# refine the result of instantiation of partially-known type `t` if some invariant can be assumed
2555
function refine_partial_type(@nospecialize t)
73,972✔
2556
    tโ€ฒ = unwrap_unionall(t)
157,157✔
2557
    if isa(tโ€ฒ, DataType) && tโ€ฒ.name === _NAMEDTUPLE_NAME && length(tโ€ฒ.parameters) == 2 &&
75,496✔
2558
        (tโ€ฒ.parameters[1] === () || tโ€ฒ.parameters[2] === Tuple{})
2559
        # if the first/second parameter of `NamedTuple` is known to be empty,
2560
        # the second/first argument should also be empty tuple type,
2561
        # so refine it here
2562
        return Const(NamedTuple())
×
2563
    end
2564
    return t
73,972✔
2565
end
2566

2567
function abstract_eval_foreigncall(interp::AbstractInterpreter, e::Expr, vtypes::Union{VarTable,Nothing}, sv::AbsIntState)
90,929✔
2568
    mi = frame_instance(sv)
90,929✔
2569
    t = sp_type_rewrap(e.args[2], mi, true)
90,929✔
2570
    for i = 3:length(e.args)
181,858✔
2571
        if abstract_eval_value(interp, e.args[i], vtypes, sv) === Bottom
1,373,858✔
2572
            return RTEffects(Bottom, EFFECTS_THROWS)
×
2573
        end
2574
    end
1,284,207✔
2575
    effects = foreigncall_effects(e) do @nospecialize x
91,507✔
2576
        abstract_eval_value(interp, x, vtypes, sv)
69,912✔
2577
    end
2578
    cconv = e.args[5]
90,929✔
2579
    if isa(cconv, QuoteNode) && (v = cconv.value; isa(v, Tuple{Symbol, UInt8}))
181,858✔
2580
        override = decode_effects_override(v[2])
848✔
2581
        effects = Effects(effects;
848✔
2582
            consistent          = override.consistent ? ALWAYS_TRUE : effects.consistent,
2583
            effect_free         = override.effect_free ? ALWAYS_TRUE : effects.effect_free,
2584
            nothrow             = override.nothrow ? true : effects.nothrow,
2585
            terminates          = override.terminates_globally ? true : effects.terminates,
2586
            notaskstate         = override.notaskstate ? true : effects.notaskstate,
2587
            inaccessiblememonly = override.inaccessiblememonly ? ALWAYS_TRUE : effects.inaccessiblememonly,
2588
            noub                = override.noub ? ALWAYS_TRUE : effects.noub)
2589
    end
2590
    return RTEffects(t, effects)
90,929✔
2591
end
2592

2593
function abstract_eval_phi(interp::AbstractInterpreter, phi::PhiNode, vtypes::Union{VarTable,Nothing}, sv::AbsIntState)
474,541✔
2594
    rt = Union{}
2✔
2595
    for i in 1:length(phi.values)
949,074✔
2596
        isassigned(phi.values, i) || continue
936,985✔
2597
        val = phi.values[i]
936,985✔
2598
        rt = tmerge(typeinf_lattice(interp), rt, abstract_eval_special_value(interp, val, vtypes, sv))
936,987✔
2599
    end
1,399,437✔
2600
    return rt
474,541✔
2601
end
2602

2603
function stmt_taints_inbounds_consistency(sv::AbsIntState)
×
2604
    propagate_inbounds(sv) && return true
×
2605
    return (get_curr_ssaflag(sv) & IR_FLAG_INBOUNDS) != 0
×
2606
end
2607

2608
function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e), vtypes::VarTable, sv::InferenceState)
46,253,593✔
2609
    if !isa(e, Expr)
46,253,593✔
2610
        if isa(e, PhiNode)
10,687,515✔
2611
            add_curr_ssaflag!(sv, IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW)
×
2612
            return abstract_eval_phi(interp, e, vtypes, sv)
×
2613
        end
2614
        return abstract_eval_special_value(interp, e, vtypes, sv)
10,687,515✔
2615
    end
2616
    (; rt, effects) = abstract_eval_statement_expr(interp, e, vtypes, sv)
35,566,078✔
2617
    if effects.noub === NOUB_IF_NOINBOUNDS
35,566,057✔
2618
        if !iszero(get_curr_ssaflag(sv) & IR_FLAG_INBOUNDS)
116,097✔
2619
            effects = Effects(effects; noub=ALWAYS_FALSE)
4,519✔
2620
        elseif !propagate_inbounds(sv)
111,578✔
2621
            # The callee read our inbounds flag, but unless we propagate inbounds,
2622
            # we ourselves don't read our parent's inbounds.
2623
            effects = Effects(effects; noub=ALWAYS_TRUE)
109,618✔
2624
        end
2625
    end
2626
    # N.B.: This only applies to the effects of the statement itself.
2627
    # It is possible for arguments (GlobalRef/:static_parameter) to throw,
2628
    # but these will be recomputed during SSA construction later.
2629
    set_curr_ssaflag!(sv, flags_for_effects(effects), IR_FLAGS_EFFECTS)
40,177,896✔
2630
    merge_effects!(interp, sv, effects)
55,304,130✔
2631
    e = e::Expr
26,477✔
2632
    @assert !isa(rt, TypeVar) "unhandled TypeVar"
35,566,057✔
2633
    rt = maybe_singleton_const(rt)
54,515,748✔
2634
    if !isempty(sv.pclimitations)
35,978,657✔
2635
        if rt isa Const || rt === Union{}
824,384✔
2636
            empty!(sv.pclimitations)
870✔
2637
        else
2638
            rt = LimitedAccuracy(rt, sv.pclimitations)
411,730✔
2639
            sv.pclimitations = IdSet{InferenceState}()
411,730✔
2640
        end
2641
    end
2642
    return rt
35,566,057✔
2643
end
2644

2645
function isdefined_globalref(g::GlobalRef)
52✔
2646
    return ccall(:jl_globalref_boundp, Cint, (Any,), g) != 0
840,586,311✔
2647
end
2648

2649
function abstract_eval_globalref(g::GlobalRef)
29,283✔
2650
    if isdefined_globalref(g) && isconst(g)
840,574,975✔
2651
        return Const(ccall(:jl_get_globalref_value, Any, (Any,), g))
840,557,514✔
2652
    end
2653
    ty = ccall(:jl_get_binding_type, Any, (Any, Any), g.mod, g.name)
17,461✔
2654
    ty === nothing && return Any
17,461✔
2655
    return ty
16,484✔
2656
end
2657
abstract_eval_global(M::Module, s::Symbol) = abstract_eval_globalref(GlobalRef(M, s))
33,259✔
2658

2659
function abstract_eval_globalref(interp::AbstractInterpreter, g::GlobalRef, sv::AbsIntState)
44,066,016✔
2660
    rt = abstract_eval_globalref(g)
44,076,726✔
2661
    consistent = inaccessiblememonly = ALWAYS_FALSE
29,068✔
2662
    nothrow = false
29,068✔
2663
    if isa(rt, Const)
44,066,016✔
2664
        consistent = ALWAYS_TRUE
44,055,306✔
2665
        nothrow = true
29,059✔
2666
        if is_mutation_free_argtype(rt)
84,125,104✔
2667
            inaccessiblememonly = ALWAYS_TRUE
44,055,273✔
2668
        end
2669
    elseif isdefined_globalref(g)
10,710✔
2670
        nothrow = true
9,902✔
2671
    elseif InferenceParams(interp).assume_bindings_static
808✔
2672
        consistent = inaccessiblememonly = ALWAYS_TRUE
×
2673
        rt = Union{}
×
2674
    end
2675
    merge_effects!(interp, sv, Effects(EFFECTS_TOTAL; consistent, nothrow, inaccessiblememonly))
66,014,694✔
2676
    return rt
44,066,016✔
2677
end
2678

2679
function handle_global_assignment!(interp::AbstractInterpreter, frame::InferenceState, lhs::GlobalRef, @nospecialize(newty))
18✔
2680
    effect_free = ALWAYS_FALSE
18✔
2681
    nothrow = global_assignment_nothrow(lhs.mod, lhs.name, newty)
1,824✔
2682
    inaccessiblememonly = ALWAYS_FALSE
18✔
2683
    if !nothrow
990✔
2684
        sub_curr_ssaflag!(frame, IR_FLAG_NOTHROW)
156✔
2685
    end
2686
    sub_curr_ssaflag!(frame, IR_FLAG_EFFECT_FREE)
990✔
2687
    merge_effects!(interp, frame, Effects(EFFECTS_TOTAL; effect_free, nothrow, inaccessiblememonly))
1,853✔
2688
    return nothing
990✔
2689
end
2690

2691
abstract_eval_ssavalue(s::SSAValue, sv::InferenceState) = abstract_eval_ssavalue(s, sv.ssavaluetypes)
69,948,050✔
2692

2693
function abstract_eval_ssavalue(s::SSAValue, ssavaluetypes::Vector{Any})
2✔
2694
    typ = ssavaluetypes[s.id]
34,974,027✔
2695
    if typ === NOT_FOUND
34,974,027✔
2696
        return Bottom
×
2697
    end
2698
    return typ
34,974,027✔
2699
end
2700

2701
struct BestguessInfo{Interp<:AbstractInterpreter}
2702
    interp::Interp
2703
    bestguess
2704
    nargs::Int
2705
    slottypes::Vector{Any}
2706
    changes::VarTable
2707
    function BestguessInfo(interp::Interp, @nospecialize(bestguess), nargs::Int,
9,479✔
2708
        slottypes::Vector{Any}, changes::VarTable) where Interp<:AbstractInterpreter
2709
        new{Interp}(interp, bestguess, nargs, slottypes, changes)
5,823,674✔
2710
    end
2711
end
2712

2713
@nospecializeinfer function widenreturn(@nospecialize(rt), info::BestguessInfo)
9,479✔
2714
    return widenreturn(typeinf_lattice(info.interp), rt, info)
5,823,674✔
2715
end
2716

2717
@nospecializeinfer function widenreturn(๐•ƒแตข::AbstractLattice, @nospecialize(rt), info::BestguessInfo)
9,479✔
2718
    return widenreturn(widenlattice(๐•ƒแตข), rt, info)
5,823,674✔
2719
end
2720
@nospecializeinfer function widenreturn_noslotwrapper(๐•ƒแตข::AbstractLattice, @nospecialize(rt), info::BestguessInfo)
5,404,574✔
2721
    return widenreturn_noslotwrapper(widenlattice(๐•ƒแตข), rt, info)
5,404,574✔
2722
end
2723

2724
@nospecializeinfer function widenreturn(๐•ƒแตข::MustAliasesLattice, @nospecialize(rt), info::BestguessInfo)
×
2725
    if isa(rt, MustAlias)
×
2726
        if 1 โ‰ค rt.slot โ‰ค info.nargs
×
2727
            rt = InterMustAlias(rt)
×
2728
        else
2729
            rt = widenmustalias(rt)
×
2730
        end
2731
    end
2732
    isa(rt, InterMustAlias) && return rt
×
2733
    return widenreturn(widenlattice(๐•ƒแตข), rt, info)
×
2734
end
2735

2736
@nospecializeinfer function widenreturn(๐•ƒแตข::ConditionalsLattice, @nospecialize(rt), info::BestguessInfo)
5,823,672✔
2737
    โŠ‘แตข = โŠ‘(๐•ƒแตข)
9,477✔
2738
    if !(โŠ‘(ipo_lattice(info.interp), info.bestguess, Bool)) || info.bestguess === Bool
11,180,893✔
2739
        # give up inter-procedural constraint back-propagation
2740
        # when tmerge would widen the result anyways (as an optimization)
2741
        rt = widenconditional(rt)
505,314✔
2742
    else
2743
        if isa(rt, Conditional)
5,318,382✔
2744
            id = rt.slot
9,620✔
2745
            if 1 โ‰ค id โ‰ค info.nargs
9,620✔
2746
                old_id_type = widenconditional(info.slottypes[id]) # same as `(states[1]::VarTable)[id].typ`
9,106✔
2747
                if (!(rt.thentype โŠ‘แตข old_id_type) || old_id_type โŠ‘แตข rt.thentype) &&
14,995✔
2748
                   (!(rt.elsetype โŠ‘แตข old_id_type) || old_id_type โŠ‘แตข rt.elsetype)
2749
                   # discard this `Conditional` since it imposes
2750
                   # no new constraint on the argument type
2751
                   # (the caller will recreate it if needed)
2752
                   rt = widenconditional(rt)
10,956✔
2753
               end
2754
            else
2755
                # discard this `Conditional` imposed on non-call arguments,
2756
                # since it's not interesting in inter-procedural context;
2757
                # we may give constraints on other call argument
2758
                rt = widenconditional(rt)
514✔
2759
            end
2760
        end
2761
        if isa(rt, Conditional)
5,318,382✔
2762
            rt = InterConditional(rt.slot, rt.thentype, rt.elsetype)
3,628✔
2763
        elseif is_lattice_bool(๐•ƒแตข, rt)
10,629,316✔
2764
            rt = bool_rt_to_conditional(rt, info)
507,461✔
2765
        end
2766
    end
2767
    if isa(rt, Conditional)
5,823,672✔
2768
        rt = InterConditional(rt)
×
2769
    end
2770
    isa(rt, InterConditional) && return rt
5,823,672✔
2771
    return widenreturn(widenlattice(๐•ƒแตข), rt, info)
5,812,451✔
2772
end
2773
@nospecializeinfer function bool_rt_to_conditional(@nospecialize(rt), info::BestguessInfo)
1,937✔
2774
    bestguess = info.bestguess
507,461✔
2775
    if isa(bestguess, InterConditional)
507,461✔
2776
        # if the bestguess so far is already `Conditional`, try to convert
2777
        # this `rt` into `Conditional` on the slot to avoid overapproximation
2778
        # due to conflict of different slots
2779
        rt = bool_rt_to_conditional(rt, bestguess.slot, info)
4,453✔
2780
    else
2781
        # pick up the first "interesting" slot, convert `rt` to its `Conditional`
2782
        # TODO: ideally we want `Conditional` and `InterConditional` to convey
2783
        # constraints on multiple slots
2784
        for slot_id = 1:info.nargs
1,006,018✔
2785
            rt = bool_rt_to_conditional(rt, slot_id, info)
1,526,436✔
2786
            rt isa InterConditional && break
1,526,436✔
2787
        end
1,522,117✔
2788
    end
2789
    return rt
507,461✔
2790
end
2791
@nospecializeinfer function bool_rt_to_conditional(@nospecialize(rt), slot_id::Int, info::BestguessInfo)
1,528,386✔
2792
    โŠ‘แตข = โŠ‘(typeinf_lattice(info.interp))
1,528,386✔
2793
    old = info.slottypes[slot_id]
1,530,887✔
2794
    new = widenslotwrapper(info.changes[slot_id].typ) # avoid nested conditional
1,530,887✔
2795
    if new โŠ‘แตข old && !(old โŠ‘แตข new)
1,530,887✔
2796
        if isa(rt, Const)
7,593✔
2797
            val = rt.val
3,739✔
2798
            if val === true
3,739✔
2799
                return InterConditional(slot_id, new, Bottom)
3,508✔
2800
            elseif val === false
231✔
2801
                return InterConditional(slot_id, Bottom, new)
231✔
2802
            end
2803
        elseif rt === Bool
3,854✔
2804
            return InterConditional(slot_id, new, new)
3,854✔
2805
        end
2806
    end
2807
    return rt
1,523,294✔
2808
end
2809

2810
@nospecializeinfer function widenreturn(๐•ƒแตข::PartialsLattice, @nospecialize(rt), info::BestguessInfo)
9,458✔
2811
    return widenreturn_partials(๐•ƒแตข, rt, info)
5,812,453✔
2812
end
2813
@nospecializeinfer function widenreturn_noslotwrapper(๐•ƒแตข::PartialsLattice, @nospecialize(rt), info::BestguessInfo)
2,702,287✔
2814
    return widenreturn_partials(๐•ƒแตข, rt, info)
2,702,287✔
2815
end
2816
@nospecializeinfer function widenreturn_partials(๐•ƒแตข::PartialsLattice, @nospecialize(rt), info::BestguessInfo)
8,514,740✔
2817
    if isa(rt, PartialStruct)
8,514,740✔
2818
        fields = copy(rt.fields)
1,076,337✔
2819
        local anyrefine = false
710✔
2820
        ๐•ƒ = typeinf_lattice(info.interp)
2,151,218✔
2821
        for i in 1:length(fields)
2,152,674✔
2822
            a = fields[i]
2,702,635✔
2823
            a = isvarargtype(a) ? a : widenreturn_noslotwrapper(๐•ƒ, a, info)
5,404,922✔
2824
            if !anyrefine
2,702,635✔
2825
                # TODO: consider adding && const_prop_profitable(a) here?
2826
                anyrefine = has_extended_info(a) ||
2,464,711✔
2827
                            โŠ(๐•ƒ, a, fieldtype(rt.typ, i))
2828
            end
2829
            fields[i] = a
2,702,635✔
2830
        end
4,328,933✔
2831
        anyrefine && return PartialStruct(rt.typ, fields)
1,076,337✔
2832
    end
2833
    if isa(rt, PartialOpaque)
7,438,403✔
2834
        return rt # XXX: this case was missed in #39512
21✔
2835
    end
2836
    return widenreturn(widenlattice(๐•ƒแตข), rt, info)
7,438,382✔
2837
end
2838

2839
@nospecializeinfer function widenreturn(::ConstsLattice, @nospecialize(rt), ::BestguessInfo)
10,197✔
2840
    return widenreturn_consts(rt)
7,438,382✔
2841
end
2842
@nospecializeinfer function widenreturn_noslotwrapper(::ConstsLattice, @nospecialize(rt), ::BestguessInfo)
×
2843
    return widenreturn_consts(rt)
×
2844
end
2845
@nospecializeinfer function widenreturn_consts(@nospecialize(rt))
7,438,382✔
2846
    isa(rt, Const) && return rt
7,438,382✔
2847
    return widenconst(rt)
4,928,239✔
2848
end
2849

2850
@nospecializeinfer function widenreturn(::JLTypeLattice, @nospecialize(rt), ::BestguessInfo)
×
2851
    return widenconst(rt)
×
2852
end
2853
@nospecializeinfer function widenreturn_noslotwrapper(::JLTypeLattice, @nospecialize(rt), ::BestguessInfo)
×
2854
    return widenconst(rt)
×
2855
end
2856

2857
function handle_control_backedge!(interp::AbstractInterpreter, frame::InferenceState, from::Int, to::Int)
1,827✔
2858
    if from > to
5,474,832✔
2859
        if is_effect_overridden(frame, :terminates_locally)
544,983✔
2860
            # this backedge is known to terminate
2861
        else
2862
            merge_effects!(interp, frame, Effects(EFFECTS_TOTAL; terminates=false))
506,052✔
2863
        end
2864
    end
2865
    return nothing
5,474,832✔
2866
end
2867

2868
struct BasicStmtChange
2869
    changes::Union{Nothing,StateUpdate}
2870
    type::Any # ::Union{Type, Nothing} - `nothing` if this statement may not be used as an SSA Value
2871
    # TODO effects::Effects
2872
    BasicStmtChange(changes::Union{Nothing,StateUpdate}, @nospecialize type) = new(changes, type)
48,195,006✔
2873
end
2874

2875
@inline function abstract_eval_basic_statement(interp::AbstractInterpreter,
48,259,392✔
2876
    @nospecialize(stmt), pc_vartable::VarTable, frame::InferenceState)
2877
    if isa(stmt, NewvarNode)
48,259,392✔
2878
        changes = StateUpdate(stmt.slot, VarState(Bottom, true), pc_vartable, false)
1,948,090✔
2879
        return BasicStmtChange(changes, nothing)
1,948,090✔
2880
    elseif !isa(stmt, Expr)
46,311,302✔
2881
        t = abstract_eval_statement(interp, stmt, pc_vartable, frame)
8,342,652✔
2882
        return BasicStmtChange(nothing, t)
8,342,652✔
2883
    end
2884
    changes = nothing
37,968,650✔
2885
    stmt = stmt::Expr
27,749✔
2886
    hd = stmt.head
37,968,650✔
2887
    if hd === :(=)
37,968,650✔
2888
        t = abstract_eval_statement(interp, stmt.args[2], pc_vartable, frame)
8,121,331✔
2889
        if t === Bottom
8,121,331✔
2890
            return BasicStmtChange(nothing, Bottom)
6,656✔
2891
        end
2892
        lhs = stmt.args[1]
8,114,675✔
2893
        if isa(lhs, SlotNumber)
8,114,675✔
2894
            changes = StateUpdate(lhs, VarState(t, false), pc_vartable, false)
8,113,685✔
2895
        elseif isa(lhs, GlobalRef)
990✔
2896
            handle_global_assignment!(interp, frame, lhs, t)
990✔
2897
        elseif !isa(lhs, SSAValue)
×
2898
            merge_effects!(interp, frame, EFFECTS_UNKNOWN)
×
2899
        end
2900
        return BasicStmtChange(changes, t)
8,114,675✔
2901
    elseif hd === :method
29,847,319✔
2902
        fname = stmt.args[1]
×
2903
        if isa(fname, SlotNumber)
×
2904
            changes = StateUpdate(fname, VarState(Any, false), pc_vartable, false)
×
2905
        end
2906
        return BasicStmtChange(changes, nothing)
×
2907
    elseif (hd === :code_coverage_effect || (
89,205,823✔
2908
            hd !== :boundscheck && # :boundscheck can be narrowed to Bool
2909
            is_meta_expr(stmt)))
2910
        return BasicStmtChange(nothing, Nothing)
57,709✔
2911
    else
2912
        t = abstract_eval_statement(interp, stmt, pc_vartable, frame)
29,789,610✔
2913
        return BasicStmtChange(nothing, t)
29,789,589✔
2914
    end
2915
end
2916

2917
function update_bbstate!(๐•ƒแตข::AbstractLattice, frame::InferenceState, bb::Int, vartable::VarTable)
4,273✔
2918
    bbtable = frame.bb_vartables[bb]
11,329,188✔
2919
    if bbtable === nothing
11,329,188✔
2920
        # if a basic block hasn't been analyzed yet,
2921
        # we can update its state a bit more aggressively
2922
        frame.bb_vartables[bb] = copy(vartable)
8,087,321✔
2923
        return true
8,087,321✔
2924
    else
2925
        return stupdate!(๐•ƒแตข, bbtable, vartable)
3,241,867✔
2926
    end
2927
end
2928

2929
function init_vartable!(vartable::VarTable, frame::InferenceState)
×
2930
    nargtypes = length(frame.result.argtypes)
×
2931
    for i = 1:length(vartable)
×
2932
        vartable[i] = VarState(Bottom, i > nargtypes)
×
2933
    end
×
2934
    return vartable
×
2935
end
2936

2937
function update_bestguess!(interp::AbstractInterpreter, frame::InferenceState,
5,823,674✔
2938
                           currstate::VarTable, @nospecialize(rt))
2939
    bestguess = frame.bestguess
5,823,674✔
2940
    nargs = narguments(frame, #=include_va=#false)
5,823,674✔
2941
    slottypes = frame.slottypes
5,823,674✔
2942
    rt = widenreturn(rt, BestguessInfo(interp, bestguess, nargs, slottypes, currstate))
5,823,674✔
2943
    # narrow representation of bestguess slightly to prepare for tmerge with rt
2944
    if rt isa InterConditional && bestguess isa Const
5,823,674✔
2945
        slot_id = rt.slot
19✔
2946
        old_id_type = slottypes[slot_id]
19✔
2947
        if bestguess.val === true && rt.elsetype !== Bottom
19✔
2948
            bestguess = InterConditional(slot_id, old_id_type, Bottom)
5✔
2949
        elseif bestguess.val === false && rt.thentype !== Bottom
14✔
2950
            bestguess = InterConditional(slot_id, Bottom, old_id_type)
7✔
2951
        end
2952
    end
2953
    # copy limitations to return value
2954
    if !isempty(frame.pclimitations)
6,015,687✔
2955
        union!(frame.limitations, frame.pclimitations)
192,013✔
2956
        empty!(frame.pclimitations)
192,013✔
2957
    end
2958
    if !isempty(frame.limitations)
6,045,506✔
2959
        rt = LimitedAccuracy(rt, copy(frame.limitations))
221,832✔
2960
    end
2961
    ๐•ƒโ‚š = ipo_lattice(interp)
11,630,262✔
2962
    if !โŠ‘(๐•ƒโ‚š, rt, bestguess)
5,823,674✔
2963
        # TODO: if bestguess isa InterConditional && !interesting(bestguess); bestguess = widenconditional(bestguess); end
2964
        frame.bestguess = tmerge(๐•ƒโ‚š, bestguess, rt) # new (wider) return type for frame
5,488,671✔
2965
        return true
5,488,670✔
2966
    else
2967
        return false
335,004✔
2968
    end
2969
end
2970

2971
# make as much progress on `frame` as possible (without handling cycles)
2972
function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
5,338,951✔
2973
    @assert !is_inferred(frame)
5,338,951✔
2974
    frame.dont_work_on_me = true # mark that this function is currently on the stack
5,338,951✔
2975
    W = frame.ip
5,338,951✔
2976
    ssavaluetypes = frame.ssavaluetypes
5,338,951✔
2977
    bbs = frame.cfg.blocks
5,338,951✔
2978
    nbbs = length(bbs)
5,338,951✔
2979
    ๐•ƒแตข = typeinf_lattice(interp)
10,654,981✔
2980

2981
    currbb = frame.currbb
5,338,951✔
2982
    if currbb != 1
5,338,951✔
2983
        currbb = frame.currbb = _bits_findnext(W.bits, 1)::Int # next basic block
10,154✔
2984
    end
2985

2986
    states = frame.bb_vartables
5,338,951✔
2987
    currstate = copy(states[currbb]::VarTable)
5,338,951✔
2988
    while currbb <= nbbs
14,646,583✔
2989
        delete!(W, currbb)
29,293,166✔
2990
        bbstart = first(bbs[currbb].stmts)
14,646,583✔
2991
        bbend = last(bbs[currbb].stmts)
14,646,583✔
2992

2993
        for currpc in bbstart:bbend
29,293,166✔
2994
            frame.currpc = currpc
61,391,082✔
2995
            empty_backedges!(frame, currpc)
63,973,656✔
2996
            stmt = frame.src.code[currpc]
61,391,082✔
2997
            # If we're at the end of the basic block ...
2998
            if currpc == bbend
61,391,082✔
2999
                # Handle control flow
3000
                if isa(stmt, GotoNode)
14,427,154✔
3001
                    succs = bbs[currbb].succs
2,249,314✔
3002
                    @assert length(succs) == 1
2,249,314✔
3003
                    nextbb = succs[1]
2,249,314✔
3004
                    ssavaluetypes[currpc] = Any
2,249,314✔
3005
                    handle_control_backedge!(interp, frame, currpc, stmt.label)
2,755,366✔
3006
                    add_curr_ssaflag!(frame, IR_FLAG_NOTHROW)
2,249,314✔
3007
                    @goto branch
2,249,314✔
3008
                elseif isa(stmt, GotoIfNot)
12,177,840✔
3009
                    condx = stmt.cond
5,000,635✔
3010
                    condt = abstract_eval_value(interp, condx, currstate, frame)
9,975,110✔
3011
                    if condt === Bottom
5,000,635✔
3012
                        ssavaluetypes[currpc] = Bottom
×
3013
                        empty!(frame.pclimitations)
×
3014
                        @goto find_next_bb
×
3015
                    end
3016
                    orig_condt = condt
2,286✔
3017
                    if !(isa(condt, Const) || isa(condt, Conditional)) && isa(condx, SlotNumber)
8,992,031✔
3018
                        # if this non-`Conditional` object is a slot, we form and propagate
3019
                        # the conditional constraint on it
3020
                        condt = Conditional(condx, Const(true), Const(false))
120,016✔
3021
                    end
3022
                    condval = maybe_extract_const_bool(condt)
5,000,778✔
3023
                    nothrow = (condval !== nothing) || โŠ‘(๐•ƒแตข, orig_condt, Bool)
7,882,299✔
3024
                    if nothrow
5,000,635✔
3025
                        add_curr_ssaflag!(frame, IR_FLAG_NOTHROW)
4,895,786✔
3026
                    else
3027
                        merge_effects!(interp, frame, EFFECTS_THROWS)
104,849✔
3028
                    end
3029

3030
                    if !isempty(frame.pclimitations)
5,032,502✔
3031
                        # we can't model the possible effect of control
3032
                        # dependencies on the return
3033
                        # directly to all the return values (unless we error first)
3034
                        condval isa Bool || union!(frame.limitations, frame.pclimitations)
63,688✔
3035
                        empty!(frame.pclimitations)
31,867✔
3036
                    end
3037
                    ssavaluetypes[currpc] = Any
5,000,635✔
3038
                    if condval === true
5,000,635✔
3039
                        @goto fallthrough
1,350,371✔
3040
                    else
3041
                        if !nothrow && !hasintersect(widenconst(orig_condt), Bool)
3,650,264✔
3042
                            ssavaluetypes[currpc] = Bottom
167✔
3043
                            @goto find_next_bb
167✔
3044
                        end
3045

3046
                        succs = bbs[currbb].succs
3,650,097✔
3047
                        if length(succs) == 1
3,650,097✔
3048
                            @assert condval === false || (stmt.dest === currpc + 1)
10✔
3049
                            nextbb = succs[1]
6✔
3050
                            @goto branch
6✔
3051
                        end
3052
                        @assert length(succs) == 2
3,650,091✔
3053
                        truebb = currbb + 1
3,650,091✔
3054
                        falsebb = succs[1] == truebb ? succs[2] : succs[1]
7,300,182✔
3055
                        if condval === false
3,650,091✔
3056
                            nextbb = falsebb
768,598✔
3057
                            handle_control_backedge!(interp, frame, currpc, stmt.dest)
768,598✔
3058
                            @goto branch
768,598✔
3059
                        end
3060

3061
                        # We continue with the true branch, but process the false
3062
                        # branch here.
3063
                        if isa(condt, Conditional)
2,881,493✔
3064
                            else_change = conditional_change(๐•ƒแตข, currstate, condt.elsetype, condt.slot)
2,777,063✔
3065
                            if else_change !== nothing
1,390,874✔
3066
                                false_vartable = stoverwrite1!(copy(currstate), else_change)
81,311,104✔
3067
                            else
3068
                                false_vartable = currstate
×
3069
                            end
3070
                            changed = update_bbstate!(๐•ƒแตข, frame, falsebb, false_vartable)
2,086,898✔
3071
                            then_change = conditional_change(๐•ƒแตข, currstate, condt.thentype, condt.slot)
2,776,823✔
3072
                            if then_change !== nothing
1,390,874✔
3073
                                stoverwrite1!(currstate, then_change)
81,293,079✔
3074
                            end
3075
                        else
3076
                            changed = update_bbstate!(๐•ƒแตข, frame, falsebb, currstate)
1,490,619✔
3077
                        end
3078
                        if changed
2,881,493✔
3079
                            handle_control_backedge!(interp, frame, currpc, stmt.dest)
2,456,920✔
3080
                            push!(W, falsebb)
2,457,066✔
3081
                        end
3082
                        @goto fallthrough
2,881,493✔
3083
                    end
3084
                elseif isa(stmt, ReturnNode)
7,177,205✔
3085
                    rt = abstract_eval_value(interp, stmt.val, currstate, frame)
11,619,932✔
3086
                    if update_bestguess!(interp, frame, currstate, rt)
5,823,674✔
3087
                        for (caller, caller_pc) in frame.cycle_backedges
10,962,085✔
3088
                            if caller.ssavaluetypes[caller_pc] !== Any
19,859✔
3089
                                # no reason to revisit if that call-site doesn't affect the final result
3090
                                push!(caller.ip, block_for_inst(caller.cfg, caller_pc))
19,136✔
3091
                            end
3092
                        end
35,114✔
3093
                    end
3094
                    ssavaluetypes[frame.currpc] = Any
5,823,674✔
3095
                    @goto find_next_bb
5,823,674✔
3096
                elseif isexpr(stmt, :enter)
1,382,342✔
3097
                    # Propagate entry info to exception handler
3098
                    l = stmt.args[1]::Int
58,067✔
3099
                    catchbb = block_for_inst(frame.cfg, l)
58,067✔
3100
                    if update_bbstate!(๐•ƒแตข, frame, catchbb, currstate)
70,921✔
3101
                        push!(W, catchbb)
59,566✔
3102
                    end
3103
                    ssavaluetypes[currpc] = Any
58,067✔
3104
                    @goto fallthrough
58,067✔
3105
                end
3106
                # Fall through terminator - treat as regular stmt
3107
            end
3108
            # Process non control-flow statements
3109
            (; changes, type) = abstract_eval_basic_statement(interp,
48,259,392✔
3110
                stmt, currstate, frame)
3111
            if type === Bottom
48,259,371✔
3112
                ssavaluetypes[currpc] = Bottom
433,093✔
3113
                @goto find_next_bb
433,093✔
3114
            end
3115
            if changes !== nothing
47,826,278✔
3116
                stoverwrite1!(currstate, changes)
370,890,984✔
3117
                let cur_hand = frame.handler_at[currpc], l, enter
10,061,775✔
3118
                    while cur_hand != 0
10,590,144✔
3119
                        enter = frame.src.code[cur_hand]::Expr
528,369✔
3120
                        l = enter.args[1]::Int
528,369✔
3121
                        exceptbb = block_for_inst(frame.cfg, l)
528,369✔
3122
                        # propagate new type info to exception handler
3123
                        # the handling for Expr(:enter) propagates all changes from before the try/catch
3124
                        # so this only needs to propagate any changes
3125
                        if stupdate1!(๐•ƒแตข, states[exceptbb]::VarTable, changes)
528,369✔
3126
                            push!(W, exceptbb)
257,601✔
3127
                        end
3128
                        cur_hand = frame.handler_at[cur_hand]
528,369✔
3129
                    end
528,369✔
3130
                end
3131
            end
3132
            if type === nothing
47,826,278✔
3133
                ssavaluetypes[currpc] = Any
1,948,090✔
3134
                continue
1,948,090✔
3135
            end
3136
            record_ssa_assign!(๐•ƒแตข, currpc, type, frame)
45,878,188✔
3137
        end # for currpc in bbstart:bbend
47,826,278✔
3138

3139
        # Case 1: Fallthrough termination
3140
        begin @label fallthrough
×
3141
            nextbb = currbb + 1
5,371,710✔
3142
        end
3143

3144
        # Case 2: Directly branch to a different BB
3145
        begin @label branch
×
3146
            if update_bbstate!(๐•ƒแตข, frame, nextbb, currstate)
10,614,791✔
3147
                push!(W, nextbb)
7,537,551✔
3148
            end
3149
        end
3150

3151
        # Case 3: Control flow ended along the current path (converged, return or throw)
3152
        begin @label find_next_bb
×
3153
            currbb = frame.currbb = _bits_findnext(W.bits, 1)::Int # next basic block
29,293,124✔
3154
            currbb == -1 && break # the working set is empty
14,646,562✔
3155
            currbb > nbbs && break
9,307,632✔
3156

3157
            nexttable = states[currbb]
9,307,632✔
3158
            if nexttable === nothing
9,307,632✔
3159
                init_vartable!(currstate, frame)
×
3160
            else
3161
                stoverwrite!(currstate, nexttable)
9,307,632✔
3162
            end
3163
        end
3164
    end # while currbb <= nbbs
9,307,632✔
3165

3166
    frame.dont_work_on_me = false
5,338,930✔
3167
    nothing
5,338,930✔
3168
end
3169

3170
function conditional_change(๐•ƒแตข::AbstractLattice, state::VarTable, @nospecialize(typ), slot::Int)
374✔
3171
    vtype = state[slot]
2,781,748✔
3172
    oldtyp = vtype.typ
2,781,748✔
3173
    if iskindtype(typ)
5,557,578✔
3174
        # this code path corresponds to the special handling for `isa(x, iskindtype)` check
3175
        # implemented within `abstract_call_builtin`
3176
    elseif โŠ‘(๐•ƒแตข, ignorelimited(typ), ignorelimited(oldtyp))
5,531,337✔
3177
        # approximate test for `typ โˆฉ oldtyp` being better than `oldtyp`
3178
        # since we probably formed these types with `typesubstract`,
3179
        # the comparison is likely simple
3180
    else
3181
        return nothing
1,653✔
3182
    end
3183
    if oldtyp isa LimitedAccuracy
2,780,095✔
3184
        # typ is better unlimited, but we may still need to compute the tmeet with the limit
3185
        # "causes" since we ignored those in the comparison
3186
        typ = tmerge(๐•ƒแตข, typ, LimitedAccuracy(Bottom, oldtyp.causes))
12,937✔
3187
    end
3188
    return StateUpdate(SlotNumber(slot), VarState(typ, vtype.undef), state, true)
2,780,095✔
3189
end
3190

3191
# make as much progress on `frame` as possible (by handling cycles)
3192
function typeinf_nocycle(interp::AbstractInterpreter, frame::InferenceState)
5,333,874✔
3193
    typeinf_local(interp, frame)
5,333,874✔
3194

3195
    # If the current frame is part of a cycle, solve the cycle before finishing
3196
    no_active_ips_in_callers = false
9,163✔
3197
    while !no_active_ips_in_callers
10,664,361✔
3198
        no_active_ips_in_callers = true
9,163✔
3199
        for caller in frame.callers_in_cycle
10,653,462✔
3200
            caller.dont_work_on_me && return false # cycle is above us on the stack
37,354✔
3201
            if !isempty(caller.ip)
31,517✔
3202
                # Note that `typeinf_local(interp, caller)` can potentially modify the other frames
3203
                # `frame.callers_in_cycle`, which is why making incremental progress requires the
3204
                # outer while loop.
3205
                typeinf_local(interp, caller)
5,077✔
3206
                no_active_ips_in_callers = false
×
3207
            end
3208
            update_valid_age!(caller, frame.valid_worlds)
30,746✔
3209
        end
44,908✔
3210
    end
5,330,508✔
3211
    return true
5,327,245✔
3212
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

© 2025 Coveralls, Inc