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

JuliaLang / julia / 1427

02 Feb 2026 03:21AM UTC coverage: 76.717% (-0.1%) from 76.855%
1427

push

buildkite

web-flow
merge the three methods of `error` into a single method (#60878)

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

1366 existing lines in 37 files now uncovered.

62925 of 82022 relevant lines covered (76.72%)

23174335.51 hits per line

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

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

3
#####################
4
# lattice utilities #
5
#####################
6

7
# true if Type{T} is inlineable as constant T
8
# requires that T is a singleton, s.t. T == S implies T === S
9
isconstType(@nospecialize t) = isType(t) && hasuniquerep(t.parameters[1])
1,230,720✔
10

11
# test whether type T has a unique representation, s.t. T == S implies T === S
12
function hasuniquerep(@nospecialize t)
68,095✔
13
    # typeof(Bottom) is special since even though it is a leaftype,
14
    # at runtime, it might be Type{Union{}} instead, so don't attempt inference of it
15
    t === typeof(Union{}) && return false
298,399✔
16
    t === Union{} && return true
298,399✔
17
    isa(t, TypeVar) && return false # TypeVars are identified by address, not equality
232,682✔
18
    iskindtype(typeof(t)) || return true # non-types are always compared by egal in the type system
296,070✔
19
    isconcretetype(t) && return true # these are also interned and pointer comparable
295,948✔
20
    if isa(t, DataType) && t.name !== Tuple.name && !isvarargtype(t) # invariant DataTypes
71,238✔
21
        return all(hasuniquerep, t.parameters)
18,533✔
22
    end
23
    return false
52,705✔
24
end
25

26
"""
27
    isTypeDataType(@nospecialize t)::Bool
28

29
For a type `t` test whether ∀S s.t. `isa(S, rewrap_unionall(Type{t}, ...))`,
30
we have `isa(S, DataType)`. In particular, if a statement is typed as `Type{t}`
31
(potentially wrapped in some `UnionAll`), then we are guaranteed that this statement
32
will be a `DataType` at runtime (and not e.g. a `Union` or `UnionAll` typeequal to it).
33
"""
34
function isTypeDataType(@nospecialize t)
35
    isa(t, DataType) || return false
145✔
36
    isType(t) && return false
145✔
37
    # Could be Union{} at runtime
38
    t === Core.TypeofBottom && return false
145✔
39
    # Return true if `t` is not covariant
40
    return t.name !== Tuple.name
145✔
41
end
42

43
has_extended_info(@nospecialize x) = (!isa(x, Type) && !isvarargtype(x)) || isType(x)
51,142✔
44

45
# Subtyping currently intentionally answers certain queries incorrectly for kind types. For
46
# some of these queries, this check can be used to somewhat protect against making incorrect
47
# decisions based on incorrect subtyping. Note that this check, itself, is broken for
48
# certain combinations of `a` and `b` where one/both isa/are `Union`/`UnionAll` type(s)s.
49
isnotbrokensubtype(@nospecialize(a), @nospecialize(b)) = (!iskindtype(b) || !isType(a) || hasuniquerep(a.parameters[1]) || b <: a)
45,000✔
50

51
function argtypes_to_type(argtypes::Vector{Any})
474,878✔
52
    argtypes = anymap(@nospecialize(a) -> isvarargtype(a) ? a : widenconst(a), argtypes)
2,812,572✔
53
    filter!(@nospecialize(x) -> !isvarargtype(x) || valid_as_lattice(unwrapva(x), true), argtypes)
1,897,036✔
54
    all(@nospecialize(x) -> isvarargtype(x) || valid_as_lattice(x, true), argtypes) || return Bottom
3,255,730✔
55
    return Tuple{argtypes...}
474,878✔
56
end
57

58
function isknownlength(t::DataType)
59
    isvatuple(t) || return true
×
60
    va = t.parameters[end]
×
61
    return isdefined(va, :N) && va.N isa Int
×
62
end
63

64
has_concrete_subtype(d::DataType) = d.flags & 0x0020 == 0x0020 # n.b. often computed only after setting the type and layout fields
2,291,559✔
65

66
# determine whether x is a valid lattice element
67
# For example, Type{v} is not valid if v is a value
68
# Accepts TypeVars and has_free_typevar also, since it assumes the user will rewrap it correctly
69
# If astag is true, then also requires that it be a possible type tag for a valid object
70
function valid_as_lattice(@nospecialize(x), astag::Bool=false)
3,669,481✔
71
    x === Bottom && false
3,793,783✔
72
    x isa TypeVar && return valid_as_lattice(x.ub, astag)
3,793,783✔
73
    x isa UnionAll && (x = unwrap_unionall(x))
3,788,541✔
74
    if x isa Union
3,788,541✔
75
        # the Union constructor ensures this (and we'll recheck after
76
        # operations that might remove the Union itself)
77
        return true
31,738✔
78
    end
79
    if x isa DataType
3,756,803✔
80
        if isType(x)
3,755,119✔
81
            p = x.parameters[1]
374,889✔
82
            p isa Type || p isa TypeVar || return false
383,607✔
83
        elseif astag && isstructtype(x)
4,313,557✔
84
            datatype_fieldtypes(x) # force computation of has_concrete_subtype to be updated now
2,286,921✔
85
            return has_concrete_subtype(x)
2,286,921✔
86
        end
87
        return true
1,468,198✔
88
    end
89
    return false
1,684✔
90
end
91

92
function valid_typeof_tparam(@nospecialize(t))
66✔
93
    if t === Symbol || t === Module || isbitstype(t)
96✔
94
        return true
48✔
95
    end
96
    isconcretetype(t) || return false
18✔
97
    if t <: NamedTuple
18✔
98
        t = t.parameters[2]::DataType
×
99
    end
100
    if t <: Tuple
18✔
101
        for p in t.parameters
36✔
102
            valid_typeof_tparam(p) || return false
36✔
103
        end
54✔
104
        return true
18✔
105
    end
106
    return false
×
107
end
108

109
# test if non-Type, non-TypeVar `x` can be used to parameterize a type
110
valid_tparam(@nospecialize(x)) = valid_typeof_tparam(typeof(x))
12✔
111

112
function compatible_vatuple(a::DataType, b::DataType)
113
    vaa = a.parameters[end]
×
114
    vab = b.parameters[end]
×
115
    if !(isvarargtype(vaa) && isvarargtype(vab))
×
116
        return isvarargtype(vaa) == isvarargtype(vab)
×
117
    end
118
    isdefined(vaa, :N) || return !isdefined(vab, :N)
×
119
    isdefined(vab, :N) || return false
×
120
    return vaa.N === vab.N
×
121
end
122

123
# return an upper-bound on type `a` with type `b` removed
124
# and also any contents that are not valid type tags on any objects
125
# such that `return <: a` && `Union{return, b} == Union{a, b}`
126
function typesubtract(@nospecialize(a), @nospecialize(b), max_union_splitting::Int)
5,232✔
127
    if a <: b && isnotbrokensubtype(a, b)
5,232✔
128
        return Bottom
1,646✔
129
    end
130
    ua = unwrap_unionall(a)
3,586✔
131
    if isa(ua, Union)
3,586✔
132
        uua = typesubtract(rewrap_unionall(ua.a, a), b, max_union_splitting)
1,646✔
133
        uub = typesubtract(rewrap_unionall(ua.b, a), b, max_union_splitting)
1,646✔
134
        return Union{valid_as_lattice(uua, true) ? uua : Union{},
1,646✔
135
                     valid_as_lattice(uub, true) ? uub : Union{}}
136
    elseif a isa DataType
1,940✔
137
        ub = unwrap_unionall(b)
1,940✔
138
        if ub isa DataType
1,940✔
139
            if a.name === ub.name === Tuple.name && length(a.parameters) == length(ub.parameters)
1,940✔
140
                if 1 < unionsplitcost(JLTypeLattice(), a.parameters) <= max_union_splitting
×
141
                    ta = switchtupleunion(a)
×
142
                    return typesubtract(Union{ta...}, b, 0)
×
143
                elseif b isa DataType
×
144
                    if !compatible_vatuple(a, b)
×
145
                        return a
×
146
                    end
147
                    # if exactly one element is not bottom after calling typesubtract
148
                    # then the result is all of the elements as normal except that one
149
                    notbottom = fill(false, length(a.parameters))
×
150
                    for i = 1:length(notbottom)
×
151
                        ap = unwrapva(a.parameters[i])
×
152
                        bp = unwrapva(b.parameters[i])
×
153
                        notbottom[i] = !(ap <: bp && isnotbrokensubtype(ap, bp))
×
154
                    end
×
155
                    let i = findfirst(notbottom)
×
156
                        if i !== nothing && findnext(notbottom, i + 1) === nothing
×
157
                            ta = collect(a.parameters)
×
158
                            ap = a.parameters[i]
×
159
                            bp = b.parameters[i]
×
160
                            (isvarargtype(ap) || isvarargtype(bp)) && return a
×
161
                            ta[i] = typesubtract(ap, bp, min(2, max_union_splitting))
×
162
                            ta[i] === Union{} && return Union{}
×
163
                            return Tuple{ta...}
×
164
                        end
165
                    end
166
                end
167
            end
168
        end
169
    end
170
    return a # TODO: improve this bound?
1,940✔
171
end
172

173
_typename(@nospecialize a) = Union{}
×
174
_typename(::TypeVar) = Core.TypeName
×
175
function _typename(a::Union)
×
176
    ta = _typename(a.a)
×
177
    tb = _typename(a.b)
×
178
    ta === tb && return ta # same type-name
×
179
    (ta === Union{} || tb === Union{}) && return Union{} # threw an error
×
180
    (ta isa Const && tb isa Const) && return Union{} # will throw an error (different type-names)
×
181
    return Core.TypeName # uncertain result
×
182
end
183
_typename(union::UnionAll) = _typename(union.body)
×
184
_typename(a::DataType) = Const(a.name)
5,109✔
185

186
function tuple_tail_elem(𝕃::AbstractLattice, @nospecialize(init), ct::Vector{Any})
×
187
    t = init
×
188
    for x in ct
×
189
        # FIXME: this is broken: it violates subtyping relations and creates invalid types with free typevars
190
        t = tmerge(𝕃, t, unwraptv(unwrapva(x)))
×
191
    end
×
192
    return Vararg{widenconst(t)}
×
193
end
194

195
# Gives a cost function over the effort to switch a tuple-union representation
196
# as a cartesian product, relative to the size of the original representation.
197
# Thus, we count the longest element as being roughly invariant to being inside
198
# or outside of the Tuple/Union nesting, though somewhat more expensive to be
199
# outside than inside because the representation is larger (because and it
200
# informs the callee whether any splitting is possible).
201
function unionsplitcost(𝕃::AbstractLattice, argtypes::Union{SimpleVector,Vector{Any}})
252,578✔
202
    nu = 1
252,578✔
203
    max = 2
252,578✔
204
    for ti in argtypes
252,578✔
205
        if has_extended_unionsplit(𝕃) && !isvarargtype(ti)
724,477✔
206
            ti = widenconst(ti)
945✔
207
        end
208
        if isa(ti, Union)
724,477✔
209
            nti = unionlen(ti)
3,312✔
210
            if nti > max
3,312✔
211
                max, nti = nti, max
33✔
212
            end
213
            nu, ovf = Core.Intrinsics.checked_smul_int(nu, nti)
3,312✔
214
            ovf && return typemax(Int)
3,312✔
215
        end
216
    end
724,474✔
217
    return nu
252,575✔
218
end
219

220
# take a Tuple where one or more parameters are Unions
221
# and return an array such that those Unions are removed
222
# and `Union{return...} == ty`
223
function switchtupleunion(@nospecialize(ty))
224
    tparams = (unwrap_unionall(ty)::DataType).parameters
×
225
    return _switchtupleunion(JLTypeLattice(), Any[tparams...], length(tparams), [], ty)
×
226
end
227

228
switchtupleunion(𝕃::AbstractLattice, argtypes::Vector{Any}) = _switchtupleunion(𝕃, argtypes, length(argtypes), [], nothing)
14,294✔
229

230
function _switchtupleunion(𝕃::AbstractLattice, t::Vector{Any}, i::Int, tunion::Vector{Any}, @nospecialize(origt))
18,915✔
231
    if i == 0
18,915✔
232
        if origt === nothing
6,258✔
233
            push!(tunion, copy(t))
12,516✔
234
        else
235
            tpl = rewrap_unionall(Tuple{t...}, origt)
×
236
            push!(tunion, tpl)
×
237
        end
238
    else
239
        origti = ti = t[i]
12,657✔
240
        # TODO remove this to implement callsite refinement of MustAlias
241
        if isa(ti, Union)
12,657✔
242
            for ty in uniontypes(ti)
3,105✔
243
                t[i] = ty
6,246✔
244
                _switchtupleunion(𝕃, t, i - 1, tunion, origt)
6,246✔
245
            end
6,246✔
246
            t[i] = origti
3,105✔
247
        elseif (has_extended_unionsplit(𝕃) && !isa(ti, Const) && !isvarargtype(ti) &&
9,552✔
248
            (wty = widenconst(ti); isa(wty, Union)))
15✔
249
            for ty in uniontypes(wty)
15✔
250
                t[i] = ty
30✔
251
                _switchtupleunion(𝕃, t, i - 1, tunion, origt)
30✔
252
            end
30✔
253
            t[i] = origti
15✔
254
        else
255
            _switchtupleunion(𝕃, t, i - 1, tunion, origt)
9,537✔
256
        end
257
    end
258
    return tunion
18,915✔
259
end
260

261
# unioncomplexity estimates the number of calls to `tmerge` to obtain the given type by
262
# counting the Union instances, taking also into account those hidden in a Tuple or UnionAll
263
unioncomplexity(@nospecialize x) = _unioncomplexity(x)::Int
2,508✔
264
function _unioncomplexity(@nospecialize x)
2,508✔
265
    if isa(x, DataType)
2,508✔
266
        x.name === Tuple.name || return 0
3,202✔
267
        c = 0
80✔
268
        for ti in x.parameters
160✔
269
            c = max(c, unioncomplexity(ti))
160✔
270
        end
240✔
271
        return c
80✔
272
    elseif isa(x, Union)
867✔
273
        return unioncomplexity(x.a) + unioncomplexity(x.b) + 1
852✔
274
    elseif isa(x, UnionAll)
15✔
275
        return max(unioncomplexity(x.body), unioncomplexity(x.var.ub))
15✔
276
    elseif isa(x, TypeofVararg)
×
UNCOV
277
        return isdefined(x, :T) ? unioncomplexity(x.T) + 1 : 1
×
278
    else
UNCOV
279
        return 0
×
280
    end
281
end
282

283
function unionall_depth(@nospecialize ua) # aka subtype_env_size
284
    depth = 0
61✔
285
    while ua isa UnionAll
151✔
286
        depth += 1
45✔
287
        ua = ua.body
45✔
288
    end
45✔
289
    return depth
106✔
290
end
291

292
function unwraptv_ub(@nospecialize t)
293
    while isa(t, TypeVar)
356,157✔
294
        t = t.ub
37✔
295
    end
37✔
296
    return t
356,151✔
297
end
298
function unwraptv_lb(@nospecialize t)
299
    while isa(t, TypeVar)
25✔
300
        t = t.lb
25✔
301
    end
25✔
302
    return t
25✔
303
end
304
const unwraptv = unwraptv_ub
305

306
"""
307
    is_identity_free_argtype(argtype)::Bool
308

309
Return `true` if the `argtype` object is identity free in the sense that this type or any
310
reachable through its fields has non-content-based identity (see `Base.isidentityfree`).
311
This query is specifically designed for `adjust_effects`, enabling it to refine the
312
`:consistent` effect property tainted by mutable allocation(s) within the analyzed call
313
graph when the return value type is `is_identity_free_argtype`, ensuring that the allocated
314
mutable objects are never returned.
315
"""
316
is_identity_free_argtype(@nospecialize ty) = is_identity_free_type(widenconst(ignorelimited(ty)))
3,538✔
317
is_identity_free_type(@nospecialize ty) = isidentityfree(ty)
3,538✔
318

319
"""
320
    is_immutable_argtype(argtype)::Bool
321

322
Return `true` if the `argtype` object is known to be immutable.
323
This query is specifically designed for `getfield_effects` and `isdefined_effects`, allowing
324
them to prove `:consistent`-cy of `getfield` / `isdefined` calls when applied to immutable
325
objects. Otherwise, we need to additionally prove that the non-immutable object is not a
326
global object to prove the `:consistent`-cy.
327
"""
328
is_immutable_argtype(@nospecialize argtype) = is_immutable_type(widenconst(ignorelimited(argtype)))
86,184✔
329
is_immutable_type(@nospecialize ty) = _is_immutable_type(unwrap_unionall(ty))
86,184✔
330
function _is_immutable_type(@nospecialize ty)
86,208✔
331
    if isa(ty, Union)
86,208✔
332
        return _is_immutable_type(ty.a) && _is_immutable_type(ty.b)
12✔
333
    end
334
    return !isabstracttype(ty) && !ismutabletype(ty)
86,196✔
335
end
336

337
"""
338
    is_mutation_free_argtype(argtype)::Bool
339

340
Return `true` if `argtype` object is mutation free in the sense that no mutable memory
341
is reachable from this type (either in the type itself) or through any fields
342
(see `Base.ismutationfree`).
343
This query is specifically written for analyzing the `:inaccessiblememonly` effect property
344
and is supposed to improve the analysis accuracy by not tainting the `:inaccessiblememonly`
345
property when there is access to mutation-free global object.
346
"""
347
is_mutation_free_argtype(@nospecialize(argtype)) =
11,987,299✔
348
    is_mutation_free_type(widenconst(ignorelimited(argtype)))
349
is_mutation_free_type(@nospecialize ty) = ismutationfree(ty)
6,908,691✔
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