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

JuliaLang / julia / 1293

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

push

buildkite

web-flow
Support superscript small q (#59544)

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

61282 of 79637 relevant lines covered (76.95%)

21700458.33 hits per line

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

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

3
#############
4
# constants #
5
#############
6

7
"""
8
    @nospecs def
9

10
Adds `@nospecialize` annotation to non-annotated arguments of `def`.
11
```julia
12
(Core.Compiler) julia> @macroexpand @nospecs function tfunc(𝕃::AbstractLattice, x, y::Bool, zs...)
13
                           x, ys
14
                       end
15
:(function tfunc(\$(Expr(:meta, :specialize, :(𝕃::AbstractLattice))), x, y::Bool, zs...)
16
      #= REPL[3]:1 =#
17
      \$(Expr(:meta, :nospecialize, :x, :zs))
18
      #= REPL[3]:2 =#
19
      (x, ys)
20
  end)
21
```
22
"""
23
macro nospecs(ex)
24
    is_function_def(ex) || throw(ArgumentError("expected function definition"))
25
    args, body = ex.args
26
    if isexpr(args, :call)
27
        args = args.args[2:end] # skip marking `@nospecialize` on the function itself
28
    else
29
        @assert isexpr(args, :tuple) # anonymous function
30
        args = args.args
31
    end
32
    names = Symbol[]
33
    for arg in args
34
        isexpr(arg, :macrocall) && continue
35
        if isexpr(arg, :...)
36
            arg = arg.args[1]
37
        elseif isexpr(arg, :kw)
38
            arg = arg.args[1]
39
        end
40
        isexpr(arg, :(::)) && continue
41
        @assert arg isa Symbol
42
        push!(names, arg)
43
    end
44
    @assert isexpr(body, :block)
45
    isempty(names) && throw(ArgumentError("no arguments for @nospec"))
46
    lin = first(body.args)::LineNumberNode
47
    nospec = Expr(:macrocall, GlobalRef(@__MODULE__, :var"@nospecialize"), lin, names...)
48
    insert!(body.args, 2, nospec)
49
    return esc(ex)
50
end
51

52
const INT_INF = typemax(Int) # integer infinity
53

54
const N_IFUNC = reinterpret(Int32, have_fma) + 1
55
const T_IFUNC = Vector{Tuple{Int, Int, Any}}(undef, N_IFUNC)
56
const T_IFUNC_COST = Vector{Int}(undef, N_IFUNC)
57
const T_FFUNC_KEY = Vector{Any}()
58
const T_FFUNC_VAL = Vector{Tuple{Int, Int, Any}}()
59
const T_FFUNC_COST = Vector{Int}()
60
function find_tfunc(@nospecialize f)
61
    for i = 1:length(T_FFUNC_KEY)
380,101✔
62
        if T_FFUNC_KEY[i] === f
5,445,021✔
63
            return i
294,565✔
64
        end
65
    end
5,150,456✔
66
end
67

68
const DATATYPE_TYPES_FIELDINDEX = fieldindex(DataType, :types)
69
const DATATYPE_NAME_FIELDINDEX = fieldindex(DataType, :name)
70

71
##########
72
# tfuncs #
73
##########
74

75
# Note that in most places in the compiler here, we'll assume that T=Type{S} is well-formed,
76
# and implies that `S <: Type`, not `1::Type{1}`, for example.
77
# This means that isType(T) implies we can call subtype on T.parameters[1], etc.
78

79
function add_tfunc(f::IntrinsicFunction, minarg::Int, maxarg::Int, @nospecialize(tfunc), cost::Int)
×
80
    idx = reinterpret(Int32, f) + 1
×
81
    T_IFUNC[idx] = (minarg, maxarg, tfunc)
×
82
    T_IFUNC_COST[idx] = cost
×
83
end
84
function add_tfunc(@nospecialize(f::Builtin), minarg::Int, maxarg::Int, @nospecialize(tfunc), cost::Int)
×
85
    push!(T_FFUNC_KEY, f)
×
86
    push!(T_FFUNC_VAL, (minarg, maxarg, tfunc))
×
87
    push!(T_FFUNC_COST, cost)
×
88
end
89

90
add_tfunc(throw, 1, 1, @nospecs((𝕃::AbstractLattice, x)->Bottom), 0)
×
91
add_tfunc(Core.throw_methoderror, 1, INT_INF, @nospecs((𝕃::AbstractLattice, x)->Bottom), 0)
×
92

93
# the inverse of typeof_tfunc
94
# returns (type, isexact, isconcrete, istype)
95
# if isexact is false, the actual runtime type may (will) be a subtype of t
96
# if isconcrete is true, the actual runtime type is definitely concrete (unreachable if not valid as a typeof)
97
# if istype is true, the actual runtime value will definitely be a type (e.g. this is false for Union{Type{Int}, Int})
98
function instanceof_tfunc(@nospecialize(t), astag::Bool=false, @nospecialize(troot) = t)
462,049✔
99
    if isa(t, Const)
462,049✔
100
        if isa(t.val, Type) && valid_as_lattice(t.val, astag)
326,039✔
101
            return t.val, true, isconcretetype(t.val), true
322,873✔
102
        end
103
        return Bottom, true, false, false # runtime throws on non-Type
3,166✔
104
    end
105
    t = widenconst(t)
27,506✔
106
    troot = widenconst(troot)
27,506✔
107
    if t === Bottom
27,506✔
108
        return Bottom, true, true, false # runtime unreachable
×
109
    elseif t === typeof(Bottom) || !hasintersect(t, Type)
55,012✔
110
        return Bottom, true, false, false # literal Bottom or non-Type
206✔
111
    elseif isType(t)
27,300✔
112
        tp = t.parameters[1]
13,076✔
113
        valid_as_lattice(tp, astag) || return Bottom, true, false, false # runtime unreachable / throws on non-Type
13,076✔
114
        if troot isa UnionAll
13,076✔
115
            # Free `TypeVar`s inside `Type` has violated the "diagonal" rule.
116
            # Widen them before `UnionAll` rewraping to relax concrete constraint.
117
            tp = widen_diagonal(tp, troot)
10,641✔
118
        end
119
        return tp, !has_free_typevars(tp), isconcretetype(tp), true
13,076✔
120
    elseif isa(t, UnionAll)
14,224✔
121
        t′ = unwrap_unionall(t)
10,641✔
122
        t′′, isexact, isconcrete, istype = instanceof_tfunc(t′, astag, rewrap_unionall(t, troot))
21,120✔
123
        tr = rewrap_unionall(t′′, t)
10,641✔
124
        if t′′ isa DataType && t′′.name !== Tuple.name && !has_free_typevars(tr)
10,641✔
125
            # a real instance must be within the declared bounds of the type,
126
            # so we can intersect with the original wrapper.
127
            tr = typeintersect(tr, t′′.name.wrapper)
5,797✔
128
            isconcrete = !isabstracttype(t′′)
5,797✔
129
            if tr === Union{}
5,797✔
130
                # runtime unreachable (our inference Type{T} where S is
131
                # uninhabited with any runtime T that exists)
132
                isexact = true
×
133
            end
134
        end
135
        return tr, isexact, isconcrete, istype
10,641✔
136
    elseif isa(t, Union)
3,583✔
137
        ta, isexact_a, isconcrete_a, istype_a = instanceof_tfunc(unwraptv(t.a), astag, troot)
584✔
138
        tb, isexact_b, isconcrete_b, istype_b = instanceof_tfunc(unwraptv(t.b), astag, troot)
584✔
139
        isconcrete = isconcrete_a && isconcrete_b
584✔
140
        istype = istype_a && istype_b
584✔
141
        # most users already handle the Union case, so here we assume that
142
        # `isexact` only cares about the answers where there's actually a Type
143
        # (and assuming other cases causing runtime errors)
144
        ta === Union{} && return tb, isexact_b, isconcrete, istype
584✔
145
        tb === Union{} && return ta, isexact_a, isconcrete, istype
584✔
146
        return Union{ta, tb}, false, isconcrete, istype # at runtime, will be exactly one of these
584✔
147
    end
148
    return Any, false, false, false
2,999✔
149
end
150

151
# IntrinsicFunction
152
# =================
153

154
# conversion
155
# ----------
156

157
@nospecs bitcast_tfunc(𝕃::AbstractLattice, t, x) = bitcast_tfunc(widenlattice(𝕃), t, x)
2,780✔
158
@nospecs bitcast_tfunc(::JLTypeLattice, t, x) = instanceof_tfunc(t, true)[1]
695✔
159
@nospecs conversion_tfunc(𝕃::AbstractLattice, t, x) = conversion_tfunc(widenlattice(𝕃), t, x)
672✔
160
@nospecs conversion_tfunc(::JLTypeLattice, t, x) = instanceof_tfunc(t, true)[1]
168✔
161

162
add_tfunc(bitcast, 2, 2, bitcast_tfunc, 0)
163
add_tfunc(sext_int, 2, 2, conversion_tfunc, 0)
164
add_tfunc(zext_int, 2, 2, conversion_tfunc, 0)
165
add_tfunc(trunc_int, 2, 2, conversion_tfunc, 0)
166
add_tfunc(fptoui, 2, 2, conversion_tfunc, 1)
167
add_tfunc(fptosi, 2, 2, conversion_tfunc, 1)
168
add_tfunc(uitofp, 2, 2, conversion_tfunc, 1)
169
add_tfunc(sitofp, 2, 2, conversion_tfunc, 1)
170
add_tfunc(fptrunc, 2, 2, conversion_tfunc, 1)
171
add_tfunc(fpext, 2, 2, conversion_tfunc, 1)
172

173
# arithmetic
174
# ----------
175

176
@nospecs math_tfunc(𝕃::AbstractLattice, args...) = math_tfunc(widenlattice(𝕃), args...)
2,924✔
177
@nospecs math_tfunc(::JLTypeLattice, x, xs...) = widenconst(x)
731✔
178

179
add_tfunc(neg_int, 1, 1, math_tfunc, 0)
180
add_tfunc(add_int, 2, 2, math_tfunc, 1)
181
add_tfunc(sub_int, 2, 2, math_tfunc, 1)
182
add_tfunc(mul_int, 2, 2, math_tfunc, 3)
183
add_tfunc(sdiv_int, 2, 2, math_tfunc, 20)
184
add_tfunc(udiv_int, 2, 2, math_tfunc, 20)
185
add_tfunc(srem_int, 2, 2, math_tfunc, 20)
186
add_tfunc(urem_int, 2, 2, math_tfunc, 20)
187
add_tfunc(neg_float, 1, 1, math_tfunc, 1)
188
add_tfunc(add_float, 2, 2, math_tfunc, 2)
189
add_tfunc(sub_float, 2, 2, math_tfunc, 2)
190
add_tfunc(mul_float, 2, 2, math_tfunc, 8)
191
add_tfunc(div_float, 2, 2, math_tfunc, 10)
192
add_tfunc(min_float, 2, 2, math_tfunc, 1)
193
add_tfunc(max_float, 2, 2, math_tfunc, 1)
194
add_tfunc(fma_float, 3, 3, math_tfunc, 8)
195
add_tfunc(muladd_float, 3, 3, math_tfunc, 8)
196

197
# fast arithmetic
198
add_tfunc(neg_float_fast, 1, 1, math_tfunc, 1)
199
add_tfunc(add_float_fast, 2, 2, math_tfunc, 2)
200
add_tfunc(sub_float_fast, 2, 2, math_tfunc, 2)
201
add_tfunc(mul_float_fast, 2, 2, math_tfunc, 8)
202
add_tfunc(div_float_fast, 2, 2, math_tfunc, 10)
203
add_tfunc(min_float_fast, 2, 2, math_tfunc, 1)
204
add_tfunc(max_float_fast, 2, 2, math_tfunc, 1)
205

206
# bitwise operators
207
# -----------------
208

209
@nospecs and_int_tfunc(𝕃::AbstractLattice, x, y) = and_int_tfunc(widenlattice(𝕃), x, y)
2,367✔
210
@nospecs function and_int_tfunc(𝕃::ConstsLattice, x, y)
805✔
211
    if isa(x, Const) && x.val === false && widenconst(y) === Bool
805✔
212
        return Const(false)
×
213
    elseif isa(y, Const) && y.val === false && widenconst(x) === Bool
805✔
214
        return Const(false)
6✔
215
    end
216
    return and_int_tfunc(widenlattice(𝕃), x, y)
799✔
217
end
218
@nospecs and_int_tfunc(::JLTypeLattice, x, y) = widenconst(x)
799✔
219

220
@nospecs or_int_tfunc(𝕃::AbstractLattice, x, y) = or_int_tfunc(widenlattice(𝕃), x, y)
3,867✔
221
@nospecs function or_int_tfunc(𝕃::ConstsLattice, x, y)
1,289✔
222
    if isa(x, Const) && x.val === true && widenconst(y) === Bool
1,289✔
223
        return Const(true)
×
224
    elseif isa(y, Const) && y.val === true && widenconst(x) === Bool
1,289✔
225
        return Const(true)
×
226
    end
227
    return or_int_tfunc(widenlattice(𝕃), x, y)
1,289✔
228
end
229
@nospecs or_int_tfunc(::JLTypeLattice, x, y) = widenconst(x)
1,289✔
230

231
@nospecs shift_tfunc(𝕃::AbstractLattice, x, y) = shift_tfunc(widenlattice(𝕃), x, y)
3,648✔
232
@nospecs shift_tfunc(::JLTypeLattice, x, y) = widenconst(x)
912✔
233

234
function not_tfunc(𝕃::AbstractLattice, @nospecialize(b))
11,347✔
235
    if isa(b, Conditional)
11,347✔
236
        return Conditional(b.slot, b.elsetype, b.thentype)
11,317✔
237
    elseif isa(b, Const)
30✔
238
        return Const(not_int(b.val))
×
239
    end
240
    return math_tfunc(𝕃, b)
30✔
241
end
242

243
add_tfunc(and_int, 2, 2, and_int_tfunc, 1)
244
add_tfunc(or_int, 2, 2, or_int_tfunc, 1)
245
add_tfunc(xor_int, 2, 2, math_tfunc, 1)
246
add_tfunc(not_int, 1, 1, not_tfunc, 0) # usually used as not_int(::Bool) to negate a condition
247
add_tfunc(shl_int, 2, 2, shift_tfunc, 1)
248
add_tfunc(lshr_int, 2, 2, shift_tfunc, 1)
249
add_tfunc(ashr_int, 2, 2, shift_tfunc, 1)
250
add_tfunc(bswap_int, 1, 1, math_tfunc, 1)
251
add_tfunc(ctpop_int, 1, 1, math_tfunc, 1)
252
add_tfunc(ctlz_int, 1, 1, math_tfunc, 1)
253
add_tfunc(cttz_int, 1, 1, math_tfunc, 1)
254
add_tfunc(checked_sdiv_int, 2, 2, math_tfunc, 40)
255
add_tfunc(checked_udiv_int, 2, 2, math_tfunc, 40)
256
add_tfunc(checked_srem_int, 2, 2, math_tfunc, 40)
257
add_tfunc(checked_urem_int, 2, 2, math_tfunc, 40)
258

259
# functions
260
# ---------
261

262
add_tfunc(abs_float, 1, 1, math_tfunc, 2)
263
add_tfunc(copysign_float, 2, 2, math_tfunc, 2)
264
add_tfunc(flipsign_int, 2, 2, math_tfunc, 1)
265
add_tfunc(ceil_llvm, 1, 1, math_tfunc, 10)
266
add_tfunc(floor_llvm, 1, 1, math_tfunc, 10)
267
add_tfunc(trunc_llvm, 1, 1, math_tfunc, 10)
268
add_tfunc(rint_llvm, 1, 1, math_tfunc, 10)
269
add_tfunc(sqrt_llvm, 1, 1, math_tfunc, 20)
270
add_tfunc(sqrt_llvm_fast, 1, 1, math_tfunc, 20)
271

272
# comparisons
273
# -----------
274

275
@nospecs cmp_tfunc(𝕃::AbstractLattice, a, b) = cmp_tfunc(widenlattice(𝕃), a, b)
800✔
276
@nospecs cmp_tfunc(::JLTypeLattice, a, b) = Bool
197✔
277

278
add_tfunc(eq_int, 2, 2, cmp_tfunc, 1)
279
add_tfunc(ne_int, 2, 2, cmp_tfunc, 1)
280
add_tfunc(slt_int, 2, 2, cmp_tfunc, 1)
281
add_tfunc(ult_int, 2, 2, cmp_tfunc, 1)
282
add_tfunc(sle_int, 2, 2, cmp_tfunc, 1)
283
add_tfunc(ule_int, 2, 2, cmp_tfunc, 1)
284
add_tfunc(eq_float, 2, 2, cmp_tfunc, 2)
285
add_tfunc(ne_float, 2, 2, cmp_tfunc, 2)
286
add_tfunc(lt_float, 2, 2, cmp_tfunc, 2)
287
add_tfunc(le_float, 2, 2, cmp_tfunc, 2)
288
add_tfunc(fpiseq, 2, 2, cmp_tfunc, 1)
289
add_tfunc(eq_float_fast, 2, 2, cmp_tfunc, 1)
290
add_tfunc(ne_float_fast, 2, 2, cmp_tfunc, 1)
291
add_tfunc(lt_float_fast, 2, 2, cmp_tfunc, 1)
292
add_tfunc(le_float_fast, 2, 2, cmp_tfunc, 1)
293

294
# checked arithmetic
295
# ------------------
296

297
@nospecs chk_tfunc(𝕃::AbstractLattice, x, y) = chk_tfunc(widenlattice(𝕃), x, y)
464✔
298
@nospecs chk_tfunc(::JLTypeLattice, x, y) = Tuple{widenconst(x), Bool}
116✔
299

300
add_tfunc(checked_sadd_int, 2, 2, chk_tfunc, 2)
301
add_tfunc(checked_uadd_int, 2, 2, chk_tfunc, 2)
302
add_tfunc(checked_ssub_int, 2, 2, chk_tfunc, 2)
303
add_tfunc(checked_usub_int, 2, 2, chk_tfunc, 2)
304
add_tfunc(checked_smul_int, 2, 2, chk_tfunc, 5)
305
add_tfunc(checked_umul_int, 2, 2, chk_tfunc, 5)
306

307
# other, misc
308
# -----------
309

310
@nospecs function llvmcall_tfunc(𝕃::AbstractLattice, fptr, rt, at, a...)
42✔
311
    return instanceof_tfunc(rt)[1]
42✔
312
end
313
add_tfunc(Core.Intrinsics.llvmcall, 3, INT_INF, llvmcall_tfunc, 10)
314

315
@nospecs cglobal_tfunc(𝕃::AbstractLattice, fptr) = Ptr{Cvoid}
×
316
@nospecs function cglobal_tfunc(𝕃::AbstractLattice, fptr, t)
×
317
    isa(t, Const) && return isa(t.val, Type) ? Ptr{t.val} : Ptr
×
318
    return isType(t) ? Ptr{t.parameters[1]} : Ptr
×
319
end
320
add_tfunc(Core.Intrinsics.cglobal, 1, 2, cglobal_tfunc, 5)
321

322
add_tfunc(Core.Intrinsics.have_fma, 1, 1, @nospecs((𝕃::AbstractLattice, x)->Bool), 1)
×
323

324
# builtin functions
325
# =================
326

327
@nospecs function ifelse_tfunc(𝕃::AbstractLattice, cnd, x, y)
45✔
328
    cnd = widenslotwrapper(cnd)
45✔
329
    if isa(cnd, Const)
45✔
330
        if cnd.val === true
39✔
331
            return x
39✔
332
        elseif cnd.val === false
×
333
            return y
×
334
        else
335
            return Bottom
×
336
        end
337
    elseif !hasintersect(widenconst(cnd), Bool)
6✔
338
        return Bottom
3✔
339
    end
340
    return tmerge(𝕃, x, y)
3✔
341
end
342
add_tfunc(Core.ifelse, 3, 3, ifelse_tfunc, 1)
343

344
@nospecs function ifelse_nothrow(𝕃::AbstractLattice, cond, x, y)
345
    ⊑ = partialorder(𝕃)
1,455✔
346
    return cond ⊑ Bool
1,455✔
347
end
348

349
@nospecs egal_tfunc(𝕃::AbstractLattice, x, y) = egal_tfunc(widenlattice(𝕃), x, y)
208,355✔
350
@nospecs function egal_tfunc(𝕃::MustAliasesLattice, x, y)
351
    return egal_tfunc(widenlattice(𝕃), widenmustalias(x), widenmustalias(y))
18✔
352
end
353
@nospecs function egal_tfunc(𝕃::ConditionalsLattice, x, y)
69,106✔
354
    if isa(x, Conditional)
69,412✔
355
        y = widenconditional(y)
104✔
356
        if isa(y, Const)
104✔
357
            y.val === false && return Conditional(x.slot, x.elsetype, x.thentype)
68✔
358
            y.val === true && return x
58✔
359
            return Const(false)
25✔
360
        end
361
    elseif isa(y, Conditional)
69,308✔
362
        x = widenconditional(x)
63✔
363
        if isa(x, Const)
63✔
364
            x.val === false && return Conditional(y.slot, y.elsetype, y.thentype)
27✔
365
            x.val === true && return y
21✔
366
            return Const(false)
15✔
367
        end
368
    end
369
    return egal_tfunc(widenlattice(𝕃), x, y)
69,377✔
370
end
371
@nospecs function egal_tfunc(𝕃::ConstsLattice, x, y)
372
    if isa(x, Const) && isa(y, Const)
69,611✔
373
        return Const(x.val === y.val)
231✔
374
    elseif (isa(x, Const) && y === typeof(x.val) && issingletontype(x)) ||
69,380✔
375
           (isa(y, Const) && x === typeof(y.val) && issingletontype(y))
376
        return Const(true)
×
377
    end
378
    return egal_tfunc(widenlattice(𝕃), x, y)
69,440✔
379
end
380
@nospecs function egal_tfunc(::JLTypeLattice, x, y)
69,152✔
381
    hasintersect(widenconst(x), widenconst(y)) || return Const(false)
78,966✔
382
    return Bool
59,614✔
383
end
384
add_tfunc(===, 2, 2, egal_tfunc, 1)
385

386
function isdefined_nothrow(𝕃::AbstractLattice, argtypes::Vector{Any})
387
    if length(argtypes) ≠ 2
756✔
388
        # TODO prove nothrow when ordering is specified
389
        return false
×
390
    end
391
    return isdefined_nothrow(𝕃, argtypes[1], argtypes[2])
756✔
392
end
393
@nospecs function isdefined_nothrow(𝕃::AbstractLattice, x, name)
756✔
394
    ⊑ = partialorder(𝕃)
756✔
395
    isvarargtype(x) && return false
756✔
396
    isvarargtype(name) && return false
756✔
397
    if hasintersect(widenconst(x), Module)
756✔
398
        return name ⊑ Symbol
×
399
    else
400
        return name ⊑ Symbol || name ⊑ Int
756✔
401
    end
402
end
403

404
@nospecs function isdefined_tfunc(𝕃::AbstractLattice, arg1, sym, order)
2,445✔
405
    return isdefined_tfunc(𝕃, arg1, sym)
2,445✔
406
end
407
@nospecs function isdefined_tfunc(𝕃::AbstractLattice, arg1, sym)
64,666✔
408
    if arg1 isa MustAlias
64,666✔
409
        arg1 = widenmustalias(arg1)
9✔
410
    end
411
    arg1t = arg1 isa Const ? typeof(arg1.val) : isconstType(arg1) ? typeof(arg1.parameters[1]) : widenconst(arg1)
82,061✔
412
    a1 = unwrap_unionall(arg1t)
64,666✔
413
    if isa(a1, DataType) && !isabstracttype(a1)
64,666✔
414
        if a1 === Module
64,666✔
415
            hasintersect(widenconst(sym), Symbol) || return Bottom
×
416
            # isa(sym, Const) case intercepted in abstract interpretation
417
        elseif isa(sym, Const)
64,666✔
418
            val = sym.val
64,666✔
419
            if isa(val, Symbol)
64,666✔
420
                idx = fieldindex(a1, val, false)::Int
9,137✔
421
            elseif isa(val, Int)
55,529✔
422
                idx = val
55,529✔
423
            else
424
                return Bottom
×
425
            end
426
            if 1 ≤ idx ≤ datatype_min_ninitialized(a1)
129,272✔
427
                return Const(true)
64,483✔
428
            elseif a1.name === _NAMEDTUPLE_NAME
183✔
429
                if isconcretetype(a1)
60✔
430
                    return Const(false)
60✔
431
                else
432
                    ns = a1.parameters[1]
×
433
                    if isa(ns, Tuple)
×
434
                        return Const(1 ≤ idx ≤ length(ns))
×
435
                    end
436
                end
437
            elseif idx ≤ 0 || (!isvatuple(a1) && idx > fieldcount(a1))
246✔
438
                return Const(false)
×
439
            elseif isa(arg1, Const)
123✔
440
                if !ismutabletype(a1) || isconst(a1, idx)
124✔
441
                    return Const(isdefined(arg1.val, idx))
2✔
442
                end
443
            elseif isa(arg1, PartialStruct)
61✔
444
                if !isvarargtype(arg1.fields[end])
58✔
445
                    aundefᵢ = _getundefs(arg1)[idx]
58✔
446
                    if aundefᵢ isa Bool
58✔
447
                        return Const(!aundefᵢ)
58✔
448
                    end
449
                end
450
            elseif !isvatuple(a1)
3✔
451
                fieldT = fieldtype(a1, idx)
3✔
452
                if isa(fieldT, DataType) && isbitstype(fieldT)
3✔
453
                    return Const(true)
×
454
                end
455
            end
456
        # datatype_fieldcount is what `fieldcount` uses internally
457
        # and returns nothing (!==0) for non-definite field counts.
458
        elseif datatype_fieldcount(a1) === 0
×
459
            return Const(false)
×
460
        end
461
    elseif isa(a1, Union)
×
462
        # Results can only be `Const` or `Bool`
463
        return tmerge(𝕃,
×
464
                      isdefined_tfunc(𝕃, rewrap_unionall(a1.a, arg1t), sym),
465
                      isdefined_tfunc(𝕃, rewrap_unionall(a1.b, arg1t), sym))
466
    end
467
    return Bool
63✔
468
end
469

470
add_tfunc(isdefined, 2, 3, isdefined_tfunc, 1)
471

472
function sizeof_nothrow(@nospecialize(x))
88✔
473
    if isa(x, Const)
88✔
474
        if !isa(x.val, Type) || x.val === DataType
141✔
475
            return true
35✔
476
        end
477
    end
478
    xu = unwrap_unionall(x)
53✔
479
    if isa(xu, Union)
53✔
480
        return sizeof_nothrow(rewrap_unionall(xu.a, x)) &&
×
481
               sizeof_nothrow(rewrap_unionall(xu.b, x))
482
    end
483
    t, exact, isconcrete = instanceof_tfunc(x, false)
53✔
484
    if t === Bottom
53✔
485
        # x must be an instance (not a Type) or is the Bottom type object
486
        x = widenconst(x)
×
487
        return !hasintersect(x, Type)
×
488
    end
489
    x = unwrap_unionall(t)
53✔
490
    if isconcrete
53✔
491
        if isa(x, DataType) && x.layout != C_NULL
53✔
492
            # there's just a few concrete types with an opaque layout
493
            (datatype_nfields(x) == 0 && !datatype_pointerfree(x)) && return false
53✔
494
        end
495
        return true # these must always have a size of these
53✔
496
    end
497
    exact || return false # Could always be the type Bottom at runtime, for example, which throws
×
498
    t === DataType && return true # DataType itself has a size
×
499
    if isa(x, Union)
×
500
        isinline = uniontype_layout(x)[1]
×
501
        return isinline # even any subset of this union would have a size
×
502
    end
503
    isa(x, DataType) || return false
×
504
    x.layout == C_NULL && return false
×
505
    (datatype_nfields(x) == 0 && !datatype_pointerfree(x)) && return false # is-layout-opaque
×
506
    return true
×
507
end
508

509
function _const_sizeof(@nospecialize(x))
×
510
    # Constant GenericMemory does not have constant size
511
    isa(x, GenericMemory) && return Int
×
512
    size = try
×
513
            Core.sizeof(x)
×
514
        catch ex
515
            # Might return
516
            # "argument is an abstract type; size is indeterminate" or
517
            # "type does not have a fixed size"
518
            isa(ex, ErrorException) || rethrow()
×
519
            return Int
×
520
        end
521
    return Const(size)
×
522
end
523
@nospecs function sizeof_tfunc(𝕃::AbstractLattice, x)
×
524
    x = widenmustalias(x)
×
525
    isa(x, Const) && return _const_sizeof(x.val)
×
526
    isa(x, Conditional) && return _const_sizeof(Bool)
×
527
    isconstType(x) && return _const_sizeof(x.parameters[1])
×
528
    xu = unwrap_unionall(x)
×
529
    if isa(xu, Union)
×
530
        return tmerge(sizeof_tfunc(𝕃, rewrap_unionall(xu.a, x)),
×
531
                      sizeof_tfunc(𝕃, rewrap_unionall(xu.b, x)))
532
    end
533
    # Core.sizeof operates on either a type or a value. First check which
534
    # case we're in.
535
    t, exact = instanceof_tfunc(x, false)
×
536
    if t !== Bottom
×
537
        # The value corresponding to `x` at runtime could be a type.
538
        # Normalize the query to ask about that type.
539
        x = unwrap_unionall(t)
×
540
        if exact && isa(x, Union)
×
541
            isinline = uniontype_layout(x)[1]
×
542
            return isinline ? Const(Int(Core.sizeof(x))) : Bottom
×
543
        end
544
        isa(x, DataType) || return Int
×
545
        (isconcretetype(x) || isprimitivetype(x)) && return _const_sizeof(x)
×
546
    else
547
        x = widenconst(x)
×
548
        x !== DataType && isconcretetype(x) && return _const_sizeof(x)
×
549
        isprimitivetype(x) && return _const_sizeof(x)
×
550
    end
551
    return Int
×
552
end
553
add_tfunc(Core.sizeof, 1, 1, sizeof_tfunc, 1)
554
@nospecs function nfields_tfunc(𝕃::AbstractLattice, x)
107✔
555
    isa(x, Const) && return Const(nfields(x.val))
107✔
556
    isa(x, Conditional) && return Const(0)
107✔
557
    xt = widenconst(x)
107✔
558
    x = unwrap_unionall(xt)
107✔
559
    isconstType(x) && return Const(nfields(x.parameters[1]))
107✔
560
    if isa(x, DataType) && !isabstracttype(x)
107✔
561
        if x.name === Tuple.name
107✔
562
            isvatuple(x) && return Int
58✔
563
            return Const(length(x.types))
58✔
564
        elseif x.name === _NAMEDTUPLE_NAME
49✔
565
            length(x.parameters) == 2 || return Int
49✔
566
            names = x.parameters[1]
49✔
567
            isa(names, Tuple{Vararg{Symbol}}) || return nfields_tfunc(𝕃, rewrap_unionall(x.parameters[2], xt))
49✔
568
            return Const(length(names))
49✔
569
        else
570
            return Const(isdefined(x, :types) ? length(x.types) : length(x.name.names))
×
571
        end
572
    end
573
    if isa(x, Union)
×
574
        na = nfields_tfunc(𝕃, unwraptv(x.a))
×
575
        na === Int && return Int
×
576
        return tmerge(𝕃, na, nfields_tfunc(𝕃, unwraptv(x.b)))
×
577
    end
578
    return Int
×
579
end
580
add_tfunc(nfields, 1, 1, nfields_tfunc, 1)
581
add_tfunc(Core._expr, 1, INT_INF, @nospecs((𝕃::AbstractLattice, args...)->Expr), 100)
4,440✔
582
add_tfunc(svec, 0, INT_INF, @nospecs((𝕃::AbstractLattice, args...)->SimpleVector), 20)
×
583

584
@nospecs function _svec_len_tfunc(::AbstractLattice, s)
1,361✔
585
    if isa(s, Const) && isa(s.val, SimpleVector)
1,361✔
586
        return Const(length(s.val))
×
587
    end
588
    return Int
1,361✔
589
end
590
add_tfunc(Core._svec_len, 1, 1, _svec_len_tfunc, 1)
591
@nospecs function _svec_len_nothrow(𝕃::AbstractLattice, s)
592
    ⊑ = partialorder(𝕃)
×
593
    return s ⊑ SimpleVector
×
594
end
595

596
@nospecs function _svec_ref_tfunc(::AbstractLattice, s, i)
597
    if isa(s, Const) && isa(i, Const)
×
598
        s, i = s.val, i.val
×
599
        if isa(s, SimpleVector) && isa(i, Int)
×
600
            return 1 ≤ i ≤ length(s) ? Const(s[i]) : Bottom
×
601
        end
602
    end
603
    return Any
×
604
end
605
add_tfunc(Core._svec_ref, 2, 2, _svec_ref_tfunc, 1)
606
@nospecs function typevar_tfunc(::AbstractLattice, n, lb_arg, ub_arg)
15✔
607
    lb = Union{}
15✔
608
    ub = Any
15✔
609
    ub_certain = lb_certain = true
15✔
610
    if isa(n, Const)
15✔
611
        nval = n.val
15✔
612
        isa(nval, Symbol) || return Union{}
15✔
613
        if isa(lb_arg, Const)
15✔
614
            lb = lb_arg.val
15✔
615
        else
616
            lb_arg = widenslotwrapper(lb_arg)
×
617
            if isType(lb_arg)
×
618
                lb = lb_arg.parameters[1]
×
619
                lb_certain = false
×
620
            else
621
                return TypeVar
×
622
            end
623
        end
624
        if isa(ub_arg, Const)
15✔
625
            ub = ub_arg.val
15✔
626
        else
627
            ub_arg = widenslotwrapper(ub_arg)
×
628
            if isType(ub_arg)
×
629
                ub = ub_arg.parameters[1]
×
630
                ub_certain = false
×
631
            else
632
                return TypeVar
×
633
            end
634
        end
635
        lb_valid = lb isa Type || lb isa TypeVar
15✔
636
        ub_valid = ub isa Type || ub isa TypeVar
15✔
637
        if lb_valid && ub_valid
15✔
638
            tv = TypeVar(nval, lb, ub)
15✔
639
            return PartialTypeVar(tv, lb_certain, ub_certain)
15✔
640
        elseif !lb_valid && lb_certain
×
641
            return Union{}
×
642
        elseif !ub_valid && ub_certain
×
643
            return Union{}
×
644
        end
645
    end
646
    return TypeVar
×
647
end
648
@nospecs function typebound_nothrow(𝕃::AbstractLattice, b)
30✔
649
    ⊑ = partialorder(𝕃)
30✔
650
    b = widenconst(b)
30✔
651
    (b ⊑ TypeVar) && return true
30✔
652
    if isType(b)
30✔
653
        return true
30✔
654
    end
655
    return false
×
656
end
657
@nospecs function typevar_nothrow(𝕃::AbstractLattice, n, lb, ub)
×
658
    ⊑ = partialorder(𝕃)
15✔
659
    n ⊑ Symbol || return false
15✔
660
    typebound_nothrow(𝕃, lb) || return false
15✔
661
    typebound_nothrow(𝕃, ub) || return false
15✔
662
    return true
15✔
663
end
664
add_tfunc(Core._typevar, 3, 3, typevar_tfunc, 100)
665

666
struct MemoryOrder x::Cint end
667
const MEMORY_ORDER_UNSPECIFIED = MemoryOrder(-2)
668
const MEMORY_ORDER_INVALID     = MemoryOrder(-1)
669
const MEMORY_ORDER_NOTATOMIC   = MemoryOrder(0)
670
const MEMORY_ORDER_UNORDERED   = MemoryOrder(1)
671
const MEMORY_ORDER_MONOTONIC   = MemoryOrder(2)
672
const MEMORY_ORDER_CONSUME     = MemoryOrder(3)
673
const MEMORY_ORDER_ACQUIRE     = MemoryOrder(4)
674
const MEMORY_ORDER_RELEASE     = MemoryOrder(5)
675
const MEMORY_ORDER_ACQ_REL     = MemoryOrder(6)
676
const MEMORY_ORDER_SEQ_CST     = MemoryOrder(7)
677

678
function get_atomic_order(order::Symbol, loading::Bool, storing::Bool)
679
    if order === :not_atomic
300✔
680
        return MEMORY_ORDER_NOTATOMIC
×
681
    elseif order === :unordered && (loading ⊻ storing)
300✔
682
        return MEMORY_ORDER_UNORDERED
300✔
683
    elseif order === :monotonic && (loading | storing)
×
684
        return MEMORY_ORDER_MONOTONIC
×
685
    elseif order === :acquire && loading
×
686
        return MEMORY_ORDER_ACQUIRE
×
687
    elseif order === :release && storing
×
688
        return MEMORY_ORDER_RELEASE
×
689
    elseif order === :acquire_release && (loading & storing)
×
690
        return MEMORY_ORDER_ACQ_REL
×
691
    elseif order === :sequentially_consistent
×
692
        return MEMORY_ORDER_SEQ_CST
×
693
    end
694
    return MEMORY_ORDER_INVALID
×
695
end
696

697
function pointer_eltype(@nospecialize(ptr))
254✔
698
    a = widenconst(ptr)
254✔
699
    if !has_free_typevars(a)
254✔
700
        unw = unwrap_unionall(a)
254✔
701
        if isa(unw, DataType) && unw.name === Ptr.body.name
254✔
702
            T = unw.parameters[1]
254✔
703
            valid_as_lattice(T, true) || return Bottom
254✔
704
            return rewrap_unionall(T, a)
254✔
705
        end
706
    end
707
    return Any
×
708
end
709

710
@nospecs function pointerarith_tfunc(𝕃::AbstractLattice, ptr, offset)
318✔
711
    return ptr
318✔
712
end
713
@nospecs function pointerref_tfunc(𝕃::AbstractLattice, a, i, align)
×
714
    return pointer_eltype(a)
×
715
end
716
@nospecs function pointerset_tfunc(𝕃::AbstractLattice, a, v, i, align)
219✔
717
    return a
219✔
718
end
719
@nospecs function atomic_fence_tfunc(𝕃::AbstractLattice, order)
×
720
    return Nothing
×
721
end
722
@nospecs function atomic_pointerref_tfunc(𝕃::AbstractLattice, a, order)
723
    return pointer_eltype(a)
×
724
end
725
@nospecs function atomic_pointerset_tfunc(𝕃::AbstractLattice, a, v, order)
×
726
    return a
×
727
end
728
@nospecs function atomic_pointerswap_tfunc(𝕃::AbstractLattice, a, v, order)
120✔
729
    return pointer_eltype(a)
120✔
730
end
731
@nospecs function atomic_pointermodify_tfunc(𝕃::AbstractLattice, ptr, op, v, order)
×
732
    a = widenconst(ptr)
×
733
    if !has_free_typevars(a)
×
734
        unw = unwrap_unionall(a)
×
735
        if isa(unw, DataType) && unw.name === Ptr.body.name
×
736
            T = unw.parameters[1]
×
737
            # note: we could sometimes refine this to a PartialStruct if we analyzed `op(T, T)::T`
738
            valid_as_lattice(T, true) || return Bottom
×
739
            return rewrap_unionall(Pair{T, T}, a)
×
740
        end
741
    end
742
    return Pair
×
743
end
744
@nospecs function atomic_pointerreplace_tfunc(𝕃::AbstractLattice, ptr, x, v, success_order, failure_order)
×
745
    a = widenconst(ptr)
×
746
    if !has_free_typevars(a)
×
747
        unw = unwrap_unionall(a)
×
748
        if isa(unw, DataType) && unw.name === Ptr.body.name
×
749
            T = unw.parameters[1]
×
750
            valid_as_lattice(T) || return Bottom
×
751
            return rewrap_unionall(ccall(:jl_apply_cmpswap_type, Any, (Any,), T), a)
×
752
        end
753
    end
754
    return ccall(:jl_apply_cmpswap_type, Any, (Any,), T) where T
×
755
end
756
add_tfunc(add_ptr, 2, 2, pointerarith_tfunc, 1)
757
add_tfunc(sub_ptr, 2, 2, pointerarith_tfunc, 1)
758
add_tfunc(pointerref, 3, 3, pointerref_tfunc, 4)
759
add_tfunc(pointerset, 4, 4, pointerset_tfunc, 5)
760
add_tfunc(atomic_fence, 1, 1, atomic_fence_tfunc, 4)
761
add_tfunc(atomic_pointerref, 2, 2, atomic_pointerref_tfunc, 4)
762
add_tfunc(atomic_pointerset, 3, 3, atomic_pointerset_tfunc, 5)
763
add_tfunc(atomic_pointerswap, 3, 3, atomic_pointerswap_tfunc, 5)
764
add_tfunc(atomic_pointermodify, 4, 4, atomic_pointermodify_tfunc, 5)
765
add_tfunc(atomic_pointerreplace, 5, 5, atomic_pointerreplace_tfunc, 5)
766
add_tfunc(donotdelete, 0, INT_INF, @nospecs((𝕃::AbstractLattice, args...)->Nothing), 0)
90✔
767
@nospecs function compilerbarrier_tfunc(𝕃::AbstractLattice, setting, val)
30✔
768
    # strongest barrier if a precise information isn't available at compiler time
769
    # XXX we may want to have "compile-time" error instead for such case
770
    isa(setting, Const) || return Any
30✔
771
    setting = setting.val
30✔
772
    isa(setting, Symbol) || return Any
30✔
773
    if setting === :const
30✔
774
        return widenconst(val)
×
775
    elseif setting === :conditional
30✔
776
        return widenconditional(val)
×
777
    elseif setting === :type
30✔
778
        return Any
30✔
779
    else
780
        return Bottom
×
781
    end
782
end
783
add_tfunc(compilerbarrier, 2, 2, compilerbarrier_tfunc, 5)
784
add_tfunc(Core.finalizer, 2, 4, @nospecs((𝕃::AbstractLattice, args...)->Nothing), 5)
×
785

786
@nospecs function compilerbarrier_nothrow(setting, val)
787
    return isa(setting, Const) && contains_is((:type, :const, :conditional), setting.val)
30✔
788
end
789

790
# more accurate typeof_tfunc for vararg tuples abstract only in length
791
function typeof_concrete_vararg(t::DataType)
450✔
792
    np = length(t.parameters)
450✔
793
    for i = 1:np
900✔
794
        p = t.parameters[i]
695✔
795
        if i == np && isvarargtype(p)
695✔
796
            if isdefined(p, :T) && isconcretetype(p.T)
39✔
797
                t = Type{Tuple{t.parameters[1:np-1]..., Vararg{p.T, N}}} where N
6✔
798
                if isdefined(p, :N)
3✔
799
                    return t{p.N}
×
800
                end
801
                return t
3✔
802
            end
803
        elseif !isconcretetype(p)
656✔
804
            break
411✔
805
        end
806
    end
526✔
807
    return nothing
447✔
808
end
809

810
@nospecs function typeof_tfunc(𝕃::AbstractLattice, t)
29,109✔
811
    isa(t, Const) && return Const(typeof(t.val))
29,109✔
812
    t = widenconst(t)
29,109✔
813
    if isType(t)
29,109✔
814
        tp = t.parameters[1]
33✔
815
        if hasuniquerep(tp)
66✔
816
            return Const(typeof(tp))
×
817
        end
818
    elseif isa(t, DataType)
29,076✔
819
        if isconcretetype(t)
28,037✔
820
            return Const(t)
26,722✔
821
        elseif t === Any
1,315✔
822
            return DataType
477✔
823
        else
824
            if t.name === Tuple.name
838✔
825
                tt = typeof_concrete_vararg(t)
447✔
826
                tt === nothing || return tt
450✔
827
            end
828
            return Type{<:t}
835✔
829
        end
830
    elseif isa(t, Union)
1,039✔
831
        a = widenconst(_typeof_tfunc(𝕃, t.a))
26✔
832
        b = widenconst(_typeof_tfunc(𝕃, t.b))
26✔
833
        return Union{a, b}
26✔
834
    elseif isa(t, UnionAll)
1,013✔
835
        u = unwrap_unionall(t)
1,013✔
836
        if isa(u, DataType) && !isabstracttype(u)
1,013✔
837
            if u.name === Tuple.name
963✔
838
                uu = typeof_concrete_vararg(u)
9✔
839
                if uu !== nothing
9✔
840
                    return rewrap_unionall(uu, t)
×
841
                end
842
            else
843
                return rewrap_unionall(Type{u}, t)
954✔
844
            end
845
        end
846
        return rewrap_unionall(widenconst(typeof_tfunc(𝕃, u)), t)
59✔
847
    end
848
    return DataType # typeof(anything)::DataType
33✔
849
end
850
# helper function of `typeof_tfunc`, which accepts `TypeVar`
851
@nospecs function _typeof_tfunc(𝕃::AbstractLattice, t)
×
852
    if isa(t, TypeVar)
52✔
853
        return t.ub !== Any ? _typeof_tfunc(𝕃, t.ub) : DataType
×
854
    end
855
    return typeof_tfunc(𝕃, t)
52✔
856
end
857
add_tfunc(typeof, 1, 1, typeof_tfunc, 1)
858

859
@nospecs function typeassert_tfunc(𝕃::AbstractLattice, v, t)
3,005✔
860
    t = instanceof_tfunc(t, true)[1]
3,005✔
861
    t === Any && return v
3,005✔
862
    return tmeet(𝕃, v, t)
3,002✔
863
end
864
add_tfunc(typeassert, 2, 2, typeassert_tfunc, 4)
865

866
@nospecs function typeassert_nothrow(𝕃::AbstractLattice, v, t)
3✔
867
    ⊑ = partialorder(𝕃)
8,648✔
868
    # ty, exact = instanceof_tfunc(t, true)
869
    # return exact && v ⊑ ty
870
    if (isType(t) && !has_free_typevars(t) && v ⊑ t.parameters[1]) ||
17,296✔
871
        (isa(t, Const) && isa(t.val, Type) && v ⊑ t.val)
872
        return true
3,734✔
873
    end
874
    return false
4,914✔
875
end
876

877
@nospecs function isa_tfunc(𝕃::AbstractLattice, v, tt)
63,022✔
878
    t, isexact = instanceof_tfunc(tt, true)
63,022✔
879
    if t === Bottom
63,022✔
880
        # check if t could be equivalent to typeof(Bottom), since that's valid in `isa`, but the set of `v` is empty
881
        # if `t` cannot have instances, it's also invalid on the RHS of isa
882
        hasintersect(widenconst(tt), Type) || return Union{}
×
883
        return Const(false)
×
884
    end
885
    if !has_free_typevars(t)
63,022✔
886
        if ⊑(𝕃, v, t)
63,022✔
887
            if isexact && isnotbrokensubtype(v, t)
39,730✔
888
                return Const(true)
38,342✔
889
            end
890
        else
891
            if isa(v, Const) || isa(v, Conditional)
46,598✔
892
                # this and the `isdispatchelem` below test for knowledge of a
893
                # leaftype appearing on the LHS (ensuring the isa is precise)
894
                return Const(false)
216✔
895
            end
896
            v = widenconst(v)
23,125✔
897
            isdispatchelem(v) && return Const(false)
46,250✔
898
            if !hasintersect(v, t)
17,299✔
899
                # similar to `isnotbrokensubtype` check above, `typeintersect(v, t)`
900
                # can't be trusted for kind types so we do an extra check here
901
                if !iskindtype(v)
2,898✔
902
                    return Const(false)
1,432✔
903
                end
904
            end
905
        end
906
    end
907
    # TODO: handle non-leaftype(t) by testing against lower and upper bounds
908
    return Bool
17,206✔
909
end
910
add_tfunc(isa, 2, 2, isa_tfunc, 1)
911

912
@nospecs function isa_nothrow(𝕃::AbstractLattice, obj, typ)
913
    ⊑ = partialorder(𝕃)
24,065✔
914
    return typ ⊑ Type
24,065✔
915
end
916

917
@nospecs function subtype_tfunc(𝕃::AbstractLattice, a, b)
×
918
    a, isexact_a = instanceof_tfunc(a, false)
×
919
    b, isexact_b = instanceof_tfunc(b, false)
×
920
    if !has_free_typevars(a) && !has_free_typevars(b)
×
921
        if a <: b
×
922
            if isexact_b || a === Bottom
×
923
                return Const(true)
×
924
            end
925
        else
926
            if isexact_a || (b !== Bottom && !hasintersect(a, b))
×
927
                return Const(false)
×
928
            end
929
        end
930
    end
931
    return Bool
×
932
end
933
add_tfunc(<:, 2, 2, subtype_tfunc, 10)
934

935
@nospecs function subtype_nothrow(𝕃::AbstractLattice, lty, rty)
936
    ⊑ = partialorder(𝕃)
690✔
937
    return lty ⊑ Type && rty ⊑ Type
690✔
938
end
939

940
function try_compute_fieldidx(@nospecialize(typ), @nospecialize(field))
46,919✔
941
    typ = argument_datatype(typ)
64,751✔
942
    typ === nothing && return nothing
64,751✔
943
    if isa(field, Symbol)
63,814✔
944
        field = fieldindex(typ, field, false)
24,808✔
945
        field == 0 && return nothing
24,808✔
946
    elseif isa(field, Int)
39,943✔
947
        # Numerical field name can only be of type `Int`
948
        max_fields = fieldcount_noerror(typ)
39,748✔
949
        max_fields === nothing && return nothing
39,748✔
950
        (1 <= field <= max_fields) || return nothing
39,748✔
951
    else
952
        return nothing
195✔
953
    end
954
    return field
64,472✔
955
end
956

957
function getfield_boundscheck(argtypes::Vector{Any})
75,455✔
958
    if length(argtypes) == 2
75,455✔
959
        isvarargtype(argtypes[2]) && return :unsafe
75,365✔
960
        return :on
75,365✔
961
    elseif length(argtypes) == 3
90✔
962
        boundscheck = argtypes[3]
90✔
963
        isvarargtype(boundscheck) && return :unsafe
90✔
964
        if widenconst(boundscheck) === Symbol
90✔
965
            return :on
12✔
966
        end
967
    elseif length(argtypes) == 4
×
968
        boundscheck = argtypes[4]
×
969
        isvarargtype(boundscheck) && return :unsafe
×
970
    else
971
        return :unsafe
×
972
    end
973
    boundscheck = widenconditional(boundscheck)
78✔
974
    if widenconst(boundscheck) === Bool
78✔
975
        if isa(boundscheck, Const)
78✔
976
            return boundscheck.val::Bool ? :on : :off
×
977
        end
978
        return :unknown # including a case when specified as `:boundscheck`
78✔
979
    end
980
    return :unsafe
×
981
end
982

983
function getfield_nothrow(𝕃::AbstractLattice, argtypes::Vector{Any}, boundscheck::Symbol=getfield_boundscheck(argtypes))
75,707✔
984
    boundscheck === :unsafe && return false
75,707✔
985
    ordering = Const(:not_atomic)
75,707✔
986
    if length(argtypes) == 3
75,707✔
987
        isvarargtype(argtypes[3]) && return false
99✔
988
        if widenconst(argtypes[3]) !== Bool
99✔
989
            ordering = argtypes[3]
12✔
990
        end
991
    elseif length(argtypes) == 4
75,608✔
992
        ordering = argtypes[3]
×
993
    elseif length(argtypes) ≠ 2
75,608✔
994
        return false
×
995
    end
996
    isa(ordering, Const) || return false
75,713✔
997
    ordering = ordering.val
75,701✔
998
    isa(ordering, Symbol) || return false
75,701✔
999
    if ordering !== :not_atomic # TODO: this is assuming not atomic
75,701✔
1000
        return false
6✔
1001
    end
1002
    return getfield_nothrow(𝕃, argtypes[1], argtypes[2], !(boundscheck === :off))
75,695✔
1003
end
1004
@nospecs function getfield_nothrow(𝕃::AbstractLattice, s00, name, boundscheck::Bool)
75,719✔
1005
    # If we don't have boundscheck off and don't know the field, don't even bother
1006
    if boundscheck
75,719✔
1007
        isa(name, Const) || return false
76,032✔
1008
    end
1009

1010
    ⊑ = partialorder(𝕃)
75,406✔
1011

1012
    # If we have s00 being a const, we can potentially refine our type-based analysis above
1013
    if isa(s00, Const) || isconstType(s00) || isa(s00, PartialStruct)
104,234✔
1014
        if isa(s00, Const)
63,895✔
1015
            sv = s00.val
46,578✔
1016
            sty = typeof(sv)
46,578✔
1017
            nflds = nfields(sv)
46,578✔
1018
            ismod = sv isa Module
46,578✔
1019
        elseif isa(s00, PartialStruct)
17,317✔
1020
            sty = unwrap_unionall(s00.typ)
17,317✔
1021
            nflds = fieldcount_noerror(sty)
17,317✔
1022
            ismod = false
17,317✔
1023
        else
1024
            sv = (s00::DataType).parameters[1]
×
1025
            sty = typeof(sv)
×
1026
            nflds = nfields(sv)
×
1027
            ismod = sv isa Module
×
1028
        end
1029
        if isa(name, Const)
63,895✔
1030
            nval = name.val
63,895✔
1031
            if !isa(nval, Symbol)
63,895✔
1032
                ismod && return false
55,517✔
1033
                isa(nval, Int) || return false
55,517✔
1034
            end
1035
            return isdefined_tfunc(𝕃, s00, name) === Const(true)
63,895✔
1036
        end
1037

1038
        # If bounds checking is disabled and all fields are assigned,
1039
        # we may assume that we don't throw
1040
        @assert !boundscheck
×
1041
        ismod && return false
×
1042
        name ⊑ Int || name ⊑ Symbol || return false
×
1043
        sty.name.n_uninitialized == 0 && return true
×
1044
        nflds === nothing && return false
×
1045
        for i = (datatype_min_ninitialized(sty)+1):nflds
×
1046
            isdefined_tfunc(𝕃, s00, Const(i)) === Const(true) || return false
×
1047
        end
×
1048
        return true
×
1049
    end
1050

1051
    s0 = widenconst(s00)
11,511✔
1052
    s = unwrap_unionall(s0)
11,511✔
1053
    if isa(s, Union)
11,511✔
1054
        return getfield_nothrow(𝕃, rewrap_unionall(s.a, s00), name, boundscheck) &&
12✔
1055
               getfield_nothrow(𝕃, rewrap_unionall(s.b, s00), name, boundscheck)
1056
    elseif isType(s) && isTypeDataType(s.parameters[1])
11,499✔
1057
        s = s0 = DataType
×
1058
    end
1059
    if isa(s, DataType)
11,499✔
1060
        # Can't say anything about abstract types
1061
        isabstracttype(s) && return false
11,499✔
1062
        # If all fields are always initialized, and bounds check is disabled,
1063
        # we can assume we don't throw
1064
        if !boundscheck && s.name.n_uninitialized == 0
11,493✔
1065
            name ⊑ Int || name ⊑ Symbol || return false
×
1066
            return true
×
1067
        end
1068
        # Else we need to know what the field is
1069
        isa(name, Const) || return false
11,493✔
1070
        field = try_compute_fieldidx(s, name.val)
11,493✔
1071
        field === nothing && return false
11,493✔
1072
        isfieldatomic(s, field) && return false # TODO: currently we're only testing for ordering === :not_atomic
11,535✔
1073
        field <= datatype_min_ninitialized(s) && return true
22,986✔
1074
        # `try_compute_fieldidx` already check for field index bound.
1075
        !isvatuple(s) && isbitstype(fieldtype(s0, field)) && return true
196✔
1076
    end
1077

1078
    return false
4✔
1079
end
1080

1081
@nospecs function getfield_tfunc(𝕃::AbstractLattice, s00, name, boundscheck_or_order)
57✔
1082
    if !isvarargtype(boundscheck_or_order)
57✔
1083
        t = widenconst(boundscheck_or_order)
57✔
1084
        hasintersect(t, Symbol) || hasintersect(t, Bool) || return Bottom
108✔
1085
    end
1086
    return getfield_tfunc(𝕃, s00, name)
57✔
1087
end
1088
@nospecs function getfield_tfunc(𝕃::AbstractLattice, s00, name, order, boundscheck)
42✔
1089
    hasintersect(widenconst(order), Symbol) || return Bottom
48✔
1090
    if !isvarargtype(boundscheck)
36✔
1091
        hasintersect(widenconst(boundscheck), Bool) || return Bottom
27✔
1092
    end
1093
    return getfield_tfunc(𝕃, s00, name)
33✔
1094
end
1095
@nospecs function getfield_tfunc(𝕃::AbstractLattice, s00, name)
26,229✔
1096
    _getfield_tfunc(𝕃, s00, name, false)
178,039✔
1097
end
1098

1099
function _getfield_fieldindex(s::DataType, name::Const)
1100
    nv = name.val
104,129✔
1101
    if isa(nv, Symbol)
104,129✔
1102
        nv = fieldindex(s, nv, false)
11,573✔
1103
    end
1104
    if isa(nv, Int)
104,129✔
1105
        return nv
104,129✔
1106
    end
1107
    return nothing
×
1108
end
1109

1110
function _getfield_tfunc_const(@nospecialize(sv), name::Const)
1111
    nv = _getfield_fieldindex(typeof(sv), name)
75,222✔
1112
    nv === nothing && return Bottom
75,222✔
1113
    if isa(sv, DataType) && nv == DATATYPE_TYPES_FIELDINDEX && isdefined(sv, nv)
75,222✔
1114
        return Const(getfield(sv, nv))
×
1115
    end
1116
    if !isa(sv, Module) && isconst(typeof(sv), nv)
75,316✔
1117
        if isdefined(sv, nv)
75,162✔
1118
            return Const(getfield(sv, nv))
75,162✔
1119
        end
1120
        return Bottom
×
1121
    end
1122
    return nothing
60✔
1123
end
1124

1125
@nospecs function _getfield_tfunc(𝕃::InferenceLattice, s00, name, setfield::Bool)
×
1126
    if isa(s00, LimitedAccuracy)
82,706✔
1127
        # This will error, but it's better than duplicating the error here
1128
        s00 = widenconst(s00)
×
1129
    end
1130
    return _getfield_tfunc(widenlattice(𝕃), s00, name, setfield)
139,795✔
1131
end
1132

1133
@nospecs function _getfield_tfunc(𝕃::AnyConditionalsLattice, s00, name, setfield::Bool)
1134
    if isa(s00, AnyConditional)
82,706✔
1135
        return Bottom # Bool has no fields
×
1136
    end
1137
    return _getfield_tfunc(widenlattice(𝕃), s00, name, setfield)
82,706✔
1138
end
1139

1140
@nospecs function _getfield_tfunc(𝕃::AnyMustAliasesLattice, s00, name, setfield::Bool)
1141
    return _getfield_tfunc(widenlattice(𝕃), widenmustalias(s00), widenmustalias(name), setfield)
510✔
1142
end
1143

1144
@nospecs function _getfield_tfunc(𝕃::PartialsLattice, s00, name, setfield::Bool)
1145
    if isa(s00, PartialStruct)
122,241✔
1146
        s = widenconst(s00)
41,130✔
1147
        sty = unwrap_unionall(s)::DataType
41,130✔
1148
        if isa(name, Const)
41,130✔
1149
            nv = _getfield_fieldindex(sty, name)
41,130✔
1150
            if isa(nv, Int)
41,130✔
1151
                if nv < 1
41,130✔
1152
                    return Bottom
×
1153
                elseif nv ≤ length(s00.fields)
41,130✔
1154
                    return unwrapva(s00.fields[nv])
41,130✔
1155
                end
1156
            end
1157
        end
1158
        s00 = s
×
1159
    end
1160
    return _getfield_tfunc(widenlattice(𝕃), s00, name, setfield)
81,111✔
1161
end
1162

1163
@nospecs function _getfield_tfunc(𝕃::ConstsLattice, s00, name, setfield::Bool)
79,311✔
1164
    if isa(s00, Const)
79,311✔
1165
        sv = s00.val
75,210✔
1166
        if isa(name, Const)
75,210✔
1167
            nv = name.val
75,192✔
1168
            if isa(sv, Module)
75,192✔
1169
                setfield && return Bottom
×
1170
                if isa(nv, Symbol)
×
1171
                    # In ordinary inference, this case is intercepted early and
1172
                    # re-routed to `getglobal`.
1173
                    return Any
×
1174
                end
1175
                return Bottom
×
1176
            end
1177
            r = _getfield_tfunc_const(sv, name)
150,384✔
1178
            r !== nothing && return r
75,192✔
1179
        end
1180
        s00 = widenconst(s00)
51✔
1181
    end
1182
    return _getfield_tfunc(widenlattice(𝕃), s00, name, setfield)
4,149✔
1183
end
1184

1185
@nospecs function _getfield_tfunc(𝕃::JLTypeLattice, s00, name, setfield::Bool)
4,188✔
1186
    s = unwrap_unionall(s00)
4,188✔
1187
    if isa(s, Union)
4,188✔
1188
        return tmerge(_getfield_tfunc(𝕃, rewrap_unionall(s.a, s00), name, setfield),
12✔
1189
                      _getfield_tfunc(𝕃, rewrap_unionall(s.b, s00), name, setfield))
1190
    end
1191
    if isType(s)
4,176✔
1192
        if isconstType(s)
90✔
1193
            sv = (s00::DataType).parameters[1]
45✔
1194
            if isa(name, Const)
45✔
1195
                r = _getfield_tfunc_const(sv, name)
60✔
1196
                r !== nothing && return r
30✔
1197
            end
1198
            s = typeof(sv)
45✔
1199
        else
1200
            sv = s.parameters[1]
×
1201
            if isTypeDataType(sv) && isa(name, Const)
×
1202
                nv = _getfield_fieldindex(DataType, name)::Int
×
1203
                if nv == DATATYPE_NAME_FIELDINDEX
×
1204
                    # N.B. This only works for fields that do not depend on type
1205
                    # parameters (which we do not know here).
1206
                    return Const(sv.name)
×
1207
                end
1208
                s = DataType
×
1209
            end
1210
        end
1211
    end
1212
    isa(s, DataType) || return Any
4,176✔
1213
    isabstracttype(s) && return Any
4,176✔
1214
    if s <: Tuple && !hasintersect(widenconst(name), Int)
4,176✔
1215
        return Bottom
×
1216
    end
1217
    if s <: Module
4,176✔
1218
        setfield && return Bottom
×
1219
        hasintersect(widenconst(name), Symbol) || return Bottom
×
1220
        return Any
×
1221
    end
1222
    if s.name === _NAMEDTUPLE_NAME && !isconcretetype(s)
4,176✔
1223
        if isa(name, Const) && isa(name.val, Symbol)
6✔
1224
            if isa(s.parameters[1], Tuple)
×
1225
                name = Const(Int(ccall(:jl_field_index, Cint, (Any, Any, Cint), s, name.val, false)+1))
×
1226
            else
1227
                name = Int
×
1228
            end
1229
        elseif Symbol ⊑ name
6✔
1230
            name = Int
×
1231
        end
1232
        _ts = unwraptv(s.parameters[2])
6✔
1233
        _ts = rewrap_unionall(_ts, s00)
6✔
1234
        if !(_ts <: Tuple)
6✔
1235
            return Any
×
1236
        end
1237
        return _getfield_tfunc(𝕃, _ts, name, setfield)
6✔
1238
    end
1239
    ftypes = datatype_fieldtypes(s)
4,170✔
1240
    nf = length(ftypes)
4,170✔
1241
    # If no value has this type, then this statement should be unreachable.
1242
    # Bail quickly now.
1243
    if !has_concrete_subtype(s) || nf == 0
8,340✔
1244
        return Bottom
×
1245
    end
1246
    if isa(name, Conditional)
4,170✔
1247
        return Bottom # can't index fields with Bool
×
1248
    end
1249
    if !isa(name, Const)
4,170✔
1250
        name = widenconst(name)
156✔
1251
        if !(Int <: name || Symbol <: name)
231✔
1252
            return Bottom
×
1253
        end
1254
        if nf == 1
156✔
1255
            fld = 1
12✔
1256
        else
1257
            # union together types of all fields
1258
            t = Bottom
144✔
1259
            for i in 1:nf
288✔
1260
                _ft = unwrapva(ftypes[i])
607✔
1261
                valid_as_lattice(_ft, true) || continue
607✔
1262
                setfield && isconst(s, i) && continue
613✔
1263
                t = tmerge(t, rewrap_unionall(_ft, s00))
1,214✔
1264
                t === Any && break
607✔
1265
            end
1,044✔
1266
            return t
144✔
1267
        end
1268
    else
1269
        fld = _getfield_fieldindex(s, name)
4,014✔
1270
        fld === nothing && return Bottom
4,014✔
1271
    end
1272
    if s <: Tuple && fld >= nf && isvarargtype(ftypes[nf])
4,026✔
1273
        R = unwrapva(ftypes[nf])
6✔
1274
    else
1275
        if fld < 1 || fld > nf
8,040✔
1276
            return Bottom
×
1277
        elseif setfield && isconst(s, fld)
4,632✔
1278
            return Bottom
×
1279
        end
1280
        R = ftypes[fld]
4,020✔
1281
        valid_as_lattice(R, true) || return Bottom
4,020✔
1282
        if isempty(s.parameters)
4,020✔
1283
            return R
984✔
1284
        end
1285
    end
1286
    return rewrap_unionall(R, s00)
3,042✔
1287
end
1288

1289
# checks if a field of this type is guaranteed to be defined to a value
1290
# and that access to an uninitialized field will cause an `UndefRefError` or return zero
1291
# - is_undefref_fieldtype(String) === true
1292
# - is_undefref_fieldtype(Integer) === true
1293
# - is_undefref_fieldtype(Any) === true
1294
# - is_undefref_fieldtype(Int) === false
1295
# - is_undefref_fieldtype(Union{Int32,Int64}) === false
1296
# - is_undefref_fieldtype(T) === false
1297
function is_undefref_fieldtype(@nospecialize ftyp)
1298
    return !has_free_typevars(ftyp) && !allocatedinline(ftyp)
137✔
1299
end
1300

1301
@nospecs function setfield!_tfunc(𝕃::AbstractLattice, o, f, v, order)
×
1302
    if !isvarargtype(order)
×
1303
        hasintersect(widenconst(order), Symbol) || return Bottom
×
1304
    end
1305
    return setfield!_tfunc(𝕃, o, f, v)
×
1306
end
1307
@nospecs function setfield!_tfunc(𝕃::AbstractLattice, o, f, v)
664✔
1308
    mutability_errorcheck(o) || return Bottom
664✔
1309
    ft = _getfield_tfunc(𝕃, o, f, true)
1,328✔
1310
    ft === Bottom && return Bottom
664✔
1311
    hasintersect(widenconst(v), widenconst(ft)) || return Bottom
664✔
1312
    return v
664✔
1313
end
1314
mutability_errorcheck(@nospecialize obj) = _mutability_errorcheck(widenconst(obj))
661✔
1315
function _mutability_errorcheck(@nospecialize objt0)
661✔
1316
    objt = unwrap_unionall(objt0)
661✔
1317
    if isa(objt, Union)
661✔
1318
        return _mutability_errorcheck(rewrap_unionall(objt.a, objt0)) ||
×
1319
               _mutability_errorcheck(rewrap_unionall(objt.b, objt0))
1320
    elseif isa(objt, DataType)
661✔
1321
        # Can't say anything about abstract types
1322
        isabstracttype(objt) && return true
661✔
1323
        return ismutabletype(objt)
661✔
1324
    end
1325
    return true
×
1326
end
1327

1328
@nospecs function setfield!_nothrow(𝕃::AbstractLattice, s00, name, v, order)
3✔
1329
    order === Const(:not_atomic) || return false # currently setfield!_nothrow is assuming not atomic
6✔
1330
    return setfield!_nothrow(𝕃, s00, name, v)
×
1331
end
1332
@nospecs function setfield!_nothrow(𝕃::AbstractLattice, s00, name, v)
1,331✔
1333
    s0 = widenconst(s00)
1,331✔
1334
    s = unwrap_unionall(s0)
1,331✔
1335
    if isa(s, Union)
1,331✔
1336
        return setfield!_nothrow(𝕃, rewrap_unionall(s.a, s00), name, v) &&
×
1337
               setfield!_nothrow(𝕃, rewrap_unionall(s.b, s00), name, v)
1338
    elseif isa(s, DataType)
1,331✔
1339
        # Can't say anything about abstract types
1340
        isabstracttype(s) && return false
1,331✔
1341
        ismutabletype(s) || return false
1,331✔
1342
        isa(name, Const) || return false
1,357✔
1343
        field = try_compute_fieldidx(s, name.val)
1,305✔
1344
        field === nothing && return false
1,305✔
1345
        # `try_compute_fieldidx` already check for field index bound.
1346
        isconst(s, field) && return false
2,532✔
1347
        isfieldatomic(s, field) && return false # TODO: currently we're only testing for ordering === :not_atomic
1,329✔
1348
        v_expected = fieldtype(s0, field)
1,305✔
1349
        ⊑ = partialorder(𝕃)
1,305✔
1350
        return v ⊑ v_expected
1,305✔
1351
    end
1352
    return false
×
1353
end
1354

1355
@nospecs function swapfield!_tfunc(𝕃::AbstractLattice, o, f, v, order=Symbol)
153✔
1356
    setfield!_tfunc(𝕃, o, f, v) === Bottom && return Bottom
153✔
1357
    return getfield_tfunc(𝕃, o, f)
1358
end
1359
@nospecs function modifyfield!_tfunc(𝕃::AbstractLattice, o, f, op, v, order=Symbol)
×
1360
    o′ = widenconst(o)
×
1361
    T = _fieldtype_tfunc(𝕃, o′, f, isconcretetype(o′))
×
1362
    T === Bottom && return Bottom
×
1363
    PT = Const(Pair)
×
1364
    return instanceof_tfunc(apply_type_tfunc(𝕃, Any[PT, T, T]), true)[1]
×
1365
end
1366
@nospecs function replacefield!_tfunc(𝕃::AbstractLattice, o, f, x, v, success_order=Symbol, failure_order=Symbol)
699✔
1367
    o′ = widenconst(o)
699✔
1368
    T = _fieldtype_tfunc(𝕃, o′, f, isconcretetype(o′))
1369
    T === Bottom && return Bottom
1370
    PT = Const(ccall(:jl_apply_cmpswap_type, Any, (Any,), T) where T)
1371
    return instanceof_tfunc(apply_type_tfunc(𝕃, Any[PT, T]), true)[1]
1372
end
1373
@nospecs function setfieldonce!_tfunc(𝕃::AbstractLattice, o, f, v, success_order=Symbol, failure_order=Symbol)
2,949✔
1374
    setfield!_tfunc(𝕃, o, f, v) === Bottom && return Bottom
3,345✔
1375
    isdefined_tfunc(𝕃, o, f) === Const(true) && return Const(false)
2,949✔
1376
    return Bool
2,664✔
1377
end
1378

1379
@nospecs function abstract_modifyop!(interp::AbstractInterpreter, ff, argtypes::Vector{Any}, si::StmtInfo, sv::AbsIntState)
64✔
1380
    if ff === modifyfield!
64✔
1381
        minargs = 5
64✔
1382
        maxargs = 6
64✔
1383
        op_argi = 4
64✔
1384
        v_argi = 5
64✔
1385
    elseif ff === Core.modifyglobal!
×
1386
        minargs = 5
×
1387
        maxargs = 6
×
1388
        op_argi = 4
×
1389
        v_argi = 5
×
1390
    elseif ff === Core.memoryrefmodify!
×
1391
        minargs = 6
×
1392
        maxargs = 6
×
1393
        op_argi = 3
×
1394
        v_argi = 4
×
1395
    elseif ff === atomic_pointermodify
×
1396
        minargs = 5
×
1397
        maxargs = 5
×
1398
        op_argi = 3
×
1399
        v_argi = 4
×
1400
    else
1401
        @assert false "unreachable"
×
1402
    end
1403

1404
    nargs = length(argtypes)
64✔
1405
    if !isempty(argtypes) && isvarargtype(argtypes[nargs])
64✔
1406
        nargs - 1 <= maxargs || return Future(CallMeta(Bottom, Any, EFFECTS_THROWS, NoCallInfo()))
×
1407
        nargs + 1 >= op_argi || return Future(CallMeta(Any, Any, Effects(), NoCallInfo()))
×
1408
    else
1409
        minargs <= nargs <= maxargs || return Future(CallMeta(Bottom, Any, EFFECTS_THROWS, NoCallInfo()))
64✔
1410
    end
1411
    𝕃ᵢ = typeinf_lattice(interp)
64✔
1412
    if ff === modifyfield!
64✔
1413
        o = unwrapva(argtypes[2])
64✔
1414
        f = unwrapva(argtypes[3])
64✔
1415
        RT = modifyfield!_tfunc(𝕃ᵢ, o, f, Any, Any, Symbol)
64✔
1416
        TF = getfield_tfunc(𝕃ᵢ, o, f)
128✔
1417
    elseif ff === Core.modifyglobal!
×
1418
        o = unwrapva(argtypes[2])
×
1419
        f = unwrapva(argtypes[3])
×
1420
        GT = abstract_eval_get_binding_type(interp, sv, o, f).rt
×
1421
        RT = isa(GT, Const) ? Pair{GT.val, GT.val} : Pair
×
1422
        TF = isa(GT, Const) ? GT.val : Any
×
1423
    elseif ff === Core.memoryrefmodify!
×
1424
        o = unwrapva(argtypes[2])
×
1425
        RT = memoryrefmodify!_tfunc(𝕃ᵢ, o, Any, Any, Symbol, Bool)
×
1426
        TF = memoryrefget_tfunc(𝕃ᵢ, o, Symbol, Bool)
×
1427
    elseif ff === atomic_pointermodify
×
1428
        o = unwrapva(argtypes[2])
×
1429
        RT = atomic_pointermodify_tfunc(𝕃ᵢ, o, Any, Any, Symbol)
×
1430
        TF = atomic_pointerref_tfunc(𝕃ᵢ, o, Symbol)
×
1431
    else
1432
        @assert false "unreachable"
×
1433
    end
1434
    info = NoCallInfo()
64✔
1435
    if nargs >= v_argi && RT !== Bottom
64✔
1436
        # we may be able to refine this to a PartialStruct by analyzing `op(o.f, v)::T`
1437
        # as well as compute the info for the method matches
1438
        op = unwrapva(argtypes[op_argi])
64✔
1439
        v = unwrapva(argtypes[v_argi])
64✔
1440
        callinfo = abstract_call(interp, ArgInfo(nothing, Any[op, TF, v]), StmtInfo(true, si.saw_latestworld), sv, #=max_methods=#1)
192✔
1441
        TF = Core.Box(TF)
64✔
1442
        RT = Core.Box(RT)
64✔
1443
        return Future{CallMeta}(callinfo, interp, sv) do callinfo, interp, sv
64✔
1444
            TF = TF.contents
64✔
1445
            RT = RT.contents
64✔
1446
            TF2 = tmeet(ipo_lattice(interp), callinfo.rt, widenconst(TF))
64✔
1447
            if TF2 === Bottom
64✔
1448
                RT = Bottom
×
1449
            elseif isconcretetype(RT) && has_nontrivial_extended_info(𝕃ᵢ, TF2) # isconcrete condition required to form a PartialStruct
117✔
1450
                RT = PartialStruct(fallback_lattice, RT, Union{Nothing,Bool}[false,false], Any[TF, TF2])
×
1451
            end
1452
            info = ModifyOpInfo(callinfo.info)
64✔
1453
            return CallMeta(RT, Any, Effects(), info)
64✔
1454
        end
1455
    end
1456
    return Future(CallMeta(RT, Any, Effects(), info))
×
1457
end
1458

1459
# we could use tuple_tfunc instead of widenconst, but `o` is mutable, so that is unlikely to be beneficial
1460

1461
add_tfunc(getfield, 2, 4, getfield_tfunc, 1)
1462
add_tfunc(setfield!, 3, 4, setfield!_tfunc, 3)
1463
add_tfunc(swapfield!, 3, 4, swapfield!_tfunc, 3)
1464
add_tfunc(modifyfield!, 4, 5, modifyfield!_tfunc, 3)
1465
add_tfunc(replacefield!, 4, 6, replacefield!_tfunc, 3)
1466
add_tfunc(setfieldonce!, 3, 5, setfieldonce!_tfunc, 3)
1467

1468
@nospecs function fieldtype_nothrow(𝕃::AbstractLattice, s0, name)
12,684✔
1469
    s0 === Bottom && return true # unreachable
12,684✔
1470
    ⊑ = partialorder(𝕃)
12,684✔
1471
    if s0 === Any || s0 === Type || DataType ⊑ s0 || UnionAll ⊑ s0
25,368✔
1472
        # We have no idea
1473
        return false
×
1474
    end
1475

1476
    if !isa(name, Const) || (!isa(name.val, Symbol) && !isa(name.val, Int))
25,342✔
1477
        # Due to bounds checking, we can't say anything unless we know what
1478
        # the name is.
1479
        return false
26✔
1480
    end
1481

1482
    su = unwrap_unionall(s0)
12,658✔
1483
    if isa(su, Union)
12,658✔
1484
        return fieldtype_nothrow(𝕃, rewrap_unionall(su.a, s0), name) &&
×
1485
               fieldtype_nothrow(𝕃, rewrap_unionall(su.b, s0), name)
1486
    end
1487

1488
    s, exact = instanceof_tfunc(s0, false)
12,658✔
1489
    s === Bottom && return false # always
12,658✔
1490
    return _fieldtype_nothrow(s, exact, name)
12,658✔
1491
end
1492

1493
function _fieldtype_nothrow(@nospecialize(s), exact::Bool, name::Const)
12,643✔
1494
    u = unwrap_unionall(s)
12,643✔
1495
    if isa(u, Union)
12,643✔
1496
        a = _fieldtype_nothrow(u.a, exact, name)
×
1497
        b = _fieldtype_nothrow(u.b, exact, name)
×
1498
        return exact ? (a || b) : (a && b)
×
1499
    end
1500
    u isa DataType || return false
12,643✔
1501
    isabstracttype(u) && return false
12,643✔
1502
    if u.name === _NAMEDTUPLE_NAME && !isconcretetype(u)
12,643✔
1503
        # TODO: better approximate inference
1504
        return false
×
1505
    end
1506
    fld = name.val
12,643✔
1507
    if isa(fld, Symbol)
12,643✔
1508
        fld = fieldindex(u, fld, false)
1,857✔
1509
    end
1510
    isa(fld, Int) || return false
12,643✔
1511
    ftypes = datatype_fieldtypes(u)
12,643✔
1512
    nf = length(ftypes)
12,643✔
1513
    fld >= 1 || return false
12,643✔
1514
    if u.name === Tuple.name && nf > 0 && isvarargtype(ftypes[nf])
12,643✔
1515
        if !exact && fld >= nf
×
1516
            # If we don't know the exact type, the length of the tuple will be determined
1517
            # at runtime and we can't say anything.
1518
            return false
×
1519
        end
1520
    elseif fld > nf
12,643✔
1521
        return false
×
1522
    end
1523
    return true
12,643✔
1524
end
1525

1526
@nospecs function fieldtype_tfunc(𝕃::AbstractLattice, s0, name, boundscheck)
12✔
1527
    return fieldtype_tfunc(𝕃, s0, name)
12✔
1528
end
1529
@nospecs function fieldtype_tfunc(𝕃::AbstractLattice, s0, name)
13✔
1530
    s0 = widenmustalias(s0)
26✔
1531
    if s0 === Bottom
13✔
1532
        return Bottom
×
1533
    end
1534
    if s0 === Any || s0 === Type || DataType ⊑ s0 || UnionAll ⊑ s0
26✔
1535
        # For a generic DataType, one of the fields could still be a TypeVar
1536
        # which is not a Type. Tuple{...} can also contain Symbols etc.
1537
        return Any
×
1538
    end
1539
    # fieldtype only accepts Types
1540
    if isa(s0, Const) && !(isa(s0.val, DataType) || isa(s0.val, UnionAll) || isa(s0.val, Union))
13✔
1541
        return Bottom
×
1542
    end
1543
    if (s0 isa Type && s0 == Type{Union{}}) || isa(s0, Conditional)
26✔
1544
        return Bottom
×
1545
    end
1546

1547
    su = unwrap_unionall(s0)
13✔
1548
    if isa(su, Union)
13✔
1549
        return tmerge(fieldtype_tfunc(𝕃, rewrap_unionall(su.a, s0), name),
×
1550
                      fieldtype_tfunc(𝕃, rewrap_unionall(su.b, s0), name))
1551
    end
1552

1553
    s, exact = instanceof_tfunc(s0, false)
13✔
1554
    s === Bottom && return Bottom
13✔
1555
    return _fieldtype_tfunc(𝕃, s, name, exact)
13✔
1556
end
1557

1558
@nospecs function _fieldtype_tfunc(𝕃::AbstractLattice, s, name, exact::Bool)
13✔
1559
    exact = exact && !has_free_typevars(s)
13✔
1560
    u = unwrap_unionall(s)
13✔
1561
    if isa(u, Union)
13✔
1562
        ta0 = _fieldtype_tfunc(𝕃, rewrap_unionall(u.a, s), name, exact)
×
1563
        tb0 = _fieldtype_tfunc(𝕃, rewrap_unionall(u.b, s), name, exact)
×
1564
        ta0 ⊑ tb0 && return tb0
×
1565
        tb0 ⊑ ta0 && return ta0
×
1566
        ta, exacta, _, istypea = instanceof_tfunc(ta0, false)
×
1567
        tb, exactb, _, istypeb = instanceof_tfunc(tb0, false)
×
1568
        if exact && exacta && exactb
×
1569
            return Const(Union{ta, tb})
×
1570
        end
1571
        if istypea && istypeb
×
1572
            return Type{<:Union{ta, tb}}
×
1573
        end
1574
        return Any
×
1575
    end
1576
    u isa DataType || return Any
13✔
1577
    if isabstracttype(u)
13✔
1578
        # Abstract types have no fields
1579
        exact && return Bottom
×
1580
        # Type{...} without free typevars has no subtypes, so it is actually
1581
        # exact, even if `exact` is false.
1582
        isType(u) && !has_free_typevars(u.parameters[1]) && return Bottom
×
1583
        return Any
×
1584
    end
1585
    if u.name === _NAMEDTUPLE_NAME && !isconcretetype(u)
13✔
1586
        # TODO: better approximate inference
1587
        return Union{Type, TypeVar}
×
1588
    end
1589
    ftypes = datatype_fieldtypes(u)
13✔
1590
    if isempty(ftypes)
13✔
1591
        return Bottom
×
1592
    end
1593

1594
    if !isa(name, Const)
13✔
1595
        name = widenconst(name)
13✔
1596
        if !(Int <: name || Symbol <: name)
26✔
1597
            return Bottom
×
1598
        end
1599
        t = Bottom
13✔
1600
        for i in 1:length(ftypes)
26✔
1601
            ft1 = unwrapva(ftypes[i])
111✔
1602
            exactft1 = exact || (!has_free_typevars(ft1) && u.name !== Tuple.name)
111✔
1603
            ft1 = rewrap_unionall(ft1, s)
111✔
1604
            if exactft1
111✔
1605
                if hasuniquerep(ft1)
222✔
1606
                    ft1 = Const(ft1) # ft unique via type cache
108✔
1607
                else
1608
                    ft1 = Type{ft1}
3✔
1609
                end
1610
            elseif ft1 isa Type || ft1 isa TypeVar
×
1611
                if ft1 === Any && u.name === Tuple.name
×
1612
                    # Tuple{:x} is possible in this case
1613
                    ft1 = Any
×
1614
                else
1615
                    ft1 = Type{ft} where ft<:ft1
×
1616
                end
1617
            else
1618
                ft1 = Const(ft1)
×
1619
            end
1620
            t = tmerge(t, ft1)
222✔
1621
            t === Any && break
111✔
1622
        end
111✔
1623
        return t
13✔
1624
    end
1625

1626
    fld = name.val
×
1627
    if isa(fld, Symbol)
×
1628
        fld = fieldindex(u, fld, false)
×
1629
    end
1630
    if !isa(fld, Int)
×
1631
        return Bottom
×
1632
    end
1633
    nf = length(ftypes)
×
1634
    if u.name === Tuple.name && fld >= nf && isvarargtype(ftypes[nf])
×
1635
        ft = unwrapva(ftypes[nf])
×
1636
    elseif fld < 1 || fld > nf
×
1637
        return Bottom
×
1638
    else
1639
        ft = ftypes[fld]
×
1640
    end
1641
    if !isa(ft, Type) && !isa(ft, TypeVar)
×
1642
        return Const(ft)
×
1643
    end
1644

1645
    exactft = exact || (!has_free_typevars(ft) && u.name !== Tuple.name)
×
1646
    ft = rewrap_unionall(ft, s)
×
1647
    if exactft
×
1648
        if hasuniquerep(ft)
×
1649
            return Const(ft) # ft unique via type cache
×
1650
        end
1651
        return Type{ft}
×
1652
    end
1653
    if u.name === Tuple.name && ft === Any
×
1654
        # Tuple{:x} is possible
1655
        return Any
×
1656
    end
1657
    return Type{<:ft}
×
1658
end
1659
add_tfunc(fieldtype, 2, 3, fieldtype_tfunc, 0)
1660

1661
# Like `valid_tparam`, but in the type domain.
1662
valid_tparam_type(T::DataType) = valid_typeof_tparam(T)
27✔
1663
valid_tparam_type(U::Union) = valid_tparam_type(U.a) && valid_tparam_type(U.b)
×
1664
valid_tparam_type(U::UnionAll) = valid_tparam_type(unwrap_unionall(U))
×
1665

1666
function apply_type_nothrow(𝕃::AbstractLattice, argtypes::Vector{Any}, @nospecialize(rt))
30,534✔
1667
    rt === Type && return false
30,534✔
1668
    length(argtypes) >= 1 || return false
30,534✔
1669
    headtypetype = argtypes[1]
30,534✔
1670
    if isa(headtypetype, Const)
30,534✔
1671
        headtype = headtypetype.val
30,534✔
1672
    elseif isconstType(headtypetype)
×
1673
        headtype = headtypetype.parameters[1]
×
1674
    else
1675
        return false
×
1676
    end
1677
    # We know the apply_type is well formed. Otherwise our rt would have been
1678
    # Bottom (or Type).
1679
    (headtype === Union) && return true
30,534✔
1680
    isa(rt, Const) && return true
26,784✔
1681
    u = headtype
163✔
1682
    # TODO: implement optimization for isvarargtype(u) and istuple occurrences (which are valid but are not UnionAll)
1683
    for i = 2:length(argtypes)
290✔
1684
        isa(u, UnionAll) || return false
181✔
1685
        ai = widenconditional(argtypes[i])
184✔
1686
        if ⊑(𝕃, ai, TypeVar) || ai === DataType
347✔
1687
            # We don't know anything about the bounds of this typevar, but as
1688
            # long as the UnionAll is not constrained, that's ok.
1689
            if !(u.var.lb === Union{} && u.var.ub === Any)
15✔
1690
                return false
×
1691
            end
1692
        elseif (isa(ai, Const) && isa(ai.val, Type)) || isconstType(ai)
332✔
1693
            ai = isa(ai, Const) ? ai.val : (ai::DataType).parameters[1]
×
1694
            if has_free_typevars(u.var.lb) || has_free_typevars(u.var.ub)
×
1695
                return false
×
1696
            end
1697
            if !(u.var.lb <: ai <: u.var.ub)
×
1698
                return false
×
1699
            end
1700
        else
1701
            T, exact, _, istype = instanceof_tfunc(ai, false)
166✔
1702
            if T === Bottom
166✔
1703
                if !(u.var.lb === Union{} && u.var.ub === Any)
27✔
1704
                    return false
×
1705
                end
1706
                if !valid_tparam_type(widenconst(ai))
54✔
1707
                    return false
×
1708
                end
1709
            else
1710
                istype || return false
198✔
1711
                if isa(u.var.ub, TypeVar) || !(T <: u.var.ub)
160✔
1712
                    return false
×
1713
                end
1714
                if exact ? !(u.var.lb <: T) : !(u.var.lb === Bottom)
160✔
1715
                    return false
×
1716
                end
1717
            end
1718
        end
1719
        u = u.body
122✔
1720
    end
140✔
1721
    return true
104✔
1722
end
1723

1724
const _tvarnames = Symbol[:_A, :_B, :_C, :_D, :_E, :_F, :_G, :_H, :_I, :_J, :_K, :_L, :_M,
1725
                          :_N, :_O, :_P, :_Q, :_R, :_S, :_T, :_U, :_V, :_W, :_X, :_Y, :_Z]
1726

1727
function apply_type_tfunc(𝕃::AbstractLattice, argtypes::Vector{Any};
3,708✔
1728
                          max_union_splitting::Int=InferenceParams().max_union_splitting)
1729
    if isempty(argtypes)
182✔
1730
        return Bottom
×
1731
    end
1732
    headtypetype = argtypes[1]
182✔
1733
    headtypetype = widenslotwrapper(headtypetype)
182✔
1734
    if isa(headtypetype, Const)
182✔
1735
        headtype = headtypetype.val
182✔
1736
    elseif isconstType(headtypetype)
×
1737
        headtype = headtypetype.parameters[1]
×
1738
    else
1739
        return Any
×
1740
    end
1741
    largs = length(argtypes)
182✔
1742
    if largs > 1 && isvarargtype(argtypes[end])
182✔
1743
        return isvarargtype(headtype) ? TypeofVararg : Type
×
1744
    end
1745
    if headtype === Union
182✔
1746
        largs == 1 && return Const(Bottom)
×
1747
        hasnonType = false
×
1748
        for i = 2:largs
×
1749
            ai = argtypes[i]
×
1750
            if isa(ai, Const)
×
1751
                if !isa(ai.val, Type)
×
1752
                    if isa(ai.val, TypeVar)
×
1753
                        hasnonType = true
×
1754
                    else
1755
                        return Bottom
×
1756
                    end
1757
                end
1758
            else
1759
                if !isType(ai)
×
1760
                    if !isa(ai, Type) || hasintersect(ai, Type) || hasintersect(ai, TypeVar)
×
1761
                        hasnonType = true
×
1762
                    else
1763
                        return Bottom
×
1764
                    end
1765
                end
1766
            end
1767
        end
×
1768
        if largs == 2 # Union{T} --> T
×
1769
            return tmeet(widenconst(argtypes[2]), Union{Type,TypeVar})
×
1770
        end
1771
        hasnonType && return Type
×
1772
        ty = Union{}
×
1773
        allconst = true
×
1774
        for i = 2:largs
×
1775
            ai = argtypes[i]
×
1776
            if isType(ai)
×
1777
                aty = ai.parameters[1]
×
1778
                allconst &= hasuniquerep(aty)
×
1779
            else
1780
                aty = (ai::Const).val
×
1781
            end
1782
            ty = Union{ty, aty}
×
1783
        end
×
1784
        return allconst ? Const(ty) : Type{ty}
×
1785
    end
1786
    if 1 < unionsplitcost(𝕃, argtypes) ≤ max_union_splitting
182✔
1787
        rt = Bottom
×
1788
        for split_argtypes = switchtupleunion(𝕃, argtypes)
×
1789
            this_rt = widenconst(_apply_type_tfunc(𝕃, headtype, split_argtypes))
×
1790
            rt = Union{rt, this_rt}
×
1791
        end
×
1792
        return rt
×
1793
    end
1794
    return _apply_type_tfunc(𝕃, headtype, argtypes)
182✔
1795
end
1796
@nospecs function _apply_type_tfunc(𝕃::AbstractLattice, headtype, argtypes::Vector{Any})
182✔
1797
    largs = length(argtypes)
182✔
1798
    istuple = headtype === Tuple
182✔
1799
    if !istuple && !isa(headtype, UnionAll) && !isvarargtype(headtype)
182✔
1800
        return Union{}
×
1801
    end
1802
    uw = unwrap_unionall(headtype)
349✔
1803
    uncertain = false
182✔
1804
    canconst = true
182✔
1805
    tparams = Any[]
182✔
1806
    outervars = TypeVar[]
182✔
1807

1808
    # first push the tailing vars from headtype into outervars
1809
    outer_start, ua = 0, headtype
182✔
1810
    while isa(ua, UnionAll)
448✔
1811
        if (outer_start += 1) > largs - 1
266✔
1812
            push!(outervars, ua.var)
×
1813
        end
1814
        ua = ua.body
266✔
1815
    end
266✔
1816
    if largs - 1 > outer_start && isa(headtype, UnionAll) # e.g. !isvarargtype(ua) && !istuple
182✔
1817
        return Bottom # too many arguments
×
1818
    end
1819
    outer_start = outer_start - largs + 2
182✔
1820

1821
    varnamectr = 1
182✔
1822
    ua = headtype
182✔
1823
    for i = 2:largs
328✔
1824
        ai = widenslotwrapper(argtypes[i])
314✔
1825
        if isType(ai)
311✔
1826
            aip1 = ai.parameters[1]
75✔
1827
            canconst &= !has_free_typevars(aip1)
75✔
1828
            push!(tparams, aip1)
75✔
1829
        elseif isa(ai, Const) && (isa(ai.val, Type) || isa(ai.val, TypeVar) ||
248✔
1830
                                  valid_tparam(ai.val) || (istuple && isvarargtype(ai.val)))
1831
            push!(tparams, ai.val)
120✔
1832
        elseif isa(ai, PartialTypeVar)
116✔
1833
            canconst = false
15✔
1834
            push!(tparams, ai.tv)
15✔
1835
        else
1836
            uncertain = true
101✔
1837
            unw = unwrap_unionall(ai)
101✔
1838
            isT = isType(unw)
101✔
1839
            # compute our desired upper bound value
1840
            if isT
101✔
1841
                ub = rewrap_unionall(unw.parameters[1], ai)
43✔
1842
            else
1843
                ub = Any
58✔
1844
            end
1845
            if !istuple && unionall_depth(ai) > 3
101✔
1846
                # Heuristic: if we are adding more than N unknown parameters here to the
1847
                # outer type, use the wrapper type, instead of letting it nest more
1848
                # complexity here. This is not monotonic, but seems to work out pretty well.
1849
                if isT
×
1850
                    ub = unwrap_unionall(unw.parameters[1])
×
1851
                    if ub isa DataType
×
1852
                        ub = ub.name.wrapper
×
1853
                        unw = Type{unwrap_unionall(ub)}
×
1854
                        ai = rewrap_unionall(unw, ub)
×
1855
                    else
1856
                        isT = false
×
1857
                        ai = unw = ub = Any
×
1858
                    end
1859
                else
1860
                    isT = false
×
1861
                    ai = unw = ub = Any
×
1862
                end
1863
            elseif !isT
101✔
1864
                # if we didn't have isType to compute ub directly, try to use instanceof_tfunc to refine this guess
1865
                ai_w = widenconst(ai)
58✔
1866
                ub = ai_w isa Type && ai_w <: Type ? instanceof_tfunc(ai, false)[1] : Any
58✔
1867
            end
1868
            if istuple
101✔
1869
                # in the last parameter of a Tuple type, if the upper bound is Any
1870
                # then this could be a Vararg type.
1871
                if i == largs && ub === Any
×
1872
                    ub = Vararg
×
1873
                end
1874
                push!(tparams, ub)
×
1875
            elseif isT
101✔
1876
                tai = ai
43✔
1877
                while isa(tai, UnionAll)
86✔
1878
                    # make sure vars introduced here are unique
1879
                    if contains_is(outervars, tai.var)
43✔
1880
                        ai = rename_unionall(ai)
×
1881
                        unw = unwrap_unionall(ai)::DataType
×
1882
                        # ub = rewrap_unionall(unw, ai)
1883
                        break
×
1884
                    end
1885
                    tai = tai.body
43✔
1886
                end
43✔
1887
                push!(tparams, unw.parameters[1])
43✔
1888
                while isa(ai, UnionAll)
86✔
1889
                    push!(outervars, ai.var)
43✔
1890
                    ai = ai.body
43✔
1891
                end
43✔
1892
            else
1893
                # Is this the second parameter to a NamedTuple?
1894
                if isa(uw, DataType) && uw.name === _NAMEDTUPLE_NAME && isa(ua, UnionAll) && uw.parameters[2] === ua.var
58✔
1895
                    # If the names are known, keep the upper bound, but otherwise widen to Tuple.
1896
                    # This is a widening heuristic to avoid keeping type information
1897
                    # that's unlikely to be useful.
1898
                    if !(uw.parameters[1] isa Tuple || (i == 3 && tparams[1] isa Tuple))
×
1899
                        ub = Any
×
1900
                    end
1901
                else
1902
                    ub = Any
58✔
1903
                end
1904
                tvname = varnamectr <= length(_tvarnames) ? _tvarnames[varnamectr] : :_Z
58✔
1905
                varnamectr += 1
58✔
1906
                v = TypeVar(tvname, ub)
58✔
1907
                push!(tparams, v)
58✔
1908
                push!(outervars, v)
58✔
1909
            end
1910
        end
1911
        if ua isa UnionAll
311✔
1912
            ua = ua.body
266✔
1913
            #otherwise, sometimes ua isa Vararg (Core.TypeofVararg) or Tuple (DataType)
1914
        end
1915
    end
440✔
1916
    local appl
1917
    try
182✔
1918
        appl = apply_type(headtype, tparams...)
182✔
1919
    catch ex
1920
        ex isa InterruptException && rethrow()
×
1921
        # type instantiation might fail if one of the type parameters doesn't
1922
        # match, which could happen only if a type estimate is too coarse
1923
        # and might guess a concrete value while the actual type for it is Bottom
1924
        if !uncertain
×
1925
            return Union{}
×
1926
        end
1927
        canconst = false
×
1928
        uncertain = true
×
1929
        empty!(outervars)
×
1930
        outer_start = 1
×
1931
        # FIXME: if these vars are substituted with TypeVar here, the result
1932
        # might be wider than the input, so should we use the `.name.wrapper`
1933
        # object here instead, to replace all of these outervars with
1934
        # unconstrained ones? Note that this code is nearly unreachable though,
1935
        # and possibly should simply return Union{} here also, since
1936
        # `apply_type` is already quite conservative about detecting and
1937
        # throwing errors.
1938
        appl = headtype
×
1939
        if isa(appl, UnionAll)
×
1940
            for _ = 2:largs
×
1941
                appl = appl::UnionAll
×
1942
                push!(outervars, appl.var)
×
1943
                appl = appl.body
×
1944
            end
×
1945
        end
1946
    end
1947
    !uncertain && canconst && return Const(appl)
182✔
1948
    if isvarargtype(appl)
107✔
1949
        return TypeofVararg
×
1950
    end
1951
    if istuple
107✔
1952
        return Type{<:appl}
×
1953
    end
1954
    ans = Type{appl}
107✔
1955
    for i = length(outervars):-1:outer_start
172✔
1956
        ans = UnionAll(outervars[i], ans)
101✔
1957
    end
110✔
1958
    return ans
107✔
1959
end
1960
@nospecs apply_type_tfunc(𝕃::AbstractLattice, headtypetype, args...) =
27✔
1961
    apply_type_tfunc(𝕃, Any[i == 0 ? headtypetype : args[i] for i in 0:length(args)])
1962
add_tfunc(apply_type, 1, INT_INF, apply_type_tfunc, 10)
1963

1964
# convert the dispatch tuple type argtype to the real (concrete) type of
1965
# the tuple of those values
1966
function tuple_tfunc(𝕃::AbstractLattice, argtypes::Vector{Any})
9,418✔
1967
    isempty(argtypes) && return Const(())
9,418✔
1968
    argtypes = anymap(widenslotwrapper, argtypes)
15,845✔
1969
    if isvarargtype(argtypes[end]) && unwrapva(argtypes[end]) === Union{}
9,300✔
1970
        # Drop the Vararg in Tuple{...,Vararg{Union{}}} since it must be length 0.
1971
        # If there is a Vararg num also, it must be a TypeVar, and it must be
1972
        # zero, but that generally shouldn't show up here, since it implies a
1973
        # UnionAll context is missing around this.
1974
        pop!(argtypes)
×
1975
    end
1976
    if is_all_const_arg(argtypes, 1) # repeated from builtin_tfunction for the benefit of callers that use this tfunc directly
9,300✔
1977
        return Const(tuple(collect_const_args(argtypes, 1)...))
411✔
1978
    end
1979
    params = Vector{Any}(undef, length(argtypes))
8,889✔
1980
    anyinfo = false
8,889✔
1981
    for i in 1:length(argtypes)
17,769✔
1982
        x = argtypes[i]
14,222✔
1983
        if has_nontrivial_extended_info(𝕃, x)
28,405✔
1984
            anyinfo = true
3,411✔
1985
        else
1986
            if !isvarargtype(x)
10,811✔
1987
                x = widenconst(x)
10,811✔
1988
            end
1989
            argtypes[i] = x
10,811✔
1990
        end
1991
        if isa(x, Const)
14,222✔
1992
            params[i] = typeof(x.val)
3,372✔
1993
        else
1994
            x = isvarargtype(x) ? x : widenconst(x)
21,700✔
1995
            # since there don't exist any values whose runtime type are `Tuple{Type{...}}`,
1996
            # here we should turn such `Type{...}`-parameters to valid parameters, e.g.
1997
            # (::Type{Int},) -> Tuple{DataType} (or PartialStruct for more accuracy)
1998
            # (::Union{Type{Int32},Type{Int64}}) -> Tuple{Type}
1999
            if isType(x)
10,850✔
2000
                anyinfo = true
78✔
2001
                xparam = x.parameters[1]
78✔
2002
                if hasuniquerep(xparam) || xparam === Bottom
156✔
2003
                    params[i] = typeof(xparam)
78✔
2004
                else
2005
                    params[i] = Type
×
2006
                end
2007
            elseif iskindtype(x)
21,542✔
2008
                params[i] = x
2✔
2009
            elseif !isvarargtype(x) && hasintersect(x, Type)
10,770✔
2010
                params[i] = Union{x, Type}
198✔
2011
            elseif x === Union{}
10,572✔
2012
                return Bottom # argtypes is malformed, but try not to crash
×
2013
            else
2014
                params[i] = x
10,572✔
2015
            end
2016
        end
2017
    end
19,555✔
2018
    typ = Tuple{params...}
8,889✔
2019
    # replace a singleton type with its equivalent Const object
2020
    issingletontype(typ) && return Const(typ.instance)
8,889✔
2021
    return anyinfo ? PartialStruct(𝕃, typ, partialstruct_init_undefs(typ, argtypes)::Vector, argtypes) : typ
8,889✔
2022
end
2023

2024
@nospecs function memorynew_tfunc(𝕃::AbstractLattice, memtype, memlen)
615✔
2025
    hasintersect(widenconst(memlen), Int) || return Bottom
615✔
2026
    memt = tmeet(𝕃, instanceof_tfunc(memtype, true)[1], GenericMemory)
615✔
2027
    memt == Union{} && return memt
615✔
2028
    # PartialStruct so that loads of Const `length` get inferred
2029
    return PartialStruct(𝕃, memt, Union{Nothing,Bool}[false,false], Any[memlen, Ptr{Nothing}])
615✔
2030
end
2031
add_tfunc(Core.memorynew, 2, 2, memorynew_tfunc, 10)
2032

2033
@nospecs function memoryrefget_tfunc(𝕃::AbstractLattice, mem, order, boundscheck)
115✔
2034
    memoryref_builtin_common_errorcheck(mem, order, boundscheck) || return Bottom
1,094✔
2035
    return memoryref_elemtype(mem)
1,094✔
2036
end
2037
@nospecs function memoryrefset!_tfunc(𝕃::AbstractLattice, mem, item, order, boundscheck)
229✔
2038
    hasintersect(widenconst(item), memoryrefget_tfunc(𝕃, mem, order, boundscheck)) || return Bottom
229✔
2039
    return item
229✔
2040
end
2041
@nospecs function memoryrefswap!_tfunc(𝕃::AbstractLattice, mem, v, order, boundscheck)
750✔
2042
    memoryrefset!_tfunc(𝕃, mem, v, order, boundscheck) === Bottom && return Bottom
750✔
2043
    return memoryrefget_tfunc(𝕃, mem, order, boundscheck)
750✔
2044
end
2045
@nospecs function memoryrefmodify!_tfunc(𝕃::AbstractLattice, mem, op, v, order, boundscheck)
×
2046
    memoryrefget_tfunc(𝕃, mem, order, boundscheck) === Bottom && return Bottom
×
2047
    T = _memoryref_elemtype(mem)
×
2048
    T === Bottom && return Bottom
×
2049
    PT = Const(Pair)
×
2050
    return instanceof_tfunc(apply_type_tfunc(𝕃, Any[PT, T, T]), true)[1]
×
2051
end
2052
@nospecs function memoryrefreplace!_tfunc(𝕃::AbstractLattice, mem, x, v, success_order, failure_order, boundscheck)
1,680✔
2053
    memoryrefset!_tfunc(𝕃, mem, v, success_order, boundscheck) === Bottom && return Bottom
1,680✔
2054
    hasintersect(widenconst(failure_order), Symbol) || return Bottom
1,668✔
2055
    T = _memoryref_elemtype(mem)
1,668✔
2056
    T === Bottom && return Bottom
1,668✔
2057
    PT = Const(ccall(:jl_apply_cmpswap_type, Any, (Any,), T) where T)
1,668✔
2058
    return instanceof_tfunc(apply_type_tfunc(𝕃, Any[PT, T]), true)[1]
1,668✔
2059
end
2060
@nospecs function memoryrefsetonce!_tfunc(𝕃::AbstractLattice, mem, v, success_order, failure_order, boundscheck)
846✔
2061
    memoryrefset!_tfunc(𝕃, mem, v, success_order, boundscheck) === Bottom && return Bottom
846✔
2062
    hasintersect(widenconst(failure_order), Symbol) || return Bottom
846✔
2063
    return Bool
846✔
2064
end
2065

2066
add_tfunc(Core.memoryrefget, 3, 3, memoryrefget_tfunc, 20)
2067
add_tfunc(Core.memoryrefset!, 4, 4, memoryrefset!_tfunc, 20)
2068
add_tfunc(Core.memoryrefswap!, 4, 4, memoryrefswap!_tfunc, 20)
2069
add_tfunc(Core.memoryrefmodify!, 5, 5, memoryrefmodify!_tfunc, 20)
2070
add_tfunc(Core.memoryrefreplace!, 6, 6, memoryrefreplace!_tfunc, 20)
2071
add_tfunc(Core.memoryrefsetonce!, 5, 5, memoryrefsetonce!_tfunc, 20)
2072

2073
@nospecs function memoryref_isassigned_tfunc(𝕃::AbstractLattice, mem, order, boundscheck)
×
2074
    return _memoryref_isassigned_tfunc(𝕃, mem, order, boundscheck)
×
2075
end
2076
@nospecs function _memoryref_isassigned_tfunc(𝕃::AbstractLattice, mem, order, boundscheck)
×
2077
    memoryref_builtin_common_errorcheck(mem, order, boundscheck) || return Bottom
×
2078
    return Bool
×
2079
end
2080
add_tfunc(memoryref_isassigned, 3, 3, memoryref_isassigned_tfunc, 20)
2081

2082
@nospecs function memoryref_tfunc(𝕃::AbstractLattice, mem)
1,065✔
2083
    a = widenconst(unwrapva(mem))
1,065✔
2084
    if !has_free_typevars(a)
1,065✔
2085
        unw = unwrap_unionall(a)
1,065✔
2086
        if isa(unw, DataType) && unw.name === GenericMemory.body.body.body.name
1,065✔
2087
            A = unw.parameters[1]
1,065✔
2088
            T = unw.parameters[2]
1,065✔
2089
            AS = unw.parameters[3]
1,065✔
2090
            T isa Type || T isa TypeVar || return Bottom
1,065✔
2091
            return rewrap_unionall(GenericMemoryRef{A, T, AS}, a)
1,065✔
2092
        end
2093
    end
2094
    return GenericMemoryRef
×
2095
end
2096
@nospecs function memoryref_tfunc(𝕃::AbstractLattice, ref, idx)
18✔
2097
    if isvarargtype(idx)
18✔
2098
        idx = unwrapva(idx)
6✔
2099
    end
2100
    return memoryref_tfunc(𝕃, ref, idx, Const(true))
18✔
2101
end
2102
@nospecs function memoryref_tfunc(𝕃::AbstractLattice, ref, idx, boundscheck)
573✔
2103
    memoryref_builtin_common_errorcheck(ref, Const(:not_atomic), boundscheck) || return Bottom
573✔
2104
    hasintersect(widenconst(idx), Int) || return Bottom
573✔
2105
    hasintersect(widenconst(ref), GenericMemory) && return memoryref_tfunc(𝕃, ref)
573✔
2106
    return ref
482✔
2107
end
2108
add_tfunc(memoryrefnew, 1, 3, memoryref_tfunc, 1)
2109

2110
@nospecs function memoryrefoffset_tfunc(𝕃::AbstractLattice, mem)
142✔
2111
    hasintersect(widenconst(mem), GenericMemoryRef) || return Bottom
142✔
2112
    return Int
142✔
2113
end
2114
add_tfunc(memoryrefoffset, 1, 1, memoryrefoffset_tfunc, 5)
2115

2116
@nospecs function memoryref_builtin_common_errorcheck(mem, order, boundscheck)
917✔
2117
    hasintersect(widenconst(mem), Union{GenericMemory, GenericMemoryRef}) || return false
917✔
2118
    hasintersect(widenconst(order), Symbol) || return false
917✔
2119
    hasintersect(widenconst(unwrapva(boundscheck)), Bool) || return false
917✔
2120
    return true
917✔
2121
end
2122

2123
@nospecs function memoryref_elemtype(mem)
419✔
2124
    m = widenconst(mem)
419✔
2125
    if !has_free_typevars(m) && m <: GenericMemoryRef
419✔
2126
        m0 = m
419✔
2127
        if isa(m, UnionAll)
419✔
2128
            m = unwrap_unionall(m0)
×
2129
        end
2130
        if isa(m, DataType)
419✔
2131
            T = m.parameters[2]
419✔
2132
            valid_as_lattice(T, true) || return Bottom
419✔
2133
            return rewrap_unionall(T, m0)
419✔
2134
        end
2135
    end
2136
    return Any
×
2137
end
2138

2139
@nospecs function _memoryref_elemtype(mem)
×
2140
    m = widenconst(mem)
×
2141
    if !has_free_typevars(m) && m <: GenericMemoryRef
×
2142
        m0 = m
×
2143
        if isa(m, UnionAll)
×
2144
            m = unwrap_unionall(m0)
×
2145
        end
2146
        if isa(m, DataType)
×
2147
            T = m.parameters[2]
×
2148
            valid_as_lattice(T, true) || return Bottom
×
2149
            has_free_typevars(T) || return Const(T)
×
2150
            return rewrap_unionall(Type{T}, m0)
×
2151
        end
2152
    end
2153
    return Type
×
2154
end
2155

2156
@nospecs function opaque_closure_tfunc(𝕃::AbstractLattice, arg, lb, ub, source, env::Vector{Any}, mi::MethodInstance)
×
2157
    argt, argt_exact = instanceof_tfunc(arg)
×
2158
    lbt, lb_exact = instanceof_tfunc(lb)
×
2159
    if !lb_exact
×
2160
        lbt = Union{}
×
2161
    end
2162

2163
    ubt, ub_exact = instanceof_tfunc(ub)
×
2164

2165
    t = (argt_exact ? Core.OpaqueClosure{argt, T} : Core.OpaqueClosure{<:argt, T}) where T
×
2166
    t = lbt == ubt ? t{ubt} : (t{T} where lbt <: T <: ubt)
×
2167

2168
    (isa(source, Const) && isa(source.val, Method)) || return t
×
2169

2170
    return PartialOpaque(t, tuple_tfunc(𝕃, env), mi, source.val)
×
2171
end
2172

2173
# whether getindex for the elements can potentially throw UndefRef
2174
@nospecs function array_type_undefable(arytype)
18✔
2175
    arytype = unwrap_unionall(arytype)
18✔
2176
    if isa(arytype, Union)
18✔
2177
        return array_type_undefable(arytype.a) || array_type_undefable(arytype.b)
×
2178
    elseif arytype isa DataType
18✔
2179
        elmtype = memoryref_elemtype(arytype)
18✔
2180
        # TODO: use arraytype layout instead to derive this
2181
        return !((elmtype isa DataType && isbitstype(elmtype)) || (elmtype isa Union && isbitsunion(elmtype)))
18✔
2182
    end
2183
    return true
×
2184
end
2185

2186
@nospecs function memoryset_typecheck(𝕃::AbstractLattice, memtype, elemtype)
2187
    # Check that we can determine the element type
2188
    isa(memtype, DataType) || return false
30✔
2189
    elemtype_expected = memoryref_elemtype(memtype)
30✔
2190
    elemtype_expected === Union{} && return false
30✔
2191
    # Check that the element type is compatible with the element we're assigning
2192
    ⊑ = partialorder(𝕃)
30✔
2193
    elemtype ⊑ elemtype_expected || return false
30✔
2194
    return true
30✔
2195
end
2196

2197
function memoryref_builtin_common_nothrow(argtypes::Vector{Any})
1,302✔
2198
    if length(argtypes) == 1
1,302✔
2199
        memtype = widenconst(argtypes[1])
1,230✔
2200
        return memtype ⊑ GenericMemory
1,230✔
2201
    else
2202
        if length(argtypes) == 2
72✔
2203
            boundscheck = Const(true)
×
2204
        elseif length(argtypes) == 3
72✔
2205
            boundscheck = argtypes[3]
72✔
2206
        else
2207
            return false
×
2208
        end
2209
        memtype = widenconst(argtypes[1])
72✔
2210
        idx = widenconst(argtypes[2])
72✔
2211
        idx ⊑ Int || return false
72✔
2212
        boundscheck ⊑ Bool || return false
72✔
2213
        memtype ⊑ Union{GenericMemory, GenericMemoryRef} || return false
72✔
2214
        # If we have @inbounds (last argument is false), we're allowed to assume
2215
        # we don't throw bounds errors.
2216
        if isa(boundscheck, Const)
72✔
2217
            boundscheck.val::Bool || return true
96✔
2218
        end
2219
        # Else we can't really say anything here
2220
        # TODO: In the future we may be able to track the minimum length though inference.
2221
        return false
24✔
2222
    end
2223
end
2224

2225
function memoryrefop_builtin_common_nothrow(𝕃::AbstractLattice, argtypes::Vector{Any}, @nospecialize f)
48✔
2226
    ismemoryset = f === memoryrefset!
48✔
2227
    nargs = ismemoryset ? 4 : 3
48✔
2228
    length(argtypes) == nargs || return false
48✔
2229
    order = argtypes[2 + ismemoryset]
48✔
2230
    boundscheck = argtypes[3 + ismemoryset]
48✔
2231
    memtype = widenconst(argtypes[1])
48✔
2232
    memoryref_builtin_common_typecheck(𝕃, boundscheck, memtype, order) || return false
48✔
2233
    if ismemoryset
48✔
2234
        # Additionally check element type compatibility
2235
        memoryset_typecheck(𝕃, memtype, argtypes[2]) || return false
30✔
2236
    elseif f === memoryrefget
18✔
2237
        # If we could potentially throw undef ref errors, bail out now.
2238
        array_type_undefable(memtype) && return false
18✔
2239
    end
2240
    # If we have @inbounds (last argument is false), we're allowed to assume
2241
    # we don't throw bounds errors.
2242
    if isa(boundscheck, Const)
42✔
2243
        boundscheck.val::Bool || return true
84✔
2244
    end
2245
    # Else we can't really say anything here
2246
    # TODO: In the future we may be able to track the minimum length though inference.
2247
    return false
×
2248
end
2249

2250
@nospecs function memoryref_builtin_common_typecheck(𝕃::AbstractLattice, boundscheck, memtype, order)
×
2251
    ⊑ = partialorder(𝕃)
48✔
2252
    return boundscheck ⊑ Bool && memtype ⊑ GenericMemoryRef && order ⊑ Symbol
48✔
2253
end
2254

2255
function memorynew_nothrow(argtypes::Vector{Any})
2256
    if !(argtypes[1] isa Const && argtypes[2] isa Const)
1,230✔
2257
        return false
18✔
2258
    end
2259
    MemT = argtypes[1].val
1,212✔
2260
    if !(isconcretetype(MemT) && MemT <: GenericMemory)
1,212✔
2261
        return false
×
2262
    end
2263
    len = argtypes[2].val
1,212✔
2264
    if !(len isa Int && 0 <= len < typemax(Int))
1,212✔
2265
        return false
×
2266
    end
2267
    elsz = datatype_layoutsize(MemT)
1,212✔
2268
    overflows = checked_smul_int(len, elsz)[2]
1,212✔
2269
    return !overflows
1,212✔
2270
end
2271

2272
# Query whether the given builtin is guaranteed not to throw given the `argtypes`.
2273
# `argtypes` can be assumed not to contain varargs.
2274
function _builtin_nothrow(𝕃::AbstractLattice, @nospecialize(f::Builtin), argtypes::Vector{Any},
82,820✔
2275
                          @nospecialize(rt))
2276
    ⊑ = partialorder(𝕃)
82,820✔
2277
    na = length(argtypes)
82,820✔
2278
    if f === Core.memorynew
82,820✔
2279
        return memorynew_nothrow(argtypes)
1,230✔
2280
    elseif f === memoryrefnew
81,590✔
2281
        return memoryref_builtin_common_nothrow(argtypes)
1,302✔
2282
    elseif f === memoryrefoffset
80,288✔
2283
        length(argtypes) == 1 || return false
42✔
2284
        memtype = widenconst(argtypes[1])
42✔
2285
        return memtype ⊑ GenericMemoryRef
42✔
2286
    elseif f === memoryrefset!
80,246✔
2287
        return memoryrefop_builtin_common_nothrow(𝕃, argtypes, f)
30✔
2288
    elseif f === memoryrefget
80,216✔
2289
        return memoryrefop_builtin_common_nothrow(𝕃, argtypes, f)
18✔
2290
    elseif f === memoryref_isassigned
80,198✔
2291
        return memoryrefop_builtin_common_nothrow(𝕃, argtypes, f)
×
2292
    elseif f === Core._expr
80,198✔
2293
        length(argtypes) >= 1 || return false
688✔
2294
        return argtypes[1] ⊑ Symbol
688✔
2295
    elseif f === Core._typevar
79,510✔
2296
        na == 3 || return false
15✔
2297
        return typevar_nothrow(𝕃, argtypes[1], argtypes[2], argtypes[3])
15✔
2298
    elseif f === invoke
79,495✔
2299
        return false
×
2300
    elseif f === getfield
79,495✔
2301
        return getfield_nothrow(𝕃, argtypes)
×
2302
    elseif f === setfield!
79,495✔
2303
        if na == 3
1,331✔
2304
            return setfield!_nothrow(𝕃, argtypes[1], argtypes[2], argtypes[3])
1,331✔
2305
        elseif na == 4
×
2306
            return setfield!_nothrow(𝕃, argtypes[1], argtypes[2], argtypes[3], argtypes[4])
×
2307
        end
2308
        return false
×
2309
    elseif f === fieldtype
78,164✔
2310
        na == 2 || return false
12,684✔
2311
        return fieldtype_nothrow(𝕃, argtypes[1], argtypes[2])
12,684✔
2312
    elseif f === apply_type
65,480✔
2313
        return apply_type_nothrow(𝕃, argtypes, rt)
30,534✔
2314
    elseif f === isa
34,946✔
2315
        na == 2 || return false
24,065✔
2316
        return isa_nothrow(𝕃, nothing, argtypes[2])
24,065✔
2317
    elseif f === (<:)
10,881✔
2318
        na == 2 || return false
690✔
2319
        return subtype_nothrow(𝕃, argtypes[1], argtypes[2])
690✔
2320
    elseif f === isdefined
10,191✔
2321
        return isdefined_nothrow(𝕃, argtypes)
×
2322
    elseif f === Core.sizeof
10,191✔
2323
        na == 1 || return false
88✔
2324
        return sizeof_nothrow(argtypes[1])
88✔
2325
    elseif f === Core.ifelse
10,103✔
2326
        na == 3 || return false
1,455✔
2327
        return ifelse_nothrow(𝕃, argtypes[1], nothing, nothing)
1,455✔
2328
    elseif f === typeassert
8,648✔
2329
        na == 2 || return false
8,648✔
2330
        return typeassert_nothrow(𝕃, argtypes[1], argtypes[2])
8,648✔
2331
    elseif f === Core.get_binding_type
×
2332
        na == 2 || return false
×
2333
        return get_binding_type_nothrow(𝕃, argtypes[1], argtypes[2])
×
2334
    elseif f === donotdelete
×
2335
        return true
×
2336
    elseif f === Core.finalizer
×
2337
        2 <= na <= 4 || return false
×
2338
        # Core.finalizer does no error checking - that's done in Base.finalizer
2339
        return true
×
2340
    elseif f === Core.compilerbarrier
×
2341
        na == 2 || return false
×
2342
        return compilerbarrier_nothrow(argtypes[1], nothing)
×
2343
    elseif f === Core._svec_len
×
2344
        na == 1 || return false
×
2345
        return _svec_len_nothrow(𝕃, argtypes[1])
×
2346
    elseif f === Core._svec_ref
×
2347
        na == 2 || return false
×
2348
        return _svec_ref_tfunc(𝕃, argtypes[1], argtypes[2]) isa Const
×
2349
    end
2350
    return false
×
2351
end
2352

2353
# known to be always effect-free (in particular also nothrow)
2354
const _PURE_BUILTINS = Any[
2355
    tuple,
2356
    svec,
2357
    ===,
2358
    typeof,
2359
    nfields,
2360
]
2361

2362
const _CONSISTENT_BUILTINS = Any[
2363
    tuple, # Tuple is immutable, thus tuples of egal arguments are egal
2364
    svec,  # SimpleVector is immutable, thus svecs of egal arguments are egal
2365
    ===,
2366
    typeof,
2367
    nfields,
2368
    fieldtype,
2369
    apply_type,
2370
    isa,
2371
    UnionAll,
2372
    Core.sizeof,
2373
    Core.ifelse,
2374
    (<:),
2375
    typeassert,
2376
    throw,
2377
    Core.throw_methoderror,
2378
    setfield!,
2379
    donotdelete,
2380
    memoryrefnew,
2381
    memoryrefoffset,
2382
    Core._svec_len,
2383
    Core._svec_ref,
2384
]
2385

2386
# known to be effect-free (but not necessarily nothrow)
2387
const _EFFECT_FREE_BUILTINS = [
2388
    fieldtype,
2389
    apply_type,
2390
    isa,
2391
    UnionAll,
2392
    getfield,
2393
    Core.memorynew,
2394
    memoryrefnew,
2395
    memoryrefoffset,
2396
    memoryrefget,
2397
    memoryref_isassigned,
2398
    isdefined,
2399
    Core.sizeof,
2400
    Core.ifelse,
2401
    Core._typevar,
2402
    (<:),
2403
    typeassert,
2404
    throw,
2405
    Core.throw_methoderror,
2406
    getglobal,
2407
    compilerbarrier,
2408
    Core._svec_len,
2409
    Core._svec_ref,
2410
]
2411

2412
const _INACCESSIBLEMEM_BUILTINS = Any[
2413
    (<:),
2414
    (===),
2415
    apply_type,
2416
    Core.ifelse,
2417
    Core.sizeof,
2418
    svec,
2419
    fieldtype,
2420
    isa,
2421
    nfields,
2422
    throw,
2423
    Core.throw_methoderror,
2424
    tuple,
2425
    typeassert,
2426
    typeof,
2427
    compilerbarrier,
2428
    Core._typevar,
2429
    donotdelete,
2430
    Core.memorynew,
2431
]
2432

2433
const _ARGMEM_BUILTINS = Any[
2434
    memoryrefnew,
2435
    memoryrefoffset,
2436
    memoryrefget,
2437
    memoryref_isassigned,
2438
    memoryrefset!,
2439
    modifyfield!,
2440
    replacefield!,
2441
    setfield!,
2442
    swapfield!,
2443
    Core._svec_len,
2444
    Core._svec_ref,
2445
]
2446

2447
const _INCONSISTENT_INTRINSICS = Any[
2448
    # all is_pure_intrinsic_infer plus
2449
    # ... all the unsound fastmath functions which should have been in is_pure_intrinsic_infer
2450
    # join(string.("Intrinsics.", sort(filter(endswith("_fast")∘string, names(Core.Intrinsics)))), ",\n")
2451
    Intrinsics.add_float_fast,
2452
    Intrinsics.div_float_fast,
2453
    Intrinsics.eq_float_fast,
2454
    Intrinsics.le_float_fast,
2455
    Intrinsics.lt_float_fast,
2456
    Intrinsics.mul_float_fast,
2457
    Intrinsics.ne_float_fast,
2458
    Intrinsics.neg_float_fast,
2459
    Intrinsics.sqrt_llvm_fast,
2460
    Intrinsics.sub_float_fast,
2461
    # TODO needs to revive #31193 to mark this as inconsistent to be accurate
2462
    # while preserving the currently optimizations for many math operations
2463
    # Intrinsics.muladd_float,    # this is not interprocedurally consistent
2464
]
2465

2466
# Intrinsics that require all arguments to be floats
2467
const _FLOAT_INTRINSICS = Any[
2468
    Intrinsics.neg_float,
2469
    Intrinsics.add_float,
2470
    Intrinsics.sub_float,
2471
    Intrinsics.mul_float,
2472
    Intrinsics.div_float,
2473
    Intrinsics.min_float,
2474
    Intrinsics.max_float,
2475
    Intrinsics.fma_float,
2476
    Intrinsics.muladd_float,
2477
    Intrinsics.neg_float_fast,
2478
    Intrinsics.add_float_fast,
2479
    Intrinsics.sub_float_fast,
2480
    Intrinsics.mul_float_fast,
2481
    Intrinsics.div_float_fast,
2482
    Intrinsics.min_float_fast,
2483
    Intrinsics.max_float_fast,
2484
    Intrinsics.eq_float,
2485
    Intrinsics.ne_float,
2486
    Intrinsics.lt_float,
2487
    Intrinsics.le_float,
2488
    Intrinsics.eq_float_fast,
2489
    Intrinsics.ne_float_fast,
2490
    Intrinsics.lt_float_fast,
2491
    Intrinsics.le_float_fast,
2492
    Intrinsics.fpiseq,
2493
    Intrinsics.abs_float,
2494
    Intrinsics.copysign_float,
2495
    Intrinsics.ceil_llvm,
2496
    Intrinsics.floor_llvm,
2497
    Intrinsics.trunc_llvm,
2498
    Intrinsics.rint_llvm,
2499
    Intrinsics.sqrt_llvm,
2500
    Intrinsics.sqrt_llvm_fast
2501
]
2502

2503
# Types compatible with fpext/fptrunc
2504
const CORE_FLOAT_TYPES = Union{Core.BFloat16, Float16, Float32, Float64}
2505

2506
function isdefined_effects(𝕃::AbstractLattice, argtypes::Vector{Any})
756✔
2507
    # consistent if the first arg is immutable
2508
    na = length(argtypes)
756✔
2509
    2 ≤ na ≤ 3 || return EFFECTS_THROWS
756✔
2510
    wobj, sym = argtypes
756✔
2511
    wobj = unwrapva(wobj)
756✔
2512
    sym = unwrapva(sym)
756✔
2513
    consistent = CONSISTENT_IF_INACCESSIBLEMEMONLY
756✔
2514
    if is_immutable_argtype(wobj)
756✔
2515
        consistent = ALWAYS_TRUE
753✔
2516
    elseif isdefined_tfunc(𝕃, wobj, sym) isa Const
3✔
2517
        # Some bindings/fields are not allowed to transition from defined to undefined or the reverse, so even
2518
        # if the object is not immutable, we can prove `:consistent`-cy of this:
2519
        consistent = ALWAYS_TRUE
3✔
2520
    end
2521
    nothrow = isdefined_nothrow(𝕃, argtypes)
1,512✔
2522
    if hasintersect(widenconst(wobj), Module)
756✔
2523
        inaccessiblememonly = ALWAYS_FALSE
×
2524
    elseif is_mutation_free_argtype(wobj)
756✔
2525
        inaccessiblememonly = ALWAYS_TRUE
750✔
2526
    else
2527
        inaccessiblememonly = INACCESSIBLEMEM_OR_ARGMEMONLY
6✔
2528
    end
2529
    return Effects(EFFECTS_TOTAL; consistent, nothrow, inaccessiblememonly)
756✔
2530
end
2531

2532
function getfield_effects(𝕃::AbstractLattice, argtypes::Vector{Any}, @nospecialize(rt))
75,707✔
2533
    length(argtypes) < 2 && return EFFECTS_THROWS
75,707✔
2534
    obj = argtypes[1]
75,707✔
2535
    if isvarargtype(obj)
75,707✔
2536
        return Effects(EFFECTS_TOTAL;
×
2537
            consistent=CONSISTENT_IF_INACCESSIBLEMEMONLY,
2538
            nothrow=false,
2539
            inaccessiblememonly=ALWAYS_FALSE,
2540
            noub=ALWAYS_FALSE)
2541
    end
2542
    # :consistent if the argtype is immutable
2543
    consistent = (is_immutable_argtype(obj) || is_mutation_free_argtype(obj)) ?
78,783✔
2544
        ALWAYS_TRUE : CONSISTENT_IF_INACCESSIBLEMEMONLY
2545
    noub = ALWAYS_TRUE
75,707✔
2546
    bcheck = getfield_boundscheck(argtypes)
75,707✔
2547
    nothrow = getfield_nothrow(𝕃, argtypes, bcheck)
75,707✔
2548
    if !nothrow
75,707✔
2549
        if bcheck !== :on
395✔
2550
            # If we cannot independently prove inboundsness, taint `:noub`.
2551
            # The inbounds-ness assertion requires dynamic reachability,
2552
            # while `:noub` needs to be true for all input values.
2553
            # However, as a special exception, we do allow literal `:boundscheck`.
2554
            # `:noub` will be tainted in any caller using `@inbounds`
2555
            # based on the `:noinbounds` effect.
2556
            # N.B. We do not taint for `--check-bounds=no` here.
2557
            # That is handled in concrete evaluation.
2558
            noub = ALWAYS_FALSE
33✔
2559
        end
2560
    end
2561
    if hasintersect(widenconst(obj), Module)
75,707✔
2562
        # Modeled more precisely in abstract_eval_getglobal
2563
        inaccessiblememonly = ALWAYS_FALSE
6✔
2564
    elseif is_mutation_free_argtype(obj)
75,701✔
2565
        inaccessiblememonly = ALWAYS_TRUE
62,659✔
2566
    else
2567
        inaccessiblememonly = INACCESSIBLEMEM_OR_ARGMEMONLY
13,042✔
2568
    end
2569
    return Effects(EFFECTS_TOTAL; consistent, nothrow, inaccessiblememonly, noub)
75,707✔
2570
end
2571

2572
# add a new builtin function to this list only after making sure that
2573
# `builtin_effects` is properly implemented for it
2574
const _EFFECTS_KNOWN_BUILTINS = Any[
2575
    <:,
2576
    ===,
2577
    # Core._abstracttype,
2578
    # _apply_iterate,
2579
    # Core._call_in_world_total,
2580
    # Core._compute_sparams,
2581
    # Core._defaultctors,
2582
    # Core._equiv_typedef,
2583
    Core._expr,
2584
    # Core._primitivetype,
2585
    # Core._setsuper!,
2586
    # Core._structtype,
2587
    Core._svec_len,
2588
    Core._svec_ref,
2589
    # Core._typebody!,
2590
    Core._typevar,
2591
    apply_type,
2592
    compilerbarrier,
2593
    Core.current_scope,
2594
    donotdelete,
2595
    Core.finalizer,
2596
    Core.get_binding_type,
2597
    Core.ifelse,
2598
    # Core.invoke_in_world,
2599
    # invokelatest,
2600
    Core.memorynew,
2601
    memoryref_isassigned,
2602
    memoryrefget,
2603
    # Core.memoryrefmodify!,
2604
    memoryrefnew,
2605
    memoryrefoffset,
2606
    # Core.memoryrefreplace!,
2607
    memoryrefset!,
2608
    # Core.memoryrefsetonce!,
2609
    # Core.memoryrefswap!,
2610
    Core.sizeof,
2611
    svec,
2612
    Core.throw_methoderror,
2613
    applicable,
2614
    fieldtype,
2615
    getfield,
2616
    getglobal,
2617
    # invoke,
2618
    isa,
2619
    isdefined,
2620
    # isdefinedglobal,
2621
    modifyfield!,
2622
    # modifyglobal!,
2623
    nfields,
2624
    replacefield!,
2625
    # replaceglobal!,
2626
    setfield!,
2627
    # setfieldonce!,
2628
    # setglobal!,
2629
    # setglobalonce!,
2630
    swapfield!,
2631
    # swapglobal!,
2632
    throw,
2633
    tuple,
2634
    typeassert,
2635
    typeof
2636
]
2637

2638
"""
2639
    builtin_effects(𝕃::AbstractLattice, f::Builtin, argtypes::Vector{Any}, rt)::Effects
2640

2641
Compute the effects of a builtin function call. `argtypes` should not include `f` itself.
2642
"""
2643
function builtin_effects(𝕃::AbstractLattice, @nospecialize(f::Builtin), argtypes::Vector{Any}, @nospecialize(rt))
228,645✔
2644
    if isa(f, IntrinsicFunction)
228,645✔
2645
        return intrinsic_effects(f, argtypes)
19,007✔
2646
    end
2647

2648
    if !(f in _EFFECTS_KNOWN_BUILTINS)
419,276✔
2649
        return Effects()
30✔
2650
    end
2651

2652
    if f === getfield
209,608✔
2653
        return getfield_effects(𝕃, argtypes, rt)
75,707✔
2654
    end
2655

2656
    # if this builtin call deterministically throws,
2657
    # don't bother to taint the other effects other than :nothrow:
2658
    # note this is safe only if we accounted for :noub already
2659
    rt === Bottom && return EFFECTS_THROWS
133,901✔
2660

2661
    if f === isdefined
133,581✔
2662
        return isdefined_effects(𝕃, argtypes)
756✔
2663
    elseif f === getglobal
132,825✔
2664
        2 ≤ length(argtypes) ≤ 3 || return EFFECTS_THROWS
×
2665
        # Modeled more precisely in abstract_eval_getglobal
2666
        return generic_getglobal_effects
×
2667
    elseif f === Core.get_binding_type
132,825✔
2668
        length(argtypes) == 2 || return EFFECTS_THROWS
×
2669
        # Modeled more precisely in abstract_eval_get_binding_type
2670
        return Effects(EFFECTS_TOTAL; nothrow=get_binding_type_nothrow(𝕃, argtypes[1], argtypes[2]))
×
2671
    elseif f === compilerbarrier
132,825✔
2672
        length(argtypes) == 2 || return Effects(EFFECTS_THROWS; consistent=ALWAYS_FALSE)
30✔
2673
        setting = argtypes[1]
30✔
2674
        return Effects(EFFECTS_TOTAL;
30✔
2675
            consistent = (isa(setting, Const) && setting.val === :conditional) ? ALWAYS_TRUE : ALWAYS_FALSE,
2676
            nothrow = compilerbarrier_nothrow(setting, nothing))
2677
    elseif f === Core.current_scope
132,795✔
2678
        nothrow = true
4,860✔
2679
        if length(argtypes) != 0
4,860✔
2680
            if length(argtypes) != 1 || !isvarargtype(argtypes[1])
×
2681
                return EFFECTS_THROWS
×
2682
            end
2683
            nothrow = false
×
2684
        end
2685
        return Effects(EFFECTS_TOTAL;
4,860✔
2686
            consistent = ALWAYS_FALSE,
2687
            notaskstate = false,
2688
            nothrow)
2689
    else
2690
        if contains_is(_CONSISTENT_BUILTINS, f)
793,989✔
2691
            consistent = ALWAYS_TRUE
125,954✔
2692
        elseif f === memoryrefget || f === memoryrefset! || f === memoryref_isassigned || f === Core._svec_len || f === Core._svec_ref
3,944✔
2693
            consistent = CONSISTENT_IF_INACCESSIBLEMEMONLY
48✔
2694
        elseif f === Core._typevar || f === Core.memorynew
3,851✔
2695
            consistent = CONSISTENT_IF_NOTRETURNED
1,245✔
2696
        else
2697
            consistent = ALWAYS_FALSE
688✔
2698
        end
2699
        if f === setfield! || f === memoryrefset!
254,539✔
2700
            effect_free = EFFECT_FREE_IF_INACCESSIBLEMEMONLY
1,361✔
2701
        elseif contains_is(_EFFECT_FREE_BUILTINS, f) || contains_is(_PURE_BUILTINS, f)
215,649✔
2702
            effect_free = ALWAYS_TRUE
125,886✔
2703
        else
2704
            effect_free = ALWAYS_FALSE
688✔
2705
        end
2706
        nothrow = builtin_nothrow(𝕃, f, argtypes, rt)
255,870✔
2707
        if contains_is(_INACCESSIBLEMEM_BUILTINS, f)
1,071,454✔
2708
            inaccessiblememonly = ALWAYS_TRUE
124,524✔
2709
        elseif contains_is(_ARGMEM_BUILTINS, f)
20,494✔
2710
            inaccessiblememonly = INACCESSIBLEMEM_OR_ARGMEMONLY
2,723✔
2711
        else
2712
            inaccessiblememonly = ALWAYS_FALSE
688✔
2713
        end
2714
        if f === memoryrefnew || f === memoryrefget || f === memoryrefset! || f === memoryref_isassigned
254,568✔
2715
            noub = memoryop_noub(f, argtypes) ? ALWAYS_TRUE : ALWAYS_FALSE
2,700✔
2716
        else
2717
            noub = ALWAYS_TRUE
126,585✔
2718
        end
2719
        return Effects(EFFECTS_TOTAL; consistent, effect_free, nothrow, inaccessiblememonly, noub)
127,935✔
2720
    end
2721
end
2722

2723
function memoryop_noub(@nospecialize(f), argtypes::Vector{Any})
1,362✔
2724
    nargs = length(argtypes)
1,362✔
2725
    nargs == 0 && return true # must throw and noub
1,362✔
2726
    lastargtype = argtypes[end]
1,362✔
2727
    isva = isvarargtype(lastargtype)
1,362✔
2728
    if f === memoryrefnew
1,362✔
2729
        if nargs == 1 && !isva
1,311✔
2730
            return true
1,230✔
2731
        elseif nargs == 2 && !isva
81✔
2732
            return true
×
2733
        end
2734
        expected_nargs = 3
81✔
2735
    elseif f === memoryrefget || f === memoryref_isassigned
84✔
2736
        expected_nargs = 3
18✔
2737
    else
2738
        @assert f === memoryrefset! "unexpected memoryop is given"
33✔
2739
        expected_nargs = 4
33✔
2740
    end
2741
    if nargs == expected_nargs && !isva
132✔
2742
        boundscheck = widenconditional(lastargtype)
132✔
2743
        hasintersect(widenconst(boundscheck), Bool) || return true # must throw and noub
132✔
2744
        boundscheck isa Const && boundscheck.val === true && return true
132✔
2745
    elseif nargs > expected_nargs + 1
×
2746
        return true # must throw and noub
×
2747
    elseif !isva
×
2748
        return true # must throw and noub
×
2749
    end
2750
    return false
132✔
2751
end
2752

2753
function current_scope_tfunc(::AbstractInterpreter, sv::InferenceState)
2,446✔
2754
    pc = sv.currpc
2,446✔
2755
    while true
2,446✔
2756
        pchandler = gethandler(sv, pc)
4,880✔
2757
        if pchandler === nothing
2,446✔
2758
            # No local scope available - inherited from the outside
2759
            return Any
2,442✔
2760
        end
2761
        # Remember that we looked at this handler, so we get re-scheduled
2762
        # if the scope information changes
2763
        isdefined(pchandler, :scope_uses) || (pchandler.scope_uses = Int[])
8✔
2764
        pcbb = block_for_inst(sv.cfg, pc)
4✔
2765
        if findfirst(==(pcbb), pchandler.scope_uses) === nothing
4✔
2766
            push!(pchandler.scope_uses, pcbb)
4✔
2767
        end
2768
        scope = pchandler.scopet
4✔
2769
        if scope !== nothing
4✔
2770
            # Found the scope - forward it
2771
            return scope
4✔
2772
        end
2773
        pc = pchandler.enter_idx
×
2774
    end
×
2775
end
2776
current_scope_tfunc(::AbstractInterpreter, ::IRInterpretationState) = Any
×
2777

2778
hasvarargtype(argtypes::Vector{Any}) = !isempty(argtypes) && isvarargtype(argtypes[end])
408,017✔
2779

2780
"""
2781
    builtin_nothrow(𝕃::AbstractLattice, f::Builtin, argtypes::Vector{Any}, rt)::Bool
2782

2783
Compute throw-ness of a builtin function call. `argtypes` should not include `f` itself.
2784
"""
2785
function builtin_nothrow(𝕃::AbstractLattice, @nospecialize(f), argtypes::Vector{Any}, @nospecialize(rt))
2786
    rt === Bottom && return false
127,935✔
2787
    if f === tuple || f === svec
226,257✔
2788
        return true
29,613✔
2789
    elseif hasvarargtype(argtypes)
98,322✔
2790
        return false
×
2791
    elseif contains_is(_PURE_BUILTINS, f)
552,236✔
2792
        return true
15,505✔
2793
    end
2794
    return _builtin_nothrow(𝕃, f, argtypes, rt)
82,817✔
2795
end
2796

2797
function builtin_tfunction(interp::AbstractInterpreter, @nospecialize(f), argtypes::Vector{Any},
544,735✔
2798
                           sv::Union{AbsIntState, Nothing})
2799
    𝕃ᵢ = typeinf_lattice(interp)
544,735✔
2800
    # Early constant evaluation for foldable builtins with all const args
2801
    if isa(f, IntrinsicFunction) ? is_pure_intrinsic_infer(f) : (f in _PURE_BUILTINS || (f in _CONSISTENT_BUILTINS && f in _EFFECT_FREE_BUILTINS))
607,885✔
2802
        if is_all_const_arg(argtypes, 1)
395,676✔
2803
            argvals = collect_const_args(argtypes, 1)
207,706✔
2804
            try
207,706✔
2805
                # unroll a few common cases for better codegen
2806
                if length(argvals) == 1
207,706✔
2807
                    return Const(f(argvals[1]))
25,952✔
2808
                elseif length(argvals) == 2
181,754✔
2809
                    return Const(f(argvals[1], argvals[2]))
144,970✔
2810
                elseif length(argvals) == 3
36,784✔
2811
                    return Const(f(argvals[1], argvals[2], argvals[3]))
34,844✔
2812
                end
2813
                return Const(f(argvals...))
1,940✔
2814
            catch ex # expected ErrorException, TypeError, ConcurrencyViolationError, DivideError etc.
2815
                ex isa InterruptException && rethrow()
15✔
2816
                return Bottom
15✔
2817
            end
2818
        end
2819
    end
2820
    if isa(f, IntrinsicFunction)
337,029✔
2821
        iidx = Int(reinterpret(Int32, f)) + 1
29,823✔
2822
        if iidx < 0 || iidx > length(T_IFUNC)
59,646✔
2823
            # unknown intrinsic
2824
            return Any
×
2825
        end
2826
        tf = T_IFUNC[iidx]
29,823✔
2827
    else
2828
        if f === tuple
307,206✔
2829
            return tuple_tfunc(𝕃ᵢ, argtypes)
40,430✔
2830
        elseif f === Core.current_scope
266,776✔
2831
            if length(argtypes) != 0
2,446✔
2832
                if length(argtypes) != 1 || !isvarargtype(argtypes[1])
×
2833
                    return Bottom
×
2834
                end
2835
            end
2836
            return current_scope_tfunc(interp, sv)
2,446✔
2837
        elseif f === Core.apply_type
264,330✔
2838
            return apply_type_tfunc(𝕃ᵢ, argtypes; max_union_splitting=InferenceParams(interp).max_union_splitting)
1,828✔
2839
        end
2840
        fidx = find_tfunc(f)
4,565,477✔
2841
        if fidx === nothing
262,502✔
2842
            # unknown/unhandled builtin function
2843
            return Any
1,748✔
2844
        end
2845
        tf = T_FFUNC_VAL[fidx]
260,754✔
2846
    end
2847

2848
    if hasvarargtype(argtypes)
290,577✔
2849
        if length(argtypes) - 1 > tf[2]
126✔
2850
            # definitely too many arguments
2851
            return Bottom
×
2852
        end
2853
        if length(argtypes) - 1 == tf[2]
126✔
2854
            argtypes = argtypes[1:end-1]
18✔
2855
        else
2856
            vatype = argtypes[end]::TypeofVararg
117✔
2857
            argtypes = argtypes[1:end-1]
162✔
2858
            while length(argtypes) < tf[1]
276✔
2859
                push!(argtypes, unwrapva(vatype))
159✔
2860
            end
159✔
2861
            if length(argtypes) < tf[2]
117✔
2862
                push!(argtypes, unconstrain_vararg_length(vatype))
51✔
2863
            end
2864
        end
2865
    elseif !(tf[1] <= length(argtypes) <= tf[2])
290,451✔
2866
        # wrong # of args
2867
        return Bottom
15✔
2868
    end
2869
    return tf[3](𝕃ᵢ, argtypes...)
290,562✔
2870
end
2871

2872
# Query whether the given intrinsic is nothrow
2873

2874
_iszero(@nospecialize x) = x === Intrinsics.xor_int(x, x)
127✔
2875
_isneg1(@nospecialize x) = _iszero(Intrinsics.not_int(x))
57✔
2876
_istypemin(@nospecialize x) = !_iszero(x) && Intrinsics.neg_int(x) === x
×
2877

2878
function builtin_exct(𝕃::AbstractLattice, @nospecialize(f::Builtin), argtypes::Vector{Any}, @nospecialize(rt))
2879
    if isa(f, IntrinsicFunction)
30,024✔
2880
        return intrinsic_exct(𝕃, f, argtypes)
458✔
2881
    elseif f === Core._svec_ref
29,566✔
2882
        return BoundsError
51✔
2883
    end
2884
    return Any
29,515✔
2885
end
2886

2887
function div_nothrow(f::IntrinsicFunction, @nospecialize(arg1), @nospecialize(arg2))
2888
    isa(arg2, Const) || return false
70✔
2889
    den_val = arg2.val
70✔
2890
    _iszero(den_val) && return false
70✔
2891
    f !== Intrinsics.checked_sdiv_int && return true
70✔
2892
    # Nothrow as long as we additionally don't do typemin(T)/-1
2893
    return !_isneg1(den_val) || (isa(arg1, Const) && !_istypemin(arg1.val))
57✔
2894
end
2895

2896
function known_is_valid_intrinsic_elptr(𝕃::AbstractLattice, @nospecialize(ptr))
2897
    ptrT = typeof_tfunc(𝕃, ptr)
254✔
2898
    isa(ptrT, Const) || return false
254✔
2899
    return is_valid_intrinsic_elptr(ptrT.val)
508✔
2900
end
2901

2902
function intrinsic_exct(𝕃::AbstractLattice, f::IntrinsicFunction, argtypes::Vector{Any})
19,118✔
2903
    if hasvarargtype(argtypes)
19,118✔
2904
        return Any
×
2905
    end
2906

2907
    # First check that we have the correct number of arguments
2908
    iidx = Int(reinterpret(Int32, f)) + 1
19,118✔
2909
    if iidx < 1 || iidx > length(T_IFUNC)
38,236✔
2910
        # invalid intrinsic (system will crash)
2911
        return Any
×
2912
    end
2913
    tf = T_IFUNC[iidx]
19,118✔
2914
    if !(tf[1] <= length(argtypes) <= tf[2])
19,118✔
2915
        # wrong # of args
2916
        return ArgumentError
×
2917
    end
2918

2919
    # TODO: We could do better for cglobal
2920
    f === Intrinsics.cglobal && return Any
19,118✔
2921
    # TODO: We can't know for sure, but the user should have a way to assert
2922
    # that it won't
2923
    f === Intrinsics.llvmcall && return Any
19,118✔
2924

2925
    if (f === Intrinsics.checked_udiv_int || f === Intrinsics.checked_urem_int ||
38,202✔
2926
        f === Intrinsics.checked_srem_int || f === Intrinsics.checked_sdiv_int)
2927
        # Nothrow as long as the second argument is guaranteed not to be zero
2928
        arg1 = argtypes[1]
70✔
2929
        arg2 = argtypes[2]
70✔
2930
        warg1 = widenconst(arg1)
70✔
2931
        warg2 = widenconst(arg2)
70✔
2932
        if !(warg1 === warg2 && isprimitivetype(warg1))
70✔
2933
            return Union{TypeError, DivideError}
×
2934
        end
2935
        if !div_nothrow(f, arg1, arg2)
140✔
2936
            return DivideError
×
2937
        end
2938
        return Union{}
70✔
2939
    end
2940

2941
    if f === Intrinsics.pointerref
19,036✔
2942
        # Nothrow as long as the types are ok. N.B.: dereferencability is not
2943
        # modeled here, but can cause errors (e.g. ReadOnlyMemoryError). We follow LLVM here
2944
        # in that it is legal to remove unused non-volatile loads.
2945
        if !(argtypes[1] ⊑ Ptr && argtypes[2] ⊑ Int && argtypes[3] ⊑ Int)
×
2946
            return Union{TypeError, ErrorException}
×
2947
        end
2948
        if !known_is_valid_intrinsic_elptr(𝕃, argtypes[1])
×
2949
            return ErrorException
×
2950
        end
2951
        return Union{}
×
2952
    end
2953

2954
    if f === Intrinsics.pointerset
19,036✔
2955
        eT = pointer_eltype(argtypes[1])
254✔
2956
        if !known_is_valid_intrinsic_elptr(𝕃, argtypes[1])
508✔
2957
            return Union{TypeError, ErrorException}
×
2958
        end
2959
        if !(argtypes[2] ⊑ eT && argtypes[3] ⊑ Int && argtypes[4] ⊑ Int)
254✔
2960
            return TypeError
×
2961
        end
2962
        return Union{}
254✔
2963
    end
2964

2965
    if f === Intrinsics.bitcast
18,782✔
2966
        ty, _, isconcrete, _ = instanceof_tfunc(argtypes[1], true)
1,052✔
2967
        xty = widenconst(argtypes[2])
1,052✔
2968
        if !isconcrete
1,052✔
2969
            return Union{ErrorException, TypeError}
×
2970
        end
2971
        if !(isprimitivetype(ty) && isprimitivetype(xty) && Core.sizeof(ty) === Core.sizeof(xty))
1,052✔
2972
            return ErrorException
×
2973
        end
2974
        return Union{}
1,052✔
2975
    end
2976

2977
    if f in (Intrinsics.sext_int, Intrinsics.zext_int, Intrinsics.trunc_int,
35,141✔
2978
             Intrinsics.fptoui, Intrinsics.fptosi, Intrinsics.uitofp,
2979
             Intrinsics.sitofp, Intrinsics.fptrunc, Intrinsics.fpext)
2980
        # If !isconcrete, `ty` may be Union{} at runtime even if we have
2981
        # isprimitivetype(ty).
2982
        ty, _, isconcrete, _ = instanceof_tfunc(argtypes[1], true)
2,047✔
2983
        if !isconcrete
2,047✔
2984
            return Union{ErrorException, TypeError}
×
2985
        end
2986
        xty = widenconst(argtypes[2])
2,047✔
2987
        if !(isprimitivetype(ty) && isprimitivetype(xty))
2,047✔
2988
            return ErrorException
×
2989
        end
2990

2991
        # fpext, fptrunc, fptoui, fptosi, uitofp, and sitofp have further
2992
        # restrictions on the allowed types.
2993
        if f === Intrinsics.fpext &&
2,047✔
2994
            !(ty <: CORE_FLOAT_TYPES && xty <: CORE_FLOAT_TYPES && Core.sizeof(ty) > Core.sizeof(xty))
2995
            return ErrorException
×
2996
        end
2997
        if f === Intrinsics.fptrunc &&
2,047✔
2998
            !(ty <: CORE_FLOAT_TYPES && xty <: CORE_FLOAT_TYPES && Core.sizeof(ty) < Core.sizeof(xty))
2999
            return ErrorException
×
3000
        end
3001
        if (f === Intrinsics.fptoui || f === Intrinsics.fptosi) && !(xty <: CORE_FLOAT_TYPES)
4,094✔
3002
            return ErrorException
×
3003
        end
3004
        if (f === Intrinsics.uitofp || f === Intrinsics.sitofp) && !(ty <: CORE_FLOAT_TYPES)
4,094✔
3005
            return ErrorException
×
3006
        end
3007

3008
        return Union{}
2,047✔
3009
    end
3010

3011
    if f === Intrinsics.have_fma
15,683✔
3012
        ty, _, isconcrete, _ = instanceof_tfunc(argtypes[1], true)
×
3013
        if !(isconcrete && isprimitivetype(ty))
×
3014
            return TypeError
×
3015
        end
3016
        return Union{}
×
3017
    end
3018

3019
    if f === Intrinsics.add_ptr || f === Intrinsics.sub_ptr
31,270✔
3020
        if !(argtypes[1] ⊑ Ptr && argtypes[2] ⊑ UInt)
96✔
3021
            return TypeError
×
3022
        end
3023
        return Union{}
96✔
3024
    end
3025

3026
    # The remaining intrinsics are math/bits/comparison intrinsics.
3027
    # All the non-floating point intrinsics work on primitive values of the same type.
3028
    isshift = f === shl_int || f === lshr_int || f === ashr_int
28,457✔
3029
    argtype1 = widenconst(argtypes[1])
15,587✔
3030
    isprimitivetype(argtype1) || return ErrorException
15,587✔
3031
    if contains_is(_FLOAT_INTRINSICS, f)
529,958✔
3032
        argtype1 <: CORE_FLOAT_TYPES || return ErrorException
×
3033
    end
3034

3035
    for i = 2:length(argtypes)
29,887✔
3036
        argtype = widenconst(argtypes[i])
14,300✔
3037
        if isshift ? !isprimitivetype(argtype) : argtype !== argtype1
14,300✔
3038
            return ErrorException
×
3039
        end
3040
    end
14,300✔
3041
    return Union{}
15,587✔
3042
end
3043

3044
function intrinsic_nothrow(f::IntrinsicFunction, argtypes::Vector{Any})
3045
    return intrinsic_exct(SimpleInferenceLattice.instance, f, argtypes) === Union{}
18,995✔
3046
end
3047

3048
function _is_effect_free_infer(f::IntrinsicFunction)
3049
     return !(f === Intrinsics.pointerset ||
164,760✔
3050
              f === Intrinsics.atomic_pointerref ||
3051
              f === Intrinsics.atomic_pointerset ||
3052
              f === Intrinsics.atomic_pointerswap ||
3053
              # f === Intrinsics.atomic_pointermodify ||
3054
              f === Intrinsics.atomic_pointerreplace ||
3055
              f === Intrinsics.atomic_fence)
3056
end
3057

3058
# whether `f` is pure for inference
3059
function is_pure_intrinsic_infer(f::IntrinsicFunction, is_effect_free::Union{Nothing,Bool}=nothing)
3060
    if is_effect_free === nothing
162,525✔
3061
        is_effect_free = _is_effect_free_infer(f)
127,024✔
3062
    end
3063
    return is_effect_free && !(
164,478✔
3064
            f === Intrinsics.llvmcall ||              # can do arbitrary things
3065
            f === Intrinsics.atomic_pointermodify ||  # can do arbitrary things
3066
            f === Intrinsics.pointerref ||            # this one is volatile
3067
            f === Intrinsics.sqrt_llvm_fast ||        # this one may differ at runtime (by a few ulps)
3068
            f === Intrinsics.have_fma ||              # this one depends on the runtime environment
3069
            f === Intrinsics.cglobal)                 # cglobal lookup answer changes at runtime
3070
end
3071

3072
function intrinsic_effects(f::IntrinsicFunction, argtypes::Vector{Any})
3073
    if f === Intrinsics.llvmcall
19,007✔
3074
        # llvmcall can do arbitrary things
3075
        return Effects()
12✔
3076
    elseif f === atomic_pointermodify
18,995✔
3077
        # atomic_pointermodify has memory effects, plus any effects from the ModifyOpInfo
3078
        return Effects()
×
3079
    end
3080
    is_effect_free = _is_effect_free_infer(f)
37,736✔
3081
    effect_free = is_effect_free ? ALWAYS_TRUE : ALWAYS_FALSE
18,995✔
3082
    if ((is_pure_intrinsic_infer(f, is_effect_free) && !contains_is(_INCONSISTENT_INTRINSICS, f)) ||
206,569✔
3083
        f === Intrinsics.pointerset || f === Intrinsics.atomic_pointerset || f === Intrinsics.atomic_fence)
3084
        consistent = ALWAYS_TRUE
18,986✔
3085
    else
3086
        consistent = ALWAYS_FALSE
×
3087
    end
3088
    nothrow = intrinsic_nothrow(f, argtypes)
18,995✔
3089
    inaccessiblememonly = is_effect_free && !(f === Intrinsics.pointerref) ? ALWAYS_TRUE : ALWAYS_FALSE
18,995✔
3090
    return Effects(EFFECTS_TOTAL; consistent, effect_free, nothrow, inaccessiblememonly)
18,995✔
3091
end
3092

3093
# TODO: this function is a very buggy and poor model of the return_type function
3094
# since abstract_call_gf_by_type is a very inaccurate model of _method and of typeinf_type,
3095
# while this assumes that it is an absolutely precise and accurate and exact model of both
3096
function return_type_tfunc(interp::AbstractInterpreter, argtypes::Vector{Any}, si::StmtInfo, sv::AbsIntState)
249✔
3097
    UNKNOWN = CallMeta(Type, Any, Effects(EFFECTS_THROWS; nortcall=false), NoCallInfo())
249✔
3098
    if !(2 <= length(argtypes) <= 3)
249✔
3099
        return Future(UNKNOWN)
×
3100
    end
3101

3102
    tt = widenslotwrapper(argtypes[end])
249✔
3103
    if !isa(tt, Const) && !(isType(tt) && !has_free_typevars(tt))
249✔
3104
        return Future(UNKNOWN)
12✔
3105
    end
3106

3107
    af_argtype = isa(tt, Const) ? tt.val : (tt::DataType).parameters[1]
237✔
3108
    if !isa(af_argtype, DataType) || !(af_argtype <: Tuple)
474✔
3109
        return Future(UNKNOWN)
×
3110
    end
3111

3112
    if length(argtypes) == 3
237✔
3113
        aft = widenslotwrapper(argtypes[2])
237✔
3114
        argtypes_vec = Any[aft, af_argtype.parameters...]
237✔
3115
    else
3116
        argtypes_vec = Any[af_argtype.parameters...]
×
3117
        isempty(argtypes_vec) && push!(argtypes_vec, Union{})
×
3118
        aft = argtypes_vec[1]
×
3119
    end
3120
    if !(isa(aft, Const) || (isType(aft) && !has_free_typevars(aft)) ||
237✔
3121
            (isconcretetype(aft) && !(aft <: Builtin) && !iskindtype(aft)))
3122
        return Future(UNKNOWN)
×
3123
    end
3124

3125
    # effects are not an issue if we know this statement will get removed, but if it does not get removed,
3126
    # then this could be recursively re-entering inference (via concrete-eval), which will not terminate
3127
    RT_CALL_EFFECTS = Effects(EFFECTS_TOTAL; nortcall=false)
237✔
3128

3129
    if contains_is(argtypes_vec, Union{})
756✔
3130
        return Future(CallMeta(Const(Union{}), Union{}, RT_CALL_EFFECTS, NoCallInfo()))
×
3131
    end
3132

3133
    # Run the abstract_call without restricting abstract call
3134
    # sites. Otherwise, our behavior model of abstract_call
3135
    # below will be wrong.
3136
    if isa(sv, InferenceState)
237✔
3137
        old_restrict = sv.restrict_abstract_call_sites
237✔
3138
        sv.restrict_abstract_call_sites = false
237✔
3139
    end
3140
    call = abstract_call(interp, ArgInfo(nothing, argtypes_vec), si, sv, #=max_methods=#-1)
237✔
3141
    tt = Core.Box(tt)
237✔
3142
    return Future{CallMeta}(call, interp, sv) do call, _, sv
237✔
3143
        if isa(sv, InferenceState)
234✔
3144
            sv.restrict_abstract_call_sites = old_restrict
234✔
3145
        end
3146
        info = MethodResultPure(ReturnTypeCallInfo(call.info))
234✔
3147
        rt = widenslotwrapper(call.rt)
234✔
3148
        if isa(rt, Const)
234✔
3149
            # output was computed to be constant
3150
            return CallMeta(Const(typeof(rt.val)), Union{}, RT_CALL_EFFECTS, info)
×
3151
        end
3152
        rt = widenconst(rt)
234✔
3153
        if rt === Bottom || (isconcretetype(rt) && !iskindtype(rt))
609✔
3154
            # output cannot be improved so it is known for certain
3155
            return CallMeta(Const(rt), Union{}, RT_CALL_EFFECTS, info)
165✔
3156
        elseif isa(sv, InferenceState) && !isempty(sv.pclimitations)
69✔
3157
            # conservatively express uncertainty of this result
3158
            # in two ways: both as being a subtype of this, and
3159
            # because of LimitedAccuracy causes
3160
            return CallMeta(Type{<:rt}, Union{}, RT_CALL_EFFECTS, info)
×
3161
        elseif isa(tt.contents, Const) || isconstType(tt.contents)
69✔
3162
            # input arguments were known for certain
3163
            # XXX: this doesn't imply we know anything about rt
3164
            return CallMeta(Const(rt), Union{}, RT_CALL_EFFECTS, info)
69✔
3165
        elseif isType(rt)
×
3166
            return CallMeta(Type{rt}, Union{}, RT_CALL_EFFECTS, info)
×
3167
        else
3168
            return CallMeta(Type{<:rt}, Union{}, RT_CALL_EFFECTS, info)
×
3169
        end
3170
    end
3171
end
3172

3173
# a simplified model of abstract_call_gf_by_type for applicable
3174
function abstract_applicable(interp::AbstractInterpreter, argtypes::Vector{Any},
50✔
3175
                             sv::AbsIntState, max_methods::Int)
3176
    length(argtypes) < 2 && return Future(CallMeta(Bottom, ArgumentError, EFFECTS_THROWS, NoCallInfo()))
50✔
3177
    isvarargtype(argtypes[2]) && return Future(CallMeta(Bool, ArgumentError, EFFECTS_THROWS, NoCallInfo()))
50✔
3178
    argtypes = argtypes[2:end]
100✔
3179
    atype = argtypes_to_type(argtypes)
50✔
3180
    if atype === Union{}
50✔
3181
        rt = Union{} # accidentally unreachable code
×
3182
    else
3183
        matches = find_method_matches(interp, argtypes, atype; max_methods)
100✔
3184
        info = NoCallInfo()
50✔
3185
        if isa(matches, FailedMethodMatch)
50✔
3186
            rt = Bool # too many matches to analyze
×
3187
        else
3188
            (; valid_worlds, applicable) = matches
50✔
3189
            update_valid_age!(sv, valid_worlds)
50✔
3190
            napplicable = length(applicable)
50✔
3191
            if napplicable == 0
50✔
3192
                rt = Const(false) # never any matches
26✔
3193
            elseif !fully_covering(matches) || any_ambig(matches)
48✔
3194
                # Account for the fact that we may encounter a MethodError with a non-covered or ambiguous signature.
3195
                rt = Bool
×
3196
            else
3197
                rt = Const(true) # has applicable matches
24✔
3198
            end
3199
            if rt !== Bool
50✔
3200
                info = VirtualMethodMatchInfo(matches.info)
50✔
3201
            end
3202
        end
3203
    end
3204
    return Future(CallMeta(rt, Union{}, EFFECTS_TOTAL, info))
50✔
3205
end
3206
add_tfunc(applicable, 1, INT_INF, @nospecs((𝕃::AbstractLattice, f, args...)->Bool), 40)
×
3207

3208
# a simplified model of abstract_invoke for Core._hasmethod
3209
function _hasmethod_tfunc(interp::AbstractInterpreter, argtypes::Vector{Any}, sv::AbsIntState)
8✔
3210
    if length(argtypes) == 3 && !isvarargtype(argtypes[3])
8✔
3211
        ft′ = argtype_by_index(argtypes, 2)
×
3212
        ft = widenconst(ft′)
×
3213
        ft === Bottom && return CallMeta(Bool, Any, EFFECTS_THROWS, NoCallInfo())
×
3214
        typeidx = 3
×
3215
    elseif length(argtypes) == 2 && !isvarargtype(argtypes[2])
8✔
3216
        typeidx = 2
8✔
3217
    else
3218
        return CallMeta(Any, Any, Effects(), NoCallInfo())
×
3219
    end
3220
    (types, isexact, _, _) = instanceof_tfunc(argtype_by_index(argtypes, typeidx), false)
8✔
3221
    isexact || return CallMeta(Bool, Any, Effects(), NoCallInfo())
14✔
3222
    unwrapped = unwrap_unionall(types)
2✔
3223
    if types === Bottom || !(unwrapped isa DataType) || unwrapped.name !== Tuple.name
4✔
3224
        return CallMeta(Bool, Any, EFFECTS_THROWS, NoCallInfo())
×
3225
    end
3226
    if typeidx == 3
2✔
3227
        isdispatchelem(ft) || return CallMeta(Bool, Any, Effects(), NoCallInfo()) # check that we might not have a subtype of `ft` at runtime, before doing supertype lookup below
×
3228
        types = rewrap_unionall(Tuple{ft, unwrapped.parameters...}, types)::Type
×
3229
    end
3230
    match, valid_worlds = findsup(types, method_table(interp))
2✔
3231
    update_valid_age!(sv, valid_worlds)
2✔
3232
    if match === nothing
2✔
3233
        rt = Const(false)
2✔
3234
        vresults = MethodLookupResult(Any[], valid_worlds, true)
2✔
3235
        mt = Core.methodtable
2✔
3236
        vinfo = MethodMatchInfo(vresults, mt, types, false) # XXX: this should actually be an info with invoke-type edge
2✔
3237
    else
3238
        rt = Const(true)
×
3239
        vinfo = InvokeCallInfo(nothing, match, nothing, types)
×
3240
    end
3241
    info = VirtualMethodMatchInfo(vinfo)
4✔
3242
    return CallMeta(rt, Union{}, EFFECTS_TOTAL, info)
2✔
3243
end
3244

3245
# N.B.: typename maps type equivalence classes to a single value
3246
function typename_static(@nospecialize(t))
×
3247
    t isa Const && return _typename(t.val)
×
3248
    t isa Conditional && return Bool.name
×
3249
    t = unwrap_unionall(widenconst(t))
×
3250
    return isType(t) ? _typename(t.parameters[1]) : Core.TypeName
×
3251
end
3252

3253
function global_order_exct(@nospecialize(o), loading::Bool, storing::Bool)
3254
    if !(o isa Const)
150✔
3255
        if o === Symbol
×
3256
            return ConcurrencyViolationError
×
3257
        elseif !hasintersect(o, Symbol)
×
3258
            return TypeError
×
3259
        else
3260
            return Union{ConcurrencyViolationError, TypeError}
×
3261
        end
3262
    end
3263
    sym = o.val
150✔
3264
    if sym isa Symbol
150✔
3265
        order = get_atomic_order(sym, loading, storing)
300✔
3266
        if order !== MEMORY_ORDER_INVALID && order !== MEMORY_ORDER_NOTATOMIC
150✔
3267
            return Union{}
150✔
3268
        else
3269
            return ConcurrencyViolationError
×
3270
        end
3271
    else
3272
        return TypeError
×
3273
    end
3274
end
3275

3276
@nospecs function get_binding_type_nothrow(𝕃::AbstractLattice, M, s)
×
3277
    ⊑ = partialorder(𝕃)
×
3278
    return M ⊑ Module && s ⊑ Symbol
×
3279
end
3280

3281
add_tfunc(getglobal, 2, 3, @nospecs((𝕃::AbstractLattice, args...)->Any), 1)
3✔
3282
add_tfunc(setglobal!, 3, 4, @nospecs((𝕃::AbstractLattice, args...)->Any), 3)
×
3283
add_tfunc(swapglobal!, 3, 4, @nospecs((𝕃::AbstractLattice, args...)->Any), 3)
×
3284
add_tfunc(modifyglobal!, 4, 5, @nospecs((𝕃::AbstractLattice, args...)->Any), 3)
×
3285
add_tfunc(replaceglobal!, 4, 6, @nospecs((𝕃::AbstractLattice, args...)->Any), 3)
×
3286
add_tfunc(setglobalonce!, 3, 5, @nospecs((𝕃::AbstractLattice, args...)->Bool), 3)
×
3287
add_tfunc(Core.get_binding_type, 2, 2, @nospecs((𝕃::AbstractLattice, args...)->Type), 0)
×
3288

3289
# foreigncall
3290
# ===========
3291

3292
# N.B. the `abstract_eval` callback below allows us to use these queries
3293
# both during abstract interpret and optimization
3294

3295
const FOREIGNCALL_ARG_START = 6
3296

3297
function foreigncall_effects(@nospecialize(abstract_eval), ::Expr)
3298
    # `:foreigncall` can potentially perform all sorts of operations, including calling
3299
    # overlay methods, but the `:foreigncall` itself is not dispatched, and there is no
3300
    # concern that the method calls that potentially occur within the `:foreigncall` will
3301
    # be executed using the wrong method table due to concrete evaluation, so using
3302
    # `EFFECTS_UNKNOWN` here and not tainting with `:nonoverlayed` is fine
3303
    return EFFECTS_UNKNOWN
4,990✔
3304
end
3305

3306
function new_genericmemory_nothrow(@nospecialize(abstract_eval), args::Vector{Any})
3307
    length(args) ≥ 1+FOREIGNCALL_ARG_START || return false
3308
    mtype = instanceof_tfunc(abstract_eval(args[FOREIGNCALL_ARG_START]))[1]
3309
    isa(mtype, DataType) || return false
3310
    isdefined(mtype, :instance) || return false
3311
    elsz = Int(datatype_layoutsize(mtype))
3312
    arrayelem = datatype_arrayelem(mtype)
3313
    dim = abstract_eval(args[1+FOREIGNCALL_ARG_START])
3314
    isa(dim, Const) || return false
3315
    dimval = dim.val
3316
    isa(dimval, Int) || return false
3317
    0 < dimval < typemax(Int) || return false
3318
    tot, ovflw = Intrinsics.checked_smul_int(dimval, elsz)
3319
    ovflw && return false
3320
    isunion = 2
3321
    tot, ovflw = Intrinsics.checked_sadd_int(tot, arrayelem == isunion ? 1 + dimval : 1)
3322
    ovflw && return false
3323
    return true
3324
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc