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

JuliaLang / julia / #38002

06 Feb 2025 06:14AM UTC coverage: 20.322% (-2.4%) from 22.722%
#38002

push

local

web-flow
bpart: Fully switch to partitioned semantics (#57253)

This is the final PR in the binding partitions series (modulo bugs and
tweaks), i.e. it closes #54654 and thus closes #40399, which was the
original design sketch.

This thus activates the full designed semantics for binding partitions,
in particular allowing safe replacement of const bindings. It in
particular allows struct redefinitions. This thus closes
timholy/Revise.jl#18 and also closes #38584.

The biggest semantic change here is probably that this gets rid of the
notion of "resolvedness" of a binding. Previously, a lot of the behavior
of our implementation depended on when bindings were "resolved", which
could happen at basically an arbitrary point (in the compiler, in REPL
completion, in a different thread), making a lot of the semantics around
bindings ill- or at least implementation-defined. There are several
related issues in the bugtracker, so this closes #14055 closes #44604
closes #46354 closes #30277

It is also the last step to close #24569.
It also supports bindings for undef->defined transitions and thus closes
#53958 closes #54733 - however, this is not activated yet for
performance reasons and may need some further optimization.

Since resolvedness no longer exists, we need to replace it with some
hopefully more well-defined semantics. I will describe the semantics
below, but before I do I will make two notes:

1. There are a number of cases where these semantics will behave
slightly differently than the old semantics absent some other task going
around resolving random bindings.
2. The new behavior (except for the replacement stuff) was generally
permissible under the old semantics if the bindings happened to be
resolved at the right time.

With all that said, there are essentially three "strengths" of bindings:

1. Implicit Bindings: Anything implicitly obtained from `using Mod`, "no
binding", plus slightly more exotic corner cases around conflicts

2. Weakly declared bindin... (continued)

11 of 111 new or added lines in 7 files covered. (9.91%)

1273 existing lines in 68 files now uncovered.

9908 of 48755 relevant lines covered (20.32%)

105126.48 hits per line

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

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

3
# name and module reflection
4

5
"""
6
    parentmodule(m::Module) -> Module
7

8
Get a module's enclosing `Module`. `Main` is its own parent.
9

10
See also: [`names`](@ref), [`nameof`](@ref), [`fullname`](@ref), [`@__MODULE__`](@ref).
11

12
# Examples
13
```jldoctest
14
julia> parentmodule(Main)
15
Main
16

17
julia> parentmodule(Base.Broadcast)
18
Base
19
```
20
"""
21
parentmodule(m::Module) = (@_total_meta; ccall(:jl_module_parent, Ref{Module}, (Any,), m))
223✔
22

23
is_root_module(m::Module) = parentmodule(m) === m || m === Compiler || (isdefined(Main, :Base) && m === Main.Base)
144✔
24

25
"""
26
    moduleroot(m::Module) -> Module
27

28
Find the root module of a given module. This is the first module in the chain of
29
parent modules of `m` which is either a registered root module or which is its
30
own parent module.
31
"""
32
function moduleroot(m::Module)
33
    @_total_meta
×
34
    while true
12✔
35
        is_root_module(m) && return m
13✔
36
        p = parentmodule(m)
×
37
        p === m && return m
×
38
        m = p
×
39
    end
×
40
end
41

42
"""
43
    @__MODULE__ -> Module
44

45
Get the `Module` of the toplevel eval,
46
which is the `Module` code is currently being read from.
47
"""
48
macro __MODULE__()
49
    return __module__
50
end
51

52
"""
53
    fullname(m::Module)
54

55
Get the fully-qualified name of a module as a tuple of symbols. For example,
56

57
# Examples
58
```jldoctest
59
julia> fullname(Base.Iterators)
60
(:Base, :Iterators)
61

62
julia> fullname(Main)
63
(:Main,)
64
```
65
"""
66
function fullname(m::Module)
67
    @_total_meta
×
68
    mn = nameof(m)
13✔
69
    if m === Main || m === Base || m === Core
14✔
70
        return (mn,)
12✔
71
    end
72
    mp = parentmodule(m)
1✔
73
    if mp === m
1✔
74
        return (mn,)
×
75
    end
76
    return (fullname(mp)..., mn)
1✔
77
end
78

79
"""
80
    moduleloc(m::Module) -> LineNumberNode
81

82
Get the location of the `module` definition.
83
"""
84
function moduleloc(m::Module)
×
85
    line = Ref{Int32}(0)
×
86
    file = ccall(:jl_module_getloc, Ref{Symbol}, (Any, Ref{Int32}), m, line)
×
87
    return LineNumberNode(Int(line[]), file)
×
88
end
89

90
"""
91
    names(x::Module; all::Bool=false, imported::Bool=false, usings::Bool=false) -> Vector{Symbol}
92

93
Get a vector of the public names of a `Module`, excluding deprecated names.
94
If `all` is true, then the list also includes non-public names defined in the module,
95
deprecated names, and compiler-generated names.
96
If `imported` is true, then names explicitly imported from other modules
97
are also included.
98
If `usings` is true, then names explicitly imported via `using` are also included.
99
Names are returned in sorted order.
100

101
As a special case, all names defined in `Main` are considered \"public\",
102
since it is not idiomatic to explicitly mark names from `Main` as public.
103

104
!!! note
105
    `sym ∈ names(SomeModule)` does *not* imply `isdefined(SomeModule, sym)`.
106
    `names` may return symbols marked with `public` or `export`, even if
107
    they are not defined in the module.
108

109
!!! warning
110
    `names` may return duplicate names. The duplication happens, e.g. if an `import`ed name
111
    conflicts with an already existing identifier.
112

113
See also: [`Base.isexported`](@ref), [`Base.ispublic`](@ref), [`Base.@locals`](@ref), [`@__MODULE__`](@ref).
114
"""
115
names(m::Module; kwargs...) = sort!(unsorted_names(m; kwargs...))
×
UNCOV
116
unsorted_names(m::Module; all::Bool=false, imported::Bool=false, usings::Bool=false) =
×
117
    ccall(:jl_module_names, Array{Symbol,1}, (Any, Cint, Cint, Cint), m, all, imported, usings)
118

119
"""
120
    isexported(m::Module, s::Symbol) -> Bool
121

122
Returns whether a symbol is exported from a module.
123

124
See also: [`ispublic`](@ref), [`names`](@ref)
125

126
```jldoctest
127
julia> module Mod
128
           export foo
129
           public bar
130
       end
131
Mod
132

133
julia> Base.isexported(Mod, :foo)
134
true
135

136
julia> Base.isexported(Mod, :bar)
137
false
138

139
julia> Base.isexported(Mod, :baz)
140
false
141
```
142
"""
143
isexported(m::Module, s::Symbol) = ccall(:jl_module_exports_p, Cint, (Any, Any), m, s) != 0
×
144

145
"""
146
    ispublic(m::Module, s::Symbol) -> Bool
147

148
Returns whether a symbol is marked as public in a module.
149

150
Exported symbols are considered public.
151

152
!!! compat "Julia 1.11"
153
    This function and the notion of publicity were added in Julia 1.11.
154

155
See also: [`isexported`](@ref), [`names`](@ref)
156

157
```jldoctest
158
julia> module Mod
159
           export foo
160
           public bar
161
       end
162
Mod
163

164
julia> Base.ispublic(Mod, :foo)
165
true
166

167
julia> Base.ispublic(Mod, :bar)
168
true
169

170
julia> Base.ispublic(Mod, :baz)
171
false
172
```
173
"""
174
ispublic(m::Module, s::Symbol) = ccall(:jl_module_public_p, Cint, (Any, Any), m, s) != 0
×
175

176
# TODO: this is vaguely broken because it only works for explicit calls to
177
# `Base.deprecate`, not the @deprecated macro:
178
isdeprecated(m::Module, s::Symbol) = ccall(:jl_is_binding_deprecated, Cint, (Any, Any), m, s) != 0
6✔
179

180
function binding_module(m::Module, s::Symbol)
181
    p = ccall(:jl_get_module_of_binding, Ptr{Cvoid}, (Any, Any), m, s)
2✔
182
    p == C_NULL && return m
2✔
183
    return unsafe_pointer_to_objref(p)::Module
2✔
184
end
185

186
const _NAMEDTUPLE_NAME = NamedTuple.body.body.name
187

188
function _fieldnames(@nospecialize t)
189
    if t.name === _NAMEDTUPLE_NAME
7✔
190
        if t.parameters[1] isa Tuple
×
191
            return t.parameters[1]
×
192
        else
193
            throw(ArgumentError("type does not have definite field names"))
×
194
        end
195
    end
196
    return t.name.names
7✔
197
end
198

199
# N.B.: Needs to be synced with julia.h
200
const BINDING_KIND_CONST        = 0x0
201
const BINDING_KIND_CONST_IMPORT = 0x1
202
const BINDING_KIND_GLOBAL       = 0x2
203
const BINDING_KIND_IMPLICIT     = 0x3
204
const BINDING_KIND_EXPLICIT     = 0x4
205
const BINDING_KIND_IMPORTED     = 0x5
206
const BINDING_KIND_FAILED       = 0x6
207
const BINDING_KIND_DECLARED     = 0x7
208
const BINDING_KIND_GUARD        = 0x8
209
const BINDING_KIND_UNDEF_CONST  = 0x9
210
const BINDING_KIND_BACKDATED_CONST = 0xa
211

212
is_defined_const_binding(kind::UInt8) = (kind == BINDING_KIND_CONST || kind == BINDING_KIND_CONST_IMPORT || kind == BINDING_KIND_BACKDATED_CONST)
341,563✔
213
is_some_const_binding(kind::UInt8) = (is_defined_const_binding(kind) || kind == BINDING_KIND_UNDEF_CONST)
323,684✔
214
is_some_imported(kind::UInt8) = (kind == BINDING_KIND_IMPLICIT || kind == BINDING_KIND_EXPLICIT || kind == BINDING_KIND_IMPORTED)
1,008,305✔
215
is_some_guard(kind::UInt8) = (kind == BINDING_KIND_GUARD || kind == BINDING_KIND_FAILED || kind == BINDING_KIND_UNDEF_CONST)
683,025✔
216

217
function lookup_binding_partition(world::UInt, b::Core.Binding)
218
    ccall(:jl_get_binding_partition, Ref{Core.BindingPartition}, (Any, UInt), b, world)
608,543✔
219
end
220

221
function convert(::Type{Core.Binding}, gr::Core.GlobalRef)
222
    if isdefined(gr, :binding)
×
223
        return gr.binding
341,772✔
224
    else
225
        return ccall(:jl_get_module_binding, Ref{Core.Binding}, (Any, Any, Cint), gr.mod, gr.name, true)
×
226
    end
227
end
228

229
function lookup_binding_partition(world::UInt, gr::Core.GlobalRef)
230
    b = convert(Core.Binding, gr)
341,527✔
231
    return lookup_binding_partition(world, b)
341,527✔
232
end
233

234
partition_restriction(bpart::Core.BindingPartition) = ccall(:jl_bpart_get_restriction_value, Any, (Any,), bpart)
608,535✔
235

236
binding_kind(bpart::Core.BindingPartition) = ccall(:jl_bpart_get_kind, UInt8, (Any,), bpart)
950,060✔
237
binding_kind(m::Module, s::Symbol) = binding_kind(lookup_binding_partition(tls_world_age(), GlobalRef(m, s)))
×
238

239
"""
240
    delete_binding(mod::Module, sym::Symbol)
241

242
Force the binding `mod.sym` to be undefined again, allowing it be redefined.
243
Note that this operation is very expensive, requiring a full scan of all code in the system,
244
as well as potential recompilation of any methods that (may) have used binding
245
information.
246

247
!!! warning
248
    The implementation of this functionality is currently incomplete. Do not use
249
    this method on versions that contain this disclaimer except for testing.
250
"""
251
function delete_binding(mod::Module, sym::Symbol)
×
252
    ccall(:jl_disable_binding, Cvoid, (Any,), GlobalRef(mod, sym))
×
253
end
254

255
"""
256
    fieldname(x::DataType, i::Integer)
257

258
Get the name of field `i` of a `DataType`.
259

260
The return type is `Symbol`, except when `x <: Tuple`, in which case the index of the field is returned, of type `Int`.
261

262
# Examples
263
```jldoctest
264
julia> fieldname(Rational, 1)
265
:num
266

267
julia> fieldname(Rational, 2)
268
:den
269

270
julia> fieldname(Tuple{String,Int}, 2)
271
2
272
```
273
"""
274
function fieldname(t::DataType, i::Integer)
×
275
    throw_not_def_field() = throw(ArgumentError("type does not have definite field names"))
×
276
    function throw_field_access(t, i, n_fields)
×
277
        field_label = n_fields == 1 ? "field" : "fields"
×
278
        throw(ArgumentError("Cannot access field $i since type $t only has $n_fields $field_label."))
×
279
    end
280
    throw_need_pos_int(i) = throw(ArgumentError("Field numbers must be positive integers. $i is invalid."))
×
281

282
    isabstracttype(t) && throw_not_def_field()
×
283
    names = _fieldnames(t)
×
284
    n_fields = length(names)::Int
×
285
    i > n_fields && throw_field_access(t, i, n_fields)
×
286
    i < 1 && throw_need_pos_int(i)
×
287
    return @inbounds names[i]::Symbol
×
288
end
289

290
fieldname(t::UnionAll, i::Integer) = fieldname(unwrap_unionall(t), i)
×
291
fieldname(t::Type{<:Tuple}, i::Integer) =
×
292
    i < 1 || i > fieldcount(t) ? throw(BoundsError(t, i)) : Int(i)
293

294
"""
295
    fieldnames(x::DataType)
296

297
Get a tuple with the names of the fields of a `DataType`.
298

299
Each name is a `Symbol`, except when `x <: Tuple`, in which case each name (actually the
300
index of the field) is an `Int`.
301

302
See also [`propertynames`](@ref), [`hasfield`](@ref).
303

304
# Examples
305
```jldoctest
306
julia> fieldnames(Rational)
307
(:num, :den)
308

309
julia> fieldnames(typeof(1+im))
310
(:re, :im)
311

312
julia> fieldnames(Tuple{String,Int})
313
(1, 2)
314
```
315
"""
316
fieldnames(t::DataType) = (fieldcount(t); # error check to make sure type is specific enough
7✔
317
                           (_fieldnames(t)...,))::Tuple{Vararg{Symbol}}
7✔
318
fieldnames(t::UnionAll) = fieldnames(unwrap_unionall(t))
×
319
fieldnames(::Core.TypeofBottom) =
×
320
    throw(ArgumentError("The empty type does not have field names since it does not have instances."))
321
fieldnames(t::Type{<:Tuple}) = ntuple(identity, fieldcount(t))
×
322

323
"""
324
    hasfield(T::Type, name::Symbol)
325

326
Return a boolean indicating whether `T` has `name` as one of its own fields.
327

328
See also [`fieldnames`](@ref), [`fieldcount`](@ref), [`hasproperty`](@ref).
329

330
!!! compat "Julia 1.2"
331
     This function requires at least Julia 1.2.
332

333
# Examples
334
```jldoctest
335
julia> struct Foo
336
            bar::Int
337
       end
338

339
julia> hasfield(Foo, :bar)
340
true
341

342
julia> hasfield(Foo, :x)
343
false
344
```
345
"""
346
hasfield(T::Type, name::Symbol) = fieldindex(T, name, false) > 0
×
347

348
"""
349
    nameof(t::DataType) -> Symbol
350

351
Get the name of a (potentially `UnionAll`-wrapped) `DataType` (without its parent module)
352
as a symbol.
353

354
# Examples
355
```jldoctest
356
julia> module Foo
357
           struct S{T}
358
           end
359
       end
360
Foo
361

362
julia> nameof(Foo.S{T} where T)
363
:S
364
```
365
"""
366
nameof(t::DataType) = t.name.name
30✔
367
nameof(t::UnionAll) = nameof(unwrap_unionall(t))::Symbol
×
368

369
"""
370
    parentmodule(t::DataType) -> Module
371

372
Determine the module containing the definition of a (potentially `UnionAll`-wrapped) `DataType`.
373

374
# Examples
375
```jldoctest
376
julia> module Foo
377
           struct Int end
378
       end
379
Foo
380

381
julia> parentmodule(Int)
382
Core
383

384
julia> parentmodule(Foo.Int)
385
Foo
386
```
387
"""
388
parentmodule(t::DataType) = t.name.module
40✔
389
parentmodule(t::UnionAll) = parentmodule(unwrap_unionall(t))
×
390

391
"""
392
    isconst(m::Module, s::Symbol) -> Bool
393
    isconst(g::GlobalRef)
394

395
Determine whether a global is `const` in a given module `m`, either
396
because it was declared constant or because it was imported from a
397
constant binding. Note that constant-ness is specific to a particular
398
world age, so the result of this function may not be assumed to hold
399
after a world age update.
400
"""
UNCOV
401
isconst(m::Module, s::Symbol) =
×
402
    ccall(:jl_is_const, Cint, (Any, Any), m, s) != 0
403

404
function isconst(g::GlobalRef)
×
405
    return ccall(:jl_globalref_is_const, Cint, (Any,), g) != 0
×
406
end
407

408
"""
409
    isconst(t::DataType, s::Union{Int,Symbol}) -> Bool
410

411
Determine whether a field `s` is const in a given type `t`
412
in the sense that a read from said field is consistent
413
for egal objects. Note in particular that out-of-bounds
414
fields are considered const under this definition (because
415
they always throw).
416
"""
417
function isconst(@nospecialize(t::Type), s::Symbol)
×
418
    @_foldable_meta
×
419
    t = unwrap_unionall(t)
×
420
    isa(t, DataType) || return false
×
421
    return isconst(t, fieldindex(t, s, false))
×
422
end
423
function isconst(@nospecialize(t::Type), s::Int)
×
424
    @_foldable_meta
×
425
    t = unwrap_unionall(t)
×
426
    # TODO: what to do for `Union`?
427
    isa(t, DataType) || return false # uncertain
×
428
    ismutabletype(t) || return true # immutable structs are always const
496✔
429
    1 <= s <= length(t.name.names) || return true # OOB reads are "const" since they always throw
352✔
430
    constfields = t.name.constfields
352✔
431
    constfields === C_NULL && return false
352✔
432
    s -= 1
14✔
433
    return unsafe_load(Ptr{UInt32}(constfields), 1 + s÷32) & (1 << (s%32)) != 0
14✔
434
end
435

436
"""
437
    isfieldatomic(t::DataType, s::Union{Int,Symbol}) -> Bool
438

439
Determine whether a field `s` is declared `@atomic` in a given type `t`.
440
"""
441
function isfieldatomic(@nospecialize(t::Type), s::Symbol)
×
442
    @_foldable_meta
×
443
    t = unwrap_unionall(t)
×
444
    isa(t, DataType) || return false
×
445
    return isfieldatomic(t, fieldindex(t, s, false))
×
446
end
447
function isfieldatomic(@nospecialize(t::Type), s::Int)
448
    @_foldable_meta
×
449
    t = unwrap_unionall(t)
×
450
    # TODO: what to do for `Union`?
451
    isa(t, DataType) || return false # uncertain
×
452
    ismutabletype(t) || return false # immutable structs are never atomic
4,344✔
453
    1 <= s <= length(t.name.names) || return false # OOB reads are not atomic (they always throw)
280✔
454
    atomicfields = t.name.atomicfields
280✔
455
    atomicfields === C_NULL && return false
280✔
456
    s -= 1
88✔
457
    return unsafe_load(Ptr{UInt32}(atomicfields), 1 + s÷32) & (1 << (s%32)) != 0
88✔
458
end
459

460
"""
461
    @locals()
462

463
Construct a dictionary of the names (as symbols) and values of all local
464
variables defined as of the call site.
465

466
!!! compat "Julia 1.1"
467
    This macro requires at least Julia 1.1.
468

469
# Examples
470
```jldoctest
471
julia> let x = 1, y = 2
472
           Base.@locals
473
       end
474
Dict{Symbol, Any} with 2 entries:
475
  :y => 2
476
  :x => 1
477

478
julia> function f(x)
479
           local y
480
           show(Base.@locals); println()
481
           for i = 1:1
482
               show(Base.@locals); println()
483
           end
484
           y = 2
485
           show(Base.@locals); println()
486
           nothing
487
       end;
488

489
julia> f(42)
490
Dict{Symbol, Any}(:x => 42)
491
Dict{Symbol, Any}(:i => 1, :x => 42)
492
Dict{Symbol, Any}(:y => 2, :x => 42)
493
```
494
"""
495
macro locals()
496
    return Expr(:locals)
497
end
498

499
# concrete datatype predicates
500

501
datatype_fieldtypes(x::DataType) = ccall(:jl_get_fieldtypes, Core.SimpleVector, (Any,), x)
59,107✔
502

503
struct DataTypeLayout
504
    size::UInt32
505
    nfields::UInt32
506
    npointers::UInt32
507
    firstptr::Int32
508
    alignment::UInt16
509
    flags::UInt16
510
    # haspadding : 1;
511
    # fielddesc_type : 2;
512
    # arrayelem_isboxed : 1;
513
    # arrayelem_isunion : 1;
514
end
515

516
"""
517
    Base.datatype_alignment(dt::DataType) -> Int
518

519
Memory allocation minimum alignment for instances of this type.
520
Can be called on any `isconcretetype`, although for Memory it will give the
521
alignment of the elements, not the whole object.
522
"""
523
function datatype_alignment(dt::DataType)
×
524
    @_foldable_meta
×
525
    dt.layout == C_NULL && throw(UndefRefError())
×
526
    alignment = unsafe_load(convert(Ptr{DataTypeLayout}, dt.layout)).alignment
×
527
    return Int(alignment)
×
528
end
529

530
function uniontype_layout(@nospecialize T::Type)
531
    sz = RefValue{Csize_t}(0)
×
532
    algn = RefValue{Csize_t}(0)
×
533
    isinline = ccall(:jl_islayout_inline, Cint, (Any, Ptr{Csize_t}, Ptr{Csize_t}), T, sz, algn) != 0
×
534
    (isinline, Int(sz[]), Int(algn[]))
×
535
end
536

537
LLT_ALIGN(x, sz) = (x + sz - 1) & -sz
×
538

539
# amount of total space taken by T when stored in a container
540
function aligned_sizeof(@nospecialize T::Type)
×
541
    @_foldable_meta
×
542
    if isa(T, Union)
×
543
        if allocatedinline(T)
×
544
            # NOTE this check is equivalent to `isbitsunion(T)`, we can improve type
545
            # inference in the second branch with the outer `isa(T, Union)` check
546
            _, sz, al = uniontype_layout(T)
×
547
            return LLT_ALIGN(sz, al)
×
548
        end
549
    elseif allocatedinline(T)
×
550
        al = datatype_alignment(T)
×
551
        return LLT_ALIGN(Core.sizeof(T), al)
×
552
    end
553
    return Core.sizeof(Ptr{Cvoid})
×
554
end
555

556
gc_alignment(sz::Integer) = Int(ccall(:jl_alignment, Cint, (Csize_t,), sz))
×
557
gc_alignment(T::Type) = gc_alignment(Core.sizeof(T))
×
558

559
"""
560
    Base.datatype_haspadding(dt::DataType) -> Bool
561

562
Return whether the fields of instances of this type are packed in memory,
563
with no intervening padding bits (defined as bits whose value does not impact
564
the semantic value of the instance itself).
565
Can be called on any `isconcretetype`.
566
"""
567
function datatype_haspadding(dt::DataType)
×
568
    @_foldable_meta
×
569
    dt.layout == C_NULL && throw(UndefRefError())
×
570
    flags = unsafe_load(convert(Ptr{DataTypeLayout}, dt.layout)).flags
×
571
    return flags & 1 == 1
×
572
end
573

574
"""
575
    Base.datatype_isbitsegal(dt::DataType) -> Bool
576

577
Return whether egality of the (non-padding bits of the) in-memory representation
578
of an instance of this type implies semantic egality of the instance itself.
579
This may not be the case if the type contains to other values whose egality is
580
independent of their identity (e.g. immutable structs, some types, etc.).
581
"""
582
function datatype_isbitsegal(dt::DataType)
×
583
    @_foldable_meta
×
584
    dt.layout == C_NULL && throw(UndefRefError())
×
585
    flags = unsafe_load(convert(Ptr{DataTypeLayout}, dt.layout)).flags
×
586
    return (flags & (1<<5)) != 0
×
587
end
588

589
"""
590
    Base.datatype_nfields(dt::DataType) -> UInt32
591

592
Return the number of fields known to this datatype's layout. This may be
593
different from the number of actual fields of the type for opaque types.
594
Can be called on any `isconcretetype`.
595
"""
596
function datatype_nfields(dt::DataType)
597
    @_foldable_meta
×
598
    dt.layout == C_NULL && throw(UndefRefError())
676✔
599
    return unsafe_load(convert(Ptr{DataTypeLayout}, dt.layout)).nfields
676✔
600
end
601

602
"""
603
    Base.datatype_npointers(dt::DataType) -> Int
604

605
Return the number of pointers in the layout of a datatype.
606
"""
607
function datatype_npointers(dt::DataType)
608
    @_foldable_meta
×
609
    dt.layout == C_NULL && throw(UndefRefError())
15,286✔
610
    return unsafe_load(convert(Ptr{DataTypeLayout}, dt.layout)).npointers
15,286✔
611
end
612

613
"""
614
    Base.datatype_pointerfree(dt::DataType) -> Bool
615

616
Return whether instances of this type can contain references to gc-managed memory.
617
Can be called on any `isconcretetype`.
618
"""
619
function datatype_pointerfree(dt::DataType)
620
    @_foldable_meta
×
621
    return datatype_npointers(dt) == 0
15,286✔
622
end
623

624
"""
625
    Base.datatype_fielddesc_type(dt::DataType) -> Int
626

627
Return the size in bytes of each field-description entry in the layout array,
628
located at `(dt.layout + sizeof(DataTypeLayout))`.
629
Can be called on any `isconcretetype`.
630

631
See also [`fieldoffset`](@ref).
632
"""
633
function datatype_fielddesc_type(dt::DataType)
×
634
    @_foldable_meta
×
635
    dt.layout == C_NULL && throw(UndefRefError())
×
636
    flags = unsafe_load(convert(Ptr{DataTypeLayout}, dt.layout)).flags
×
637
    return (flags >> 1) & 3
×
638
end
639

640
"""
641
    Base.datatype_arrayelem(dt::DataType) -> Int
642

643
Return the behavior of the trailing array types allocations.
644
Can be called on any `isconcretetype`, but only meaningful on `Memory`.
645

646
0 = inlinealloc
647
1 = isboxed
648
2 = isbitsunion
649
"""
650
function datatype_arrayelem(dt::DataType)
2,418✔
651
    @_foldable_meta
2,418✔
652
    dt.layout == C_NULL && throw(UndefRefError())
2,418✔
653
    flags = unsafe_load(convert(Ptr{DataTypeLayout}, dt.layout)).flags
2,418✔
654
    return (flags >> 3) & 3
2,418✔
655
end
656

657
function datatype_layoutsize(dt::DataType)
2,418✔
658
    @_foldable_meta
2,418✔
659
    dt.layout == C_NULL && throw(UndefRefError())
18,137✔
660
    size = unsafe_load(convert(Ptr{DataTypeLayout}, dt.layout)).size
18,137✔
661
    return size % Int
18,137✔
662
end
663

664

665
# For type stability, we only expose a single struct that describes everything
666
struct FieldDesc
667
    isforeign::Bool
×
668
    isptr::Bool
669
    size::UInt32
670
    offset::UInt32
671
end
672

673
struct FieldDescStorage{T}
674
    ptrsize::T
675
    offset::T
676
end
677
FieldDesc(fd::FieldDescStorage{T}) where {T} =
1,702✔
678
    FieldDesc(false, fd.ptrsize & 1 != 0,
679
              fd.ptrsize >> 1, fd.offset)
680

681
struct DataTypeFieldDesc
682
    dt::DataType
683
    function DataTypeFieldDesc(dt::DataType)
684
        dt.layout == C_NULL && throw(UndefRefError())
670✔
685
        new(dt)
670✔
686
    end
687
end
688

689
function getindex(dtfd::DataTypeFieldDesc, i::Int)
690
    layout_ptr = convert(Ptr{DataTypeLayout}, dtfd.dt.layout)
1,702✔
691
    fd_ptr = layout_ptr + Core.sizeof(DataTypeLayout)
1,702✔
692
    layout = unsafe_load(layout_ptr)
1,702✔
693
    fielddesc_type = (layout.flags >> 1) & 3
1,702✔
694
    nfields = layout.nfields
1,702✔
695
    @boundscheck ((1 <= i <= nfields) || throw(BoundsError(dtfd, i)))
1,702✔
696
    if fielddesc_type == 0
1,702✔
697
        return FieldDesc(unsafe_load(Ptr{FieldDescStorage{UInt8}}(fd_ptr), i))
1,702✔
698
    elseif fielddesc_type == 1
×
699
        return FieldDesc(unsafe_load(Ptr{FieldDescStorage{UInt16}}(fd_ptr), i))
×
700
    elseif fielddesc_type == 2
×
701
        return FieldDesc(unsafe_load(Ptr{FieldDescStorage{UInt32}}(fd_ptr), i))
×
702
    else
703
        # fielddesc_type == 3
704
        return FieldDesc(true, true, 0, 0)
×
705
    end
706
end
707

708
"""
709
    ismutable(v) -> Bool
710

711
Return `true` if and only if value `v` is mutable.  See [Mutable Composite Types](@ref)
712
for a discussion of immutability. Note that this function works on values, so if you
713
give it a `DataType`, it will tell you that a value of the type is mutable.
714

715
!!! note
716
    For technical reasons, `ismutable` returns `true` for values of certain special types
717
    (for example `String` and `Symbol`) even though they cannot be mutated in a permissible way.
718

719
See also [`isbits`](@ref), [`isstructtype`](@ref).
720

721
# Examples
722
```jldoctest
723
julia> ismutable(1)
724
false
725

726
julia> ismutable([1,2])
727
true
728
```
729

730
!!! compat "Julia 1.5"
731
    This function requires at least Julia 1.5.
732
"""
733
ismutable(@nospecialize(x)) = (@_total_meta; (typeof(x).name::Core.TypeName).flags & 0x2 == 0x2)
9,267✔
734
# The type assertion above is required to fix some invalidations.
735
# See also https://github.com/JuliaLang/julia/issues/52134
736

737
"""
738
    ismutabletype(T) -> Bool
739

740
Determine whether type `T` was declared as a mutable type
741
(i.e. using `mutable struct` keyword).
742
If `T` is not a type, then return `false`.
743

744
!!! compat "Julia 1.7"
745
    This function requires at least Julia 1.7.
746
"""
747
function ismutabletype(@nospecialize t)
748
    @_total_meta
×
749
    t = unwrap_unionall(t)
5,100✔
750
    # TODO: what to do for `Union`?
751
    return isa(t, DataType) && ismutabletypename(t.name)
8,399✔
752
end
753

754
ismutabletypename(tn::Core.TypeName) = tn.flags & 0x2 == 0x2
18,004✔
755

756
"""
757
    isstructtype(T) -> Bool
758

759
Determine whether type `T` was declared as a struct type
760
(i.e. using the `struct` or `mutable struct` keyword).
761
If `T` is not a type, then return `false`.
762
"""
763
function isstructtype(@nospecialize t)
764
    @_total_meta
×
765
    t = unwrap_unionall(t)
×
766
    # TODO: what to do for `Union`?
767
    isa(t, DataType) || return false
×
768
    return !isprimitivetype(t) && !isabstracttype(t)
95,770✔
769
end
770

771
"""
772
    isprimitivetype(T) -> Bool
773

774
Determine whether type `T` was declared as a primitive type
775
(i.e. using the `primitive type` syntax).
776
If `T` is not a type, then return `false`.
777
"""
778
function isprimitivetype(@nospecialize t)
14,512✔
779
    @_total_meta
14,512✔
780
    t = unwrap_unionall(t)
15,984✔
781
    # TODO: what to do for `Union`?
782
    isa(t, DataType) || return false
15,986✔
783
    return (t.flags & 0x0080) == 0x0080
93,334✔
784
end
785

786
"""
787
    isbitstype(T)
788

789
Return `true` if type `T` is a "plain data" type,
790
meaning it is immutable and contains no references to other values,
791
only `primitive` types and other `isbitstype` types.
792
Typical examples are numeric types such as [`UInt8`](@ref),
793
[`Float64`](@ref), and [`Complex{Float64}`](@ref).
794
This category of types is significant since they are valid as type parameters,
795
may not track [`isdefined`](@ref) / [`isassigned`](@ref) status,
796
and have a defined layout that is compatible with C.
797
If `T` is not a type, then return `false`.
798

799
See also [`isbits`](@ref), [`isprimitivetype`](@ref), [`ismutable`](@ref).
800

801
# Examples
802
```jldoctest
803
julia> isbitstype(Complex{Float64})
804
true
805

806
julia> isbitstype(Complex)
807
false
808
```
809
"""
810
isbitstype(@nospecialize t) = (@_total_meta; isa(t, DataType) && (t.flags & 0x0008) == 0x0008)
7,504✔
811

812
"""
813
    isbits(x)
814

815
Return `true` if `x` is an instance of an [`isbitstype`](@ref) type.
816
"""
817
isbits(@nospecialize x) = isbitstype(typeof(x))
7,092✔
818

819
"""
820
    objectid(x) -> UInt
821

822
Get a hash value for `x` based on object identity.
823

824
If `x === y` then `objectid(x) == objectid(y)`, and usually when `x !== y`, `objectid(x) != objectid(y)`.
825

826
See also [`hash`](@ref), [`IdDict`](@ref).
827
"""
828
function objectid(@nospecialize(x))
829
    @_total_meta
1✔
830
    return ccall(:jl_object_id, UInt, (Any,), x)
4,397✔
831
end
832

833
"""
834
    isdispatchtuple(T)
835

836
Determine whether type `T` is a tuple of concrete types,
837
meaning it could appear as a type signature in dispatch
838
and has no subtypes (or supertypes) which could appear in a call.
839
If `T` is not a type, then return `false`.
840
"""
841
isdispatchtuple(@nospecialize(t)) = (@_total_meta; isa(t, DataType) && (t.flags & 0x0004) == 0x0004)
343✔
842

843
datatype_ismutationfree(dt::DataType) = (@_total_meta; (dt.flags & 0x0100) == 0x0100)
33,084✔
844

845
"""
846
    Base.ismutationfree(T)
847

848
Determine whether type `T` is mutation free in the sense that no mutable memory
849
is reachable from this type (either in the type itself) or through any fields.
850
Note that the type itself need not be immutable. For example, an empty mutable
851
type is `ismutabletype`, but also `ismutationfree`.
852
If `T` is not a type, then return `false`.
853
"""
854
function ismutationfree(@nospecialize(t))
10,490✔
855
    t = unwrap_unionall(t)
15,353✔
856
    if isa(t, DataType)
15,315✔
857
        return datatype_ismutationfree(t)
33,084✔
858
    elseif isa(t, Union)
70✔
859
        return ismutationfree(t.a) && ismutationfree(t.b)
70✔
860
    end
861
    # TypeVar, etc.
862
    return false
×
863
end
864

865
datatype_isidentityfree(dt::DataType) = (@_total_meta; (dt.flags & 0x0200) == 0x0200)
16✔
866

867
"""
868
    Base.isidentityfree(T)
869

870
Determine whether type `T` is identity free in the sense that this type or any
871
reachable through its fields has non-content-based identity.
872
If `T` is not a type, then return `false`.
873
"""
874
function isidentityfree(@nospecialize(t))
×
875
    t = unwrap_unionall(t)
16✔
876
    if isa(t, DataType)
16✔
877
        return datatype_isidentityfree(t)
16✔
878
    elseif isa(t, Union)
×
879
        return isidentityfree(t.a) && isidentityfree(t.b)
×
880
    end
881
    # TypeVar, etc.
882
    return false
×
883
end
884

885
iskindtype(@nospecialize t) = (t === DataType || t === UnionAll || t === Union || t === typeof(Bottom))
15,927✔
886
isconcretedispatch(@nospecialize t) = isconcretetype(t) && !iskindtype(t)
2,174✔
887

888
using Core: has_free_typevars
889

890
# equivalent to isa(v, Type) && isdispatchtuple(Tuple{v}) || v === Union{}
891
# and is thus perhaps most similar to the old (pre-1.0) `isconcretetype` query
892
function isdispatchelem(@nospecialize v)
893
    return (v === Bottom) || (v === typeof(Bottom)) || isconcretedispatch(v) ||
1,710✔
894
        (isType(v) && !has_free_typevars(v))
895
end
896

897
const _TYPE_NAME = Type.body.name
898
isType(@nospecialize t) = isa(t, DataType) && t.name === _TYPE_NAME
122,173✔
899

900
"""
901
    isconcretetype(T)
902

903
Determine whether type `T` is a concrete type, meaning it could have direct instances
904
(values `x` such that `typeof(x) === T`).
905
Note that this is not the negation of `isabstracttype(T)`.
906
If `T` is not a type, then return `false`.
907

908
See also: [`isbits`](@ref), [`isabstracttype`](@ref), [`issingletontype`](@ref).
909

910
# Examples
911
```jldoctest
912
julia> isconcretetype(Complex)
913
false
914

915
julia> isconcretetype(Complex{Float32})
916
true
917

918
julia> isconcretetype(Vector{Complex})
919
true
920

921
julia> isconcretetype(Vector{Complex{Float32}})
922
true
923

924
julia> isconcretetype(Union{})
925
false
926

927
julia> isconcretetype(Union{Int,String})
928
false
929
```
930
"""
931
isconcretetype(@nospecialize(t)) = (@_total_meta; isa(t, DataType) && (t.flags & 0x0002) == 0x0002)
14,991✔
932

933
"""
934
    isabstracttype(T)
935

936
Determine whether type `T` was declared as an abstract type
937
(i.e. using the `abstract type` syntax).
938
Note that this is not the negation of `isconcretetype(T)`.
939
If `T` is not a type, then return `false`.
940

941
# Examples
942
```jldoctest
943
julia> isabstracttype(AbstractArray)
944
true
945

946
julia> isabstracttype(Vector)
947
false
948
```
949
"""
950
function isabstracttype(@nospecialize(t))
951
    @_total_meta
×
952
    t = unwrap_unionall(t)
3,856✔
953
    # TODO: what to do for `Union`?
954
    return isa(t, DataType) && (t.name.flags & 0x1) == 0x1
79,805✔
955
end
956

957
function is_datatype_layoutopaque(dt::DataType)
958
    datatype_nfields(dt) == 0 && !datatype_pointerfree(dt)
4✔
959
end
960

961
function is_valid_intrinsic_elptr(@nospecialize(ety))
962
    ety === Any && return true
4✔
963
    isconcretetype(ety) || return false
4✔
964
    ety <: Array && return false
4✔
965
    return !is_datatype_layoutopaque(ety)
4✔
966
end
967

968
"""
969
    Base.issingletontype(T)
970

971
Determine whether type `T` has exactly one possible instance; for example, a
972
struct type with no fields except other singleton values.
973
If `T` is not a concrete type, then return `false`.
974
"""
975
issingletontype(@nospecialize(t)) = (@_total_meta; isa(t, DataType) && isdefined(t, :instance) && datatype_layoutsize(t) == 0 && datatype_pointerfree(t))
65,787✔
976

977
"""
978
    typeintersect(T::Type, S::Type)
979

980
Compute a type that contains the intersection of `T` and `S`. Usually this will be the
981
smallest such type or one close to it.
982

983
A special case where exact behavior is guaranteed: when `T <: S`,
984
`typeintersect(S, T) == T == typeintersect(T, S)`.
985
"""
986
typeintersect(@nospecialize(a), @nospecialize(b)) = (@_total_meta; ccall(:jl_type_intersection, Any, (Any, Any), a::Type, b::Type))
17,431✔
987

988
morespecific(@nospecialize(a), @nospecialize(b)) = (@_total_meta; ccall(:jl_type_morespecific, Cint, (Any, Any), a::Type, b::Type) != 0)
×
989
morespecific(a::Method, b::Method) = ccall(:jl_method_morespecific, Cint, (Any, Any), a, b) != 0
×
990

991
"""
992
    fieldoffset(type, i)
993

994
The byte offset of field `i` of a type relative to the data start. For example, we could
995
use it in the following manner to summarize information about a struct:
996

997
```jldoctest
998
julia> structinfo(T) = [(fieldoffset(T,i), fieldname(T,i), fieldtype(T,i)) for i = 1:fieldcount(T)];
999

1000
julia> structinfo(Base.Filesystem.StatStruct)
1001
14-element Vector{Tuple{UInt64, Symbol, Type}}:
1002
 (0x0000000000000000, :desc, Union{RawFD, String})
1003
 (0x0000000000000008, :device, UInt64)
1004
 (0x0000000000000010, :inode, UInt64)
1005
 (0x0000000000000018, :mode, UInt64)
1006
 (0x0000000000000020, :nlink, Int64)
1007
 (0x0000000000000028, :uid, UInt64)
1008
 (0x0000000000000030, :gid, UInt64)
1009
 (0x0000000000000038, :rdev, UInt64)
1010
 (0x0000000000000040, :size, Int64)
1011
 (0x0000000000000048, :blksize, Int64)
1012
 (0x0000000000000050, :blocks, Int64)
1013
 (0x0000000000000058, :mtime, Float64)
1014
 (0x0000000000000060, :ctime, Float64)
1015
 (0x0000000000000068, :ioerrno, Int32)
1016
```
1017
"""
1018
fieldoffset(x::DataType, idx::Integer) = (@_foldable_meta; ccall(:jl_get_field_offset, Csize_t, (Any, Cint), x, idx))
×
1019

1020
"""
1021
    fieldtype(T, name::Symbol | index::Int)
1022

1023
Determine the declared type of a field (specified by name or index) in a composite DataType `T`.
1024

1025
# Examples
1026
```jldoctest
1027
julia> struct Foo
1028
           x::Int64
1029
           y::String
1030
       end
1031

1032
julia> fieldtype(Foo, :x)
1033
Int64
1034

1035
julia> fieldtype(Foo, 2)
1036
String
1037
```
1038
"""
1039
fieldtype
1040

1041
"""
1042
    Base.fieldindex(T, name::Symbol, err:Bool=true)
1043

1044
Get the index of a named field, throwing an error if the field does not exist (when err==true)
1045
or returning 0 (when err==false).
1046

1047
# Examples
1048
```jldoctest
1049
julia> struct Foo
1050
           x::Int64
1051
           y::String
1052
       end
1053

1054
julia> Base.fieldindex(Foo, :z)
1055
ERROR: FieldError: type Foo has no field `z`, available fields: `x`, `y`
1056
Stacktrace:
1057
[...]
1058

1059
julia> Base.fieldindex(Foo, :z, false)
1060
0
1061
```
1062
"""
1063
function fieldindex(T::DataType, name::Symbol, err::Bool=true)
1064
    return err ? _fieldindex_maythrow(T, name) : _fieldindex_nothrow(T, name)
6,864✔
1065
end
1066

1067
function _fieldindex_maythrow(T::DataType, name::Symbol)
×
1068
    @_foldable_meta
×
1069
    @noinline
×
1070
    return Int(ccall(:jl_field_index, Cint, (Any, Any, Cint), T, name, true)+1)
×
1071
end
1072

1073
function _fieldindex_nothrow(T::DataType, name::Symbol)
6,864✔
1074
    @_total_meta
×
1075
    @noinline
×
1076
    return Int(ccall(:jl_field_index, Cint, (Any, Any, Cint), T, name, false)+1)
6,864✔
1077
end
1078

1079
function fieldindex(t::UnionAll, name::Symbol, err::Bool=true)
×
1080
    t = argument_datatype(t)
×
1081
    if t === nothing
×
1082
        err && throw(ArgumentError("type does not have definite fields"))
×
1083
        return 0
×
1084
    end
1085
    return fieldindex(t, name, err)
×
1086
end
1087

1088
function argument_datatype(@nospecialize t)
18,850✔
1089
    @_total_meta
×
1090
    @noinline
×
1091
    return ccall(:jl_argument_datatype, Any, (Any,), t)::Union{Nothing,DataType}
18,850✔
1092
end
1093

1094
function datatype_fieldcount(t::DataType)
825✔
1095
    if t.name === _NAMEDTUPLE_NAME
825✔
1096
        names, types = t.parameters[1], t.parameters[2]
10✔
1097
        if names isa Tuple
10✔
1098
            return length(names)
10✔
1099
        end
1100
        if types isa DataType && types <: Tuple
×
1101
            return fieldcount(types)
×
1102
        end
1103
        return nothing
×
1104
    elseif isabstracttype(t)
815✔
1105
        return nothing
×
1106
    end
1107
    if t.name === Tuple.name
815✔
1108
        isvatuple(t) && return nothing
404✔
1109
        return length(t.types)
404✔
1110
    end
1111
    # Equivalent to length(t.types), but `t.types` is lazy and we do not want
1112
    # to be forced to compute it.
1113
    return length(t.name.names)
411✔
1114
end
1115

1116
"""
1117
    fieldcount(t::Type)
1118

1119
Get the number of fields that an instance of the given type would have.
1120
An error is thrown if the type is too abstract to determine this.
1121
"""
1122
function fieldcount(@nospecialize t)
×
1123
    @_foldable_meta
×
1124
    if t isa UnionAll || t isa Union
×
1125
        t = argument_datatype(t)
×
1126
        if t === nothing
×
1127
            throw(ArgumentError("type does not have a definite number of fields"))
×
1128
        end
1129
    elseif t === Union{}
×
1130
        throw(ArgumentError("The empty type does not have a well-defined number of fields since it does not have instances."))
×
1131
    end
1132
    if !(t isa DataType)
×
1133
        throw(TypeError(:fieldcount, DataType, t))
×
1134
    end
1135
    fcount = datatype_fieldcount(t)
587✔
1136
    if fcount === nothing
587✔
1137
        throw(ArgumentError("type does not have a definite number of fields"))
×
1138
    end
1139
    return fcount
587✔
1140
end
1141

1142
"""
1143
    fieldtypes(T::Type)
1144

1145
The declared types of all fields in a composite DataType `T` as a tuple.
1146

1147
!!! compat "Julia 1.1"
1148
    This function requires at least Julia 1.1.
1149

1150
# Examples
1151
```jldoctest
1152
julia> struct Foo
1153
           x::Int64
1154
           y::String
1155
       end
1156

1157
julia> fieldtypes(Foo)
1158
(Int64, String)
1159
```
1160
"""
1161
fieldtypes(T::Type) = (@_foldable_meta; ntupleany(i -> fieldtype(T, i), fieldcount(T)))
×
1162

1163
# return all instances, for types that can be enumerated
1164

1165
"""
1166
    instances(T::Type)
1167

1168
Return a collection of all instances of the given type, if applicable. Mostly used for
1169
enumerated types (see `@enum`).
1170

1171
# Examples
1172
```jldoctest
1173
julia> @enum Color red blue green
1174

1175
julia> instances(Color)
1176
(red, blue, green)
1177
```
1178
"""
1179
function instances end
1180

1181
function to_tuple_type(@nospecialize(t))
2✔
1182
    if isa(t, Tuple) || isa(t, AbstractArray) || isa(t, SimpleVector)
5✔
1183
        t = Tuple{t...}
2✔
1184
    end
1185
    if isa(t, Type) && t <: Tuple
5✔
1186
        for p in (unwrap_unionall(t)::DataType).parameters
43✔
1187
            if isa(p, Core.TypeofVararg)
113✔
1188
                p = unwrapva(p)
×
1189
            end
1190
            if !(isa(p, Type) || isa(p, TypeVar))
113✔
1191
                error("argument tuple type must contain only types")
×
1192
            end
1193
        end
185✔
1194
    else
1195
        error("expected tuple type")
×
1196
    end
1197
    t
5✔
1198
end
1199

1200
function signature_type(@nospecialize(f), @nospecialize(argtypes))
2✔
1201
    argtypes = to_tuple_type(argtypes)
113✔
1202
    ft = Core.Typeof(f)
43✔
1203
    u = unwrap_unionall(argtypes)::DataType
41✔
1204
    return rewrap_unionall(Tuple{ft, u.parameters...}, argtypes)
41✔
1205
end
1206

1207
function get_methodtable(m::Method)
UNCOV
1208
    mt = ccall(:jl_method_get_table, Any, (Any,), m)
×
UNCOV
1209
    if mt === nothing
×
1210
        return nothing
×
1211
    end
UNCOV
1212
    return mt::Core.MethodTable
×
1213
end
1214

1215
"""
1216
    has_bottom_parameter(t) -> Bool
1217

1218
Determine whether `t` is a Type for which one or more of its parameters is `Union{}`.
1219
"""
1220
function has_bottom_parameter(t::DataType)
×
1221
    for p in t.parameters
×
1222
        has_bottom_parameter(p) && return true
×
1223
    end
×
1224
    return false
×
1225
end
1226
has_bottom_parameter(t::typeof(Bottom)) = true
×
1227
has_bottom_parameter(t::UnionAll) = has_bottom_parameter(unwrap_unionall(t))
×
1228
has_bottom_parameter(t::Union) = has_bottom_parameter(t.a) & has_bottom_parameter(t.b)
×
1229
has_bottom_parameter(t::TypeVar) = has_bottom_parameter(t.ub)
×
1230
has_bottom_parameter(::Any) = false
×
1231

1232
min_world(m::Core.CodeInstance) = m.min_world
8,699✔
1233
max_world(m::Core.CodeInstance) = m.max_world
8,699✔
1234
min_world(m::Core.CodeInfo) = m.min_world
×
1235
max_world(m::Core.CodeInfo) = m.max_world
×
1236

1237
"""
1238
    get_world_counter()
1239

1240
Returns the current maximum world-age counter. This counter is global and monotonically
1241
increasing.
1242
"""
1243
get_world_counter() = ccall(:jl_get_world_counter, UInt, ())
3,623✔
1244

1245
"""
1246
    tls_world_age()
1247

1248
Returns the world the [current_task()](@ref) is executing within.
1249
"""
1250
tls_world_age() = ccall(:jl_get_tls_world_age, UInt, ())
22✔
1251

1252
"""
1253
    propertynames(x, private=false)
1254

1255
Get a tuple or a vector of the properties (`x.property`) of an object `x`.
1256
This is typically the same as [`fieldnames(typeof(x))`](@ref), but types
1257
that overload [`getproperty`](@ref) should generally overload `propertynames`
1258
as well to get the properties of an instance of the type.
1259

1260
`propertynames(x)` may return only "public" property names that are part
1261
of the documented interface of `x`.   If you want it to also return "private"
1262
property names intended for internal use, pass `true` for the optional second argument.
1263
REPL tab completion on `x.` shows only the `private=false` properties.
1264

1265
See also: [`hasproperty`](@ref), [`hasfield`](@ref).
1266
"""
1267
propertynames(x) = fieldnames(typeof(x))
7✔
1268
propertynames(m::Module) = names(m)
×
1269
propertynames(x, private::Bool) = propertynames(x) # ignore private flag by default
×
1270
propertynames(x::Array) = () # hide the fields from tab completion to discourage calling `x.size` instead of `size(x)`, even though they are equivalent
×
1271

1272
"""
1273
    hasproperty(x, s::Symbol)
1274

1275
Return a boolean indicating whether the object `x` has `s` as one of its own properties.
1276

1277
!!! compat "Julia 1.2"
1278
     This function requires at least Julia 1.2.
1279

1280
See also: [`propertynames`](@ref), [`hasfield`](@ref).
1281
"""
1282
hasproperty(x, s::Symbol) = s in propertynames(x)
7✔
1283

1284
"""
1285
    delete_method(m::Method)
1286

1287
Make method `m` uncallable and force recompilation of any methods that use(d) it.
1288
"""
1289
function delete_method(m::Method)
×
1290
    ccall(:jl_method_table_disable, Cvoid, (Any, Any), get_methodtable(m), m)
×
1291
end
1292

1293

1294
# type for reflecting and pretty-printing a subset of methods
1295
mutable struct MethodList <: AbstractArray{Method,1}
1296
    ms::Array{Method,1}
×
1297
    mt::Core.MethodTable
1298
end
1299

1300
size(m::MethodList) = size(m.ms)
3✔
1301
getindex(m::MethodList, i::Integer) = m.ms[i]
×
1302

1303
function MethodList(mt::Core.MethodTable)
1304
    ms = Method[]
×
1305
    visit(mt) do m
×
1306
        push!(ms, m)
1307
    end
1308
    return MethodList(ms, mt)
×
1309
end
1310

1311
"""
1312
    methods(f, [types], [module])
1313

1314
Return the method table for `f`.
1315

1316
If `types` is specified, return an array of methods whose types match.
1317
If `module` is specified, return an array of methods defined in that module.
1318
A list of modules can also be specified as an array.
1319

1320
!!! compat "Julia 1.4"
1321
    At least Julia 1.4 is required for specifying a module.
1322

1323
See also: [`which`](@ref), [`@which`](@ref Main.InteractiveUtils.@which) and [`methodswith`](@ref Main.InteractiveUtils.methodswith).
1324
"""
1325
function methods(@nospecialize(f), @nospecialize(t),
1326
                 mod::Union{Tuple{Module},AbstractArray{Module},Nothing}=nothing)
1327
    world = get_world_counter()
×
1328
    world == typemax(UInt) && error("code reflection cannot be used from generated functions")
1329
    # Lack of specialization => a comprehension triggers too many invalidations via _collect, so collect the methods manually
1330
    ms = Method[]
1331
    for m in _methods(f, t, -1, world)::Vector
1332
        m = m::Core.MethodMatch
1333
        (mod === nothing || parentmodule(m.method) ∈ mod) && push!(ms, m.method)
1334
    end
1335
    MethodList(ms, typeof(f).name.mt)
1336
end
1337
methods(@nospecialize(f), @nospecialize(t), mod::Module) = methods(f, t, (mod,))
×
1338

1339
function methods_including_ambiguous(@nospecialize(f), @nospecialize(t))
×
1340
    tt = signature_type(f, t)
×
1341
    world = get_world_counter()
×
1342
    world == typemax(UInt) && error("code reflection cannot be used from generated functions")
×
1343
    min = RefValue{UInt}(typemin(UInt))
×
1344
    max = RefValue{UInt}(typemax(UInt))
×
1345
    ms = _methods_by_ftype(tt, nothing, -1, world, true, min, max, Ptr{Int32}(C_NULL))::Vector
×
1346
    return MethodList(Method[(m::Core.MethodMatch).method for m in ms], typeof(f).name.mt)
×
1347
end
1348

1349
function methods(@nospecialize(f),
1350
                 mod::Union{Module,AbstractArray{Module},Nothing}=nothing)
1351
    # return all matches
1352
    return methods(f, Tuple{Vararg{Any}}, mod)
6✔
1353
end
1354

1355
# low-level method lookup functions used by the compiler
1356

1357
unionlen(@nospecialize(x)) = x isa Union ? unionlen(x.a) + unionlen(x.b) : 1
1,386✔
1358

1359
function _uniontypes(@nospecialize(x), ts::Array{Any,1})
548✔
1360
    if x isa Union
548✔
1361
        _uniontypes(x.a, ts)
170✔
1362
        _uniontypes(x.b, ts)
170✔
1363
    else
1364
        push!(ts, x)
378✔
1365
    end
1366
    return ts
548✔
1367
end
1368
uniontypes(@nospecialize(x)) = _uniontypes(x, Any[])
138✔
1369

1370
function _methods(@nospecialize(f), @nospecialize(t), lim::Int, world::UInt)
×
1371
    tt = signature_type(f, t)
×
1372
    return _methods_by_ftype(tt, lim, world)
×
1373
end
1374

1375
function _methods_by_ftype(@nospecialize(t), lim::Int, world::UInt)
1376
    return _methods_by_ftype(t, nothing, lim, world)
×
1377
end
1378
function _methods_by_ftype(@nospecialize(t), mt::Union{Core.MethodTable, Nothing}, lim::Int, world::UInt)
1379
    return _methods_by_ftype(t, mt, lim, world, false, RefValue{UInt}(typemin(UInt)), RefValue{UInt}(typemax(UInt)), Ptr{Int32}(C_NULL))
×
1380
end
1381
function _methods_by_ftype(@nospecialize(t), mt::Union{Core.MethodTable, Nothing}, lim::Int, world::UInt, ambig::Bool, min::Ref{UInt}, max::Ref{UInt}, has_ambig::Ref{Int32})
1382
    return ccall(:jl_matching_methods, Any, (Any, Any, Cint, Cint, UInt, Ptr{UInt}, Ptr{UInt}, Ptr{Int32}), t, mt, lim, ambig, world, min, max, has_ambig)::Union{Vector{Any},Nothing}
8,008✔
1383
end
1384

1385
hasgenerator(m::Method) = isdefined(m, :generator)
1,078✔
1386
hasgenerator(m::Core.MethodInstance) = hasgenerator(m.def::Method)
×
1387

1388
function _uncompressed_ir(m::Method)
UNCOV
1389
    s = m.source
×
UNCOV
1390
    if s isa String
×
UNCOV
1391
        s = ccall(:jl_uncompress_ir, Ref{CodeInfo}, (Any, Ptr{Cvoid}, Any), m, C_NULL, s)
×
1392
    end
UNCOV
1393
    return s::CodeInfo
×
1394
end
1395

1396
_uncompressed_ir(codeinst::CodeInstance, s::String) =
7,046✔
1397
    ccall(:jl_uncompress_ir, Ref{CodeInfo}, (Any, Any, Any), codeinst.def.def::Method, codeinst, s)
1398

1399
"""
1400
    Base.generating_output([incremental::Bool])::Bool
1401

1402
Return `true` if the current process is being used to pre-generate a
1403
code cache via any of the `--output-*` command line arguments. The optional
1404
`incremental` argument further specifies the precompilation mode: when set
1405
to `true`, the function will return `true` only for package precompilation;
1406
when set to `false`, it will return `true` only for system image generation.
1407

1408
!!! compat "Julia 1.11"
1409
    This function requires at least Julia 1.11.
1410
"""
1411
function generating_output(incremental::Union{Bool,Nothing}=nothing)
1412
    ccall(:jl_generating_output, Cint, ()) == 0 && return false
12,845✔
1413
    if incremental !== nothing
×
1414
        JLOptions().incremental == incremental || return false
×
1415
    end
1416
    return true
×
1417
end
1418

1419
const SLOT_USED = 0x8
1420
ast_slotflag(@nospecialize(code), i) = ccall(:jl_ir_slotflag, UInt8, (Any, Csize_t), code, i - 1)
×
1421

1422
"""
1423
    may_invoke_generator(method, atype, sparams) -> Bool
1424

1425
Computes whether or not we may invoke the generator for the given `method` on
1426
the given `atype` and `sparams`. For correctness, all generated function are
1427
required to return monotonic answers. However, since we don't expect users to
1428
be able to successfully implement this criterion, we only call generated
1429
functions on concrete types. The one exception to this is that we allow calling
1430
generators with abstract types if the generator does not use said abstract type
1431
(and thus cannot incorrectly use it to break monotonicity). This function
1432
computes whether we are in either of these cases.
1433

1434
Unlike normal functions, the compilation heuristics still can't generate good dispatch
1435
in some cases, but this may still allow inference not to fall over in some limited cases.
1436
"""
1437
function may_invoke_generator(mi::MethodInstance)
1438
    return may_invoke_generator(mi.def::Method, mi.specTypes, mi.sparam_vals)
×
1439
end
1440
function may_invoke_generator(method::Method, @nospecialize(atype), sparams::SimpleVector)
×
1441
    # If we have complete information, we may always call the generator
1442
    isdispatchtuple(atype) && return true
×
1443

1444
    # We don't have complete information, but it is possible that the generator
1445
    # syntactically doesn't make use of the information we don't have. Check
1446
    # for that.
1447

1448
    # For now, only handle the (common, generated by the frontend case) that the
1449
    # generator only has one method
1450
    generator = method.generator
×
1451
    isa(generator, Core.GeneratedFunctionStub) || return false
×
1452
    tt = Tuple{typeof(generator.gen), Vararg{Any}}
×
1453
    gen_mthds = _methods_by_ftype(tt, #=lim=#1, method.primary_world)
×
1454
    gen_mthds isa Vector || return false
×
1455
    length(gen_mthds) == 1 || return false
×
1456

1457
    generator_method = (first(gen_mthds)::Core.MethodMatch).method
×
1458
    nsparams = length(sparams)
×
1459
    isdefined(generator_method, :source) || return false
×
1460
    code = generator_method.source
×
1461
    nslots = ccall(:jl_ir_nslots, Int, (Any,), code)
×
1462
    at = unwrap_unionall(atype)
×
1463
    at isa DataType || return false
×
1464
    (nslots >= 1 + length(sparams) + length(at.parameters)) || return false
×
1465

1466
    firstarg = 1
×
1467
    for i = 1:nsparams
×
1468
        if isa(sparams[i], TypeVar)
×
1469
            if (ast_slotflag(code, firstarg + i) & SLOT_USED) != 0
×
1470
                return false
×
1471
            end
1472
        end
1473
    end
×
1474
    nargs = Int(method.nargs)
×
1475
    non_va_args = method.isva ? nargs - 1 : nargs
×
1476
    for i = 1:non_va_args
×
1477
        if !isdispatchelem(at.parameters[i])
×
1478
            if (ast_slotflag(code, firstarg + i + nsparams) & SLOT_USED) != 0
×
1479
                return false
×
1480
            end
1481
        end
1482
    end
×
1483
    if method.isva
×
1484
        # If the va argument is used, we need to ensure that all arguments that
1485
        # contribute to the va tuple are dispatchelemes
1486
        if (ast_slotflag(code, firstarg + nargs + nsparams) & SLOT_USED) != 0
×
1487
            for i = (non_va_args+1):length(at.parameters)
×
1488
                if !isdispatchelem(at.parameters[i])
×
1489
                    return false
×
1490
                end
1491
            end
×
1492
        end
1493
    end
1494
    return true
×
1495
end
1496

1497
# get a handle to the unique specialization object representing a particular instantiation of a call
1498
# eliminate UnionAll vars that might be degenerate due to having identical bounds,
1499
# or a concrete upper bound and appearing covariantly.
1500
function subst_trivial_bounds(@nospecialize(atype))
×
1501
    if !isa(atype, UnionAll)
×
1502
        return atype
×
1503
    end
1504
    v = atype.var
×
1505
    if isconcretetype(v.ub) || v.lb === v.ub
×
1506
        subst = try
×
1507
            atype{v.ub}
×
1508
        catch
1509
            # Note in rare cases a var bound might not be valid to substitute.
1510
            nothing
×
1511
        end
1512
        if subst !== nothing
×
1513
            return subst_trivial_bounds(subst)
×
1514
        end
1515
    end
1516
    return UnionAll(v, subst_trivial_bounds(atype.body))
×
1517
end
1518

1519
# If removing trivial vars from atype results in an equivalent type, use that
1520
# instead. Otherwise we can get a case like issue #38888, where a signature like
1521
#   f(x::S) where S<:Int
1522
# gets cached and matches a concrete dispatch case.
1523
function normalize_typevars(method::Method, @nospecialize(atype), sparams::SimpleVector)
×
1524
    at2 = subst_trivial_bounds(atype)
×
1525
    if at2 !== atype && at2 == atype
×
1526
        atype = at2
×
1527
        sp_ = ccall(:jl_type_intersection_with_env, Any, (Any, Any), at2, method.sig)::SimpleVector
×
1528
        sparams = sp_[2]::SimpleVector
×
1529
    end
1530
    return Pair{Any,SimpleVector}(atype, sparams)
×
1531
end
1532

1533
function get_nospecializeinfer_sig(method::Method, @nospecialize(atype), sparams::SimpleVector)
UNCOV
1534
    isa(atype, DataType) || return method.sig
×
UNCOV
1535
    mt = ccall(:jl_method_get_table, Any, (Any,), method)
×
UNCOV
1536
    mt === nothing && return method.sig
×
UNCOV
1537
    return ccall(:jl_normalize_to_compilable_sig, Any, (Any, Any, Any, Any, Cint),
×
1538
        mt, atype, sparams, method, #=int return_if_compileable=#0)
1539
end
1540

UNCOV
1541
is_nospecialized(method::Method) = method.nospecialize ≠ 0
×
1542
is_nospecializeinfer(method::Method) = method.nospecializeinfer && is_nospecialized(method)
37,374✔
1543
function specialize_method(method::Method, @nospecialize(atype), sparams::SimpleVector; preexisting::Bool=false)
30,216✔
1544
    @inline
×
1545
    if isa(atype, UnionAll)
28,509✔
1546
        atype, sparams = normalize_typevars(method, atype, sparams)
×
1547
    end
1548
    if is_nospecializeinfer(method)
28,509✔
UNCOV
1549
        atype = get_nospecializeinfer_sig(method, atype, sparams)
×
1550
    end
1551
    if preexisting
28,509✔
1552
        # check cached specializations
1553
        # for an existing result stored there
1554
        return ccall(:jl_specializations_lookup, Any, (Any, Any), method, atype)::Union{Nothing,MethodInstance}
13,975✔
1555
    end
1556
    return ccall(:jl_specializations_get_linfo, Ref{MethodInstance}, (Any, Any, Any), method, atype, sparams)
14,534✔
1557
end
1558

1559
function specialize_method(match::Core.MethodMatch; kwargs...)
35,282✔
1560
    return specialize_method(match.method, match.spec_types, match.sparams; kwargs...)
19,600✔
1561
end
1562

1563
hasintersect(@nospecialize(a), @nospecialize(b)) = typeintersect(a, b) !== Bottom
14,535✔
1564

1565
###########
1566
# scoping #
1567
###########
1568

1569
_topmod(m::Module) = ccall(:jl_base_relative_to, Any, (Any,), m)::Module
759✔
1570

1571

1572
# high-level, more convenient method lookup functions
1573

1574
function visit(f, mt::Core.MethodTable)
NEW
1575
    mt.defs !== nothing && visit(f, mt.defs)
×
NEW
1576
    nothing
×
1577
end
NEW
1578
function visit(f, mc::Core.TypeMapLevel)
×
NEW
1579
    function avisit(f, e::Memory{Any})
×
NEW
1580
        for i in 2:2:length(e)
×
NEW
1581
            isassigned(e, i) || continue
×
NEW
1582
            ei = e[i]
×
NEW
1583
            if ei isa Memory{Any}
×
NEW
1584
                for j in 2:2:length(ei)
×
NEW
1585
                    isassigned(ei, j) || continue
×
NEW
1586
                    visit(f, ei[j])
×
NEW
1587
                end
×
1588
            else
NEW
1589
                visit(f, ei)
×
1590
            end
NEW
1591
        end
×
1592
    end
NEW
1593
    if mc.targ !== nothing
×
NEW
1594
        avisit(f, mc.targ::Memory{Any})
×
1595
    end
NEW
1596
    if mc.arg1 !== nothing
×
NEW
1597
        avisit(f, mc.arg1::Memory{Any})
×
1598
    end
NEW
1599
    if mc.tname !== nothing
×
NEW
1600
        avisit(f, mc.tname::Memory{Any})
×
1601
    end
NEW
1602
    if mc.name1 !== nothing
×
NEW
1603
        avisit(f, mc.name1::Memory{Any})
×
1604
    end
NEW
1605
    mc.list !== nothing && visit(f, mc.list)
×
NEW
1606
    mc.any !== nothing && visit(f, mc.any)
×
NEW
1607
    nothing
×
1608
end
NEW
1609
function visit(f, d::Core.TypeMapEntry)
×
NEW
1610
    while d !== nothing
×
NEW
1611
        f(d.func)
×
NEW
1612
        d = d.next
×
NEW
1613
    end
×
NEW
1614
    nothing
×
1615
end
1616
struct MethodSpecializations
1617
    specializations::Union{Nothing, Core.MethodInstance, Core.SimpleVector}
1618
end
1619
"""
1620
    specializations(m::Method) → itr
1621

1622
Return an iterator `itr` of all compiler-generated specializations of `m`.
1623
"""
NEW
1624
specializations(m::Method) = MethodSpecializations(isdefined(m, :specializations) ? m.specializations : nothing)
×
NEW
1625
function iterate(specs::MethodSpecializations)
×
NEW
1626
    s = specs.specializations
×
NEW
1627
    s === nothing && return nothing
×
NEW
1628
    isa(s, Core.MethodInstance) && return (s, nothing)
×
NEW
1629
    return iterate(specs, 0)
×
1630
end
NEW
1631
iterate(specs::MethodSpecializations, ::Nothing) = nothing
×
NEW
1632
function iterate(specs::MethodSpecializations, i::Int)
×
NEW
1633
    s = specs.specializations::Core.SimpleVector
×
NEW
1634
    n = length(s)
×
NEW
1635
    i >= n && return nothing
×
NEW
1636
    item = nothing
×
NEW
1637
    while i < n && item === nothing
×
NEW
1638
        item = s[i+=1]
×
NEW
1639
    end
×
NEW
1640
    item === nothing && return nothing
×
NEW
1641
    return (item, i)
×
1642
end
NEW
1643
length(specs::MethodSpecializations) = count(Returns(true), specs)
×
1644

NEW
1645
function length(mt::Core.MethodTable)
×
NEW
1646
    n = 0
×
NEW
1647
    visit(mt) do m
×
NEW
1648
        n += 1
×
1649
    end
NEW
1650
    return n::Int
×
1651
end
NEW
1652
isempty(mt::Core.MethodTable) = (mt.defs === nothing)
×
1653

NEW
1654
uncompressed_ir(m::Method) = isdefined(m, :source) ? _uncompressed_ir(m) :
×
1655
                             isdefined(m, :generator) ? error("Method is @generated; try `code_lowered` instead.") :
1656
                             error("Code for this Method is not available.")
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