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

JuliaLang / julia / 1431

05 Feb 2026 12:37AM UTC coverage: 76.655% (-0.07%) from 76.729%
1431

push

buildkite

web-flow
doc: Clarify policy on working on issues i.e. anti-cookie licking (#60925)

62930 of 82095 relevant lines covered (76.66%)

23295584.69 hits per line

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

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

3
"""
4
    code_lowered(f, types; generated=true, debuginfo=:default)
5

6
Return an array of the lowered forms (IR) for the methods matching the given generic function
7
and type signature.
8

9
If `generated` is `false`, the returned `CodeInfo` instances will correspond to fallback
10
implementations. An error is thrown if no fallback implementation exists.
11
If `generated` is `true`, these `CodeInfo` instances will correspond to the method bodies
12
yielded by expanding the generators.
13

14
The keyword `debuginfo` controls the amount of code metadata present in the output.
15

16
Note that an error will be thrown if `types` are not concrete types when `generated` is
17
`true` and any of the corresponding methods are an `@generated` method.
18
"""
19
function code_lowered(@nospecialize(argtypes::Union{Tuple,Type{<:Tuple}}); generated::Bool=true, debuginfo::Symbol=:default)
147✔
20
    if @isdefined(IRShow)
21✔
21
        debuginfo = IRShow.debuginfo(debuginfo)
21✔
22
    elseif debuginfo === :default
×
23
        debuginfo = :source
×
24
    end
25
    if debuginfo !== :source && debuginfo !== :none
21✔
26
        throw(ArgumentError("'debuginfo' must be either :source or :none"))
×
27
    end
28
    world = get_world_counter()
21✔
29
    world == typemax(UInt) && error("code reflection cannot be used from generated functions")
21✔
30
    ret = CodeInfo[]
18✔
31
    for m in method_instances(argtypes, world)
18✔
32
        if generated && hasgenerator(m)
18✔
33
            if may_invoke_generator(m)
9✔
34
                code = ccall(:jl_code_for_staged, Ref{CodeInfo}, (Any, UInt, Ptr{Cvoid}), m, world, C_NULL)
9✔
35
            else
36
                error("Could not expand generator for `@generated` method ", m, ". ",
×
37
                      "This can happen if the provided argument types (", t, ") are ",
38
                      "not concrete types, but the `generated` argument is `true`.")
39
            end
40
        else
41
            code = uncompressed_ir(m.def::Method)
9✔
42
            debuginfo === :none && remove_linenums!(code)
9✔
43
        end
44
        push!(ret, code)
18✔
45
    end
18✔
46
    return ret
18✔
47
end
48

49
function code_lowered(@nospecialize(f), @nospecialize(t=Tuple); generated::Bool=true, debuginfo::Symbol=:default)
78✔
50
    tt = signature_type(f, t)
45✔
51
    return code_lowered(tt; generated, debuginfo)
87✔
52
end
53

54
# for backwards compat
55
const uncompressed_ast = uncompressed_ir
56
const _uncompressed_ast = _uncompressed_ir
57

58
function method_instances(@nospecialize(argtypes::Union{Tuple,Type{<:Tuple}}), world::UInt)
18✔
59
    tt = to_tuple_type(argtypes)
36✔
60
    results = Core.MethodInstance[]
18✔
61
    # this make a better error message than the typeassert that follows
62
    world == typemax(UInt) && error("code reflection cannot be used from generated functions")
18✔
63
    for match in _methods_by_ftype(tt, -1, world)::Vector
18✔
64
        instance = specialize_method(match::Core.MethodMatch)
18✔
65
        push!(results, instance)
18✔
66
    end
18✔
67
    return results
18✔
68
end
69

70
function method_instances(@nospecialize(f), @nospecialize(t), world::UInt)
×
71
    tt = signature_type(f, t)
×
72
    return method_instances(tt, world)
×
73
end
74

75
function method_instance(@nospecialize(argtypes::Union{Tuple,Type{<:Tuple}});
18✔
76
                         world=Base.get_world_counter(), method_table=nothing)
77
    tt = to_tuple_type(argtypes)
12✔
78
    mi = ccall(:jl_method_lookup_by_tt, Any,
6✔
79
                (Any, Csize_t, Any),
80
                tt, world, method_table)
81
    return mi::Union{Nothing, MethodInstance}
6✔
82
end
83

84
function method_instance(@nospecialize(f), @nospecialize(t);
6✔
85
                         world=Base.get_world_counter(), method_table=nothing)
86
    tt = signature_type(f, t)
6✔
87
    return method_instance(tt; world, method_table)
12✔
88
end
89

90
default_debug_info_kind() = unsafe_load(cglobal(:jl_default_debug_info_kind, Cint))
129✔
91

92
# this type mirrors jl_cgparams_t (documented in julia.h)
93
struct CodegenParams
94
    """
95
    If enabled, generate the necessary code to support the --track-allocations
96
    command line flag to julia itself. Note that the option itself does not enable
97
    allocation tracking. Rather, it merely generates the support code necessary
98
    to perform allocation tracking if requested by the command line option.
99
    """
100
    track_allocations::Cint
101

102
    """
103
    If enabled, generate the necessary code to support the --code-coverage
104
    command line flag to julia itself. Note that the option itself does not enable
105
    code coverage. Rather, it merely generates the support code necessary
106
    to code coverage if requested by the command line option.
107
    """
108
    code_coverage::Cint
109

110
    """
111
    If enabled, force the compiler to use the specialized signature
112
    for all generated functions, whenever legal. If disabled, the choice is made
113
    heuristically and specsig is only used when deemed profitable.
114
    """
115
    prefer_specsig::Cint
116

117
    """
118
    If enabled, enable emission of `.debug_names` sections.
119
    """
120
    gnu_pubnames::Cint
121

122
    """
123
    Controls what level of debug info to emit. Currently supported values are:
124
    - 0: no debug info
125
    - 1: full debug info
126
    - 2: Line tables only
127
    - 3: Debug directives only
128

129
    The integer values currently match the llvm::DICompilerUnit::DebugEmissionKind enum,
130
    although this is not guaranteed.
131
    """
132
    debug_info_kind::Cint
133

134
    """
135
    Controls the debug_info_level parameter, equivalent to the -g command line option.
136
    """
137
    debug_info_level::Cint
138

139
    """
140
    If enabled, generate a GC safepoint at the entry to every function. Emitting
141
    these extra safepoints can reduce the amount of time that other threads are
142
    waiting for the currently running thread to reach a safepoint. The cost for
143
    a safepoint is small, but non-zero. The option is enabled by default.
144
    """
145
    safepoint_on_entry::Cint
146

147
    """
148
    If enabled, add an implicit argument to each function call that is used to
149
    pass down the current task local state pointer. This argument is passed
150
    using the `swiftself` convention, which in the ordinary case means that the
151
    pointer is kept in a register and accesses are thus very fast. If this option
152
    is disabled, the task local state pointer must be loaded from thread local
153
    storage, which incurs a small amount of additional overhead. The option is enabled by
154
    default.
155
    """
156
    gcstack_arg::Cint
157

158
    """
159
    If enabled, use the Julia PLT mechanism to support lazy-resolution of `ccall`
160
    targets. The option may be disabled for use in environments where the julia
161
    runtime is unavailable, but is otherwise recommended to be enabled, even if
162
    lazy resolution is not required, as the Julia PLT mechanism may have superior
163
    performance compared to the native platform mechanism. The options is enabled by default.
164
    """
165
    use_jlplt::Cint
166

167
    """
168
        If enabled emit LLVM IR for all functions even if wouldn't be compiled
169
        for some reason (i.e functions that return a constant value).
170
    """
171
    force_emit_all::Cint
172

173
    """
174
    When enabled, run the MemorySanitizer pass.
175
    """
176
    sanitize_memory::Cint
177
    """
178
    When enabled, run the ThreadSanitizer pass.
179
    """
180
    sanitize_thread::Cint
181
    """
182
    When enabled, run the AddressSanitizer pass.
183
    """
184
    sanitize_address::Cint
185

186
    function CodegenParams(; track_allocations::Bool=true, code_coverage::Bool=true,
483✔
187
                   prefer_specsig::Bool=false,
188
                   gnu_pubnames::Bool=true, debug_info_kind::Cint = default_debug_info_kind(),
189
                   debug_info_level::Cint = Cint(JLOptions().debug_level), safepoint_on_entry::Bool=true,
190
                   gcstack_arg::Bool=true, use_jlplt::Bool=true, force_emit_all::Bool=false,
191
                   sanitize_memory::Bool=false, sanitize_thread::Bool=false, sanitize_address::Bool=false)
192
        return new(
171✔
193
            Cint(track_allocations), Cint(code_coverage),
194
            Cint(prefer_specsig),
195
            Cint(gnu_pubnames), debug_info_kind,
196
            debug_info_level, Cint(safepoint_on_entry),
197
            Cint(gcstack_arg), Cint(use_jlplt), Cint(force_emit_all),
198
            Cint(sanitize_memory), Cint(sanitize_thread), Cint(sanitize_address))
199
    end
200
end
201

202
# this type mirrors jl_emission_params_t (documented in julia.h)
203
struct EmissionParams
204
    emit_metadata::Cint
205

206
    function EmissionParams(; emit_metadata::Bool=true)
×
207
        return new(Cint(emit_metadata))
×
208
    end
209
end
210

211
"""
212
    code_typed(f, types; kw...)
213

214
Return an array of type-inferred lowered form (IR) for the methods matching the given
215
generic function and type signature.
216

217
# Keyword Arguments
218

219
- `optimize::Bool = true`: optional, controls whether additional optimizations,
220
  such as inlining, are also applied.
221
- `debuginfo::Symbol = :default`: optional, controls the amount of code metadata present
222
  in the output, possible options are `:source` or `:none`.
223

224
# Internal Keyword Arguments
225

226
This section should be considered internal, and is only for who understands Julia compiler
227
internals.
228

229
- `world::UInt = Base.get_world_counter()`: optional, controls the world age to use
230
  when looking up methods, use current world age if not specified.
231
- `interp::Core.Compiler.AbstractInterpreter = Core.Compiler.NativeInterpreter(world)`:
232
  optional, controls the abstract interpreter to use, use the native interpreter if not specified.
233

234
# Examples
235

236
One can put the argument types in a tuple to get the corresponding `code_typed`.
237

238
```julia
239
julia> code_typed(+, (Float64, Float64))
240
1-element Vector{Any}:
241
 CodeInfo(
242
1 ─ %1 = Base.add_float(x, y)::Float64
243
└──      return %1
244
) => Float64
245

246
julia> code_typed((typeof(-), Float64, Float64))
247
1-element Vector{Any}:
248
 CodeInfo(
249
1 ─ %1 = Base.sub_float(x, y)::Float64
250
└──      return %1
251
) => Float64
252

253
julia> code_typed((Type{Int}, UInt8))
254
1-element Vector{Any}:
255
 CodeInfo(
256
1 ─ %1 = Core.zext_int(Core.Int64, x)::Int64
257
└──      return %1
258
) => Int64
259

260
julia> code_typed((Returns{Int64},))
261
1-element Vector{Any}:
262
 CodeInfo(
263
1 ─ %1 =   builtin Base.getfield(obj, :value)::Int64
264
└──      return %1
265
) => Int64
266
```
267
"""
268
function code_typed end
269

270
function code_typed(@nospecialize(f), @nospecialize(types=default_tt(f)); kwargs...)
342✔
271
    if isa(f, Core.OpaqueClosure)
255✔
272
        return code_typed_opaque_closure(f, types; kwargs...)
3✔
273
    end
274
    tt = signature_type(f, types)
255✔
275
    return code_typed_by_type(tt; kwargs...)
252✔
276
end
277

278
# support queries with signatures rather than objects to better support
279
# non-singleton function objects such as `(::Foo)(::Int, ::Int)`
280
# via `code_typed((Foo, Int, Int))` or `code_typed(Tuple{Foo, Int, Int})`.
281
function code_typed(@nospecialize(argtypes::Union{Tuple,Type{<:Tuple}}); kwargs...)
165✔
282
    tt = to_tuple_type(argtypes)
144✔
283
    return code_typed_by_type(tt; kwargs...)
81✔
284
end
285

286
# returns argument tuple type which is supposed to be used for `code_typed` and its family;
287
# if there is a single method this functions returns the method argument signature,
288
# otherwise returns `Tuple` that doesn't match with any signature
289
function default_tt(@nospecialize(f))
290
    ms = methods(f)
162✔
291
    if length(ms) == 1
162✔
292
        return tuple_type_tail(only(ms).sig)
162✔
293
    else
294
        return Tuple
×
295
    end
296
end
297

298
function raise_match_failure(name::Symbol, @nospecialize(tt))
×
299
    @noinline
×
300
    sig_str = sprint(Base.show_tuple_as_call, Symbol(""), tt)
×
301
    error("$name: unanalyzable call given $sig_str")
×
302
end
303

304
const REFLECTION_COMPILER = RefValue{Union{Nothing, Module}}(nothing)
305

306
function invoke_in_typeinf_world(args...)
307
    vargs = Any[args...]
254✔
308
    return ccall(:jl_call_in_typeinf_world, Any, (Ptr{Any}, Cint), vargs, length(vargs))
127✔
309
end
310

311
function invoke_default_compiler(fname::Symbol, args...)
1,298,350✔
312
    if REFLECTION_COMPILER[] === nothing
1,298,350✔
313
        return invoke_in_typeinf_world(getglobal(Compiler, fname), args...)
1,296,588✔
314
    else
315
        return getglobal(REFLECTION_COMPILER[], fname)(args...)
1,762✔
316
    end
317
end
318

319
function invoke_interp_compiler(interp, fname::Symbol, args...)
1,938,295✔
320
    if interp === nothing
1,938,544✔
321
        return invoke_default_compiler(fname, args...)
1,937,974✔
322
    else
323
        T = typeof(interp)
570✔
324
        while true
1,140✔
325
            Tname = typename(T).name
1,140✔
326
            Tname === :Any && error("Expected AbstractInterpreter")
1,140✔
327
            Tname === :AbstractInterpreter && break
1,140✔
328
            T = supertype(T)
1,140✔
329
        end
570✔
330
        return getglobal(typename(T).module, fname)(args...)
570✔
331
    end
332
end
333

334
function invoke_mt_compiler(mt, fname::Symbol, args...)
335
    if mt === nothing
36✔
336
        return invoke_default_compiler(fname, args...)
36✔
337
    else
338
        T = typeof(mt)
×
339
        while true
×
340
            Tname = typename(T).name
×
341
            Tname === :Any && error("Expected MethodTableView")
×
342
            Tname === :MethodTableView && break
×
343
            T = supertype(T)
×
344
        end
×
345
        return getglobal(typename(T).module, fname)(args...)
×
346
    end
347
end
348

349
"""
350
    code_typed_by_type(types::Type{<:Tuple}; ...)
351

352
Similar to [`code_typed`](@ref), except the argument is a tuple type describing
353
a full signature to query.
354
"""
355
function code_typed_by_type(@nospecialize(tt::Type);
402✔
356
                            optimize::Bool=true,
357
                            debuginfo::Symbol=:default,
358
                            world::UInt=get_world_counter(),
359
                            interp=nothing)
360
    passed_interp = interp
69✔
361
    interp = passed_interp === nothing ? invoke_default_compiler(:_default_interp, world) : interp
69✔
362
    (ccall(:jl_is_in_pure_context, Bool, ()) || world == typemax(UInt)) &&
69✔
363
        error("code reflection cannot be used from generated functions")
364
    if @isdefined(IRShow)
66✔
365
        debuginfo = IRShow.debuginfo(debuginfo)
66✔
366
    elseif debuginfo === :default
×
367
        debuginfo = :source
×
368
    end
369
    if debuginfo !== :source && debuginfo !== :none
66✔
370
        throw(ArgumentError("'debuginfo' must be either :source or :none"))
×
371
    end
372
    tt = to_tuple_type(tt)
66✔
373
    matches = invoke_interp_compiler(passed_interp, :_findall_matches, interp, tt)
66✔
374
    matches === nothing && raise_match_failure(:code_typed, tt)
66✔
375
    asts = []
66✔
376
    for match in matches.matches
66✔
377
        match = match::Core.MethodMatch
66✔
378
        code = invoke_interp_compiler(passed_interp, :typeinf_code, interp, match, optimize)
66✔
379
        if code === nothing
63✔
380
            push!(asts, match.method => Any)
×
381
        else
382
            debuginfo === :none && remove_linenums!(code)
63✔
383
            push!(asts, code => code.rettype)
63✔
384
        end
385
    end
63✔
386
    return asts
63✔
387
end
388

389
function get_oc_code_rt(passed_interp, oc::Core.OpaqueClosure, types, optimize::Bool)
×
390
    @nospecialize oc types
×
391
    ccall(:jl_is_in_pure_context, Bool, ()) &&
×
392
        error("code reflection cannot be used from generated functions")
393
    m = oc.source
×
394
    if isa(m, Method)
×
395
        if isdefined(m, :source)
×
396
            if optimize
×
397
                tt = Tuple{typeof(oc.captures), to_tuple_type(types).parameters...}
×
398
                mi = specialize_method(m, tt, Core.svec())
×
399
                interp = invoke_interp_compiler(passed_interp, :_default_interp, m.primary_world)
×
400
                code = invoke_interp_compiler(passed_interp, :typeinf_code, interp, mi, optimize)
×
401
                if code isa CodeInfo
×
402
                    return Pair{CodeInfo, Any}(code, code.rettype)
×
403
                end
404
                error("inference not successful")
×
405
            else
406
                code = _uncompressed_ir(m)
×
407
                return Pair{CodeInfo, Any}(code, typeof(oc).parameters[2])
×
408
            end
409
        else
410
            # OC constructed from optimized IR
411
            codeinst = m.specializations.cache
×
412
            # XXX: the inferred field is not normally a CodeInfo, but this assumes it is guaranteed to be always
413
            return Pair{CodeInfo, Any}(codeinst.inferred, codeinst.rettype)
×
414
        end
415
    else
416
        error("encountered invalid Core.OpaqueClosure object")
×
417
    end
418
end
419

420
function code_typed_opaque_closure(oc::Core.OpaqueClosure, types;
6✔
421
                                   debuginfo::Symbol=:default,
422
                                   optimize::Bool=true,
423
                                   interp=nothing,
424
                                   _...)
425
    @nospecialize oc types
6✔
426
    (code, rt) = get_oc_code_rt(interp, oc, types, optimize)
6✔
427
    debuginfo === :none && remove_linenums!(code)
6✔
428
    return Any[Pair{CodeInfo,Any}(code, rt)]
6✔
429
end
430

431
"""
432
    code_ircode(f, [types])
433

434
Return an array of pairs of `IRCode` and inferred return type if type inference succeeds.
435
The `Method` is included instead of `IRCode` otherwise.
436

437
See also: [`code_typed`](@ref)
438

439
# Internal Keyword Arguments
440

441
This section should be considered internal, and is only for who understands Julia compiler
442
internals.
443

444
- `world::UInt = Base.get_world_counter()`: optional, controls the world age to use
445
  when looking up methods, use current world age if not specified.
446
- `interp::Core.Compiler.AbstractInterpreter = Core.Compiler.NativeInterpreter(world)`:
447
  optional, controls the abstract interpreter to use, use the native interpreter if not specified.
448
- `optimize_until::Union{Int,String,Nothing} = nothing`: optional,
449
  controls the optimization passes to run.
450
  If it is a string, it specifies the name of the pass up to which the optimizer is run.
451
  If it is an integer, it specifies the number of passes to run.
452
  If it is `nothing` (default), all passes are run.
453

454
# Examples
455

456
One can put the argument types in a tuple to get the corresponding `code_ircode`.
457

458
```julia
459
julia> Base.code_ircode(+, (Float64, Int64))
460
1-element Vector{Any}:
461
 388 1 ─ %1 = Base.sitofp(Float64, _3)::Float64
462
    │   %2 = Base.add_float(_2, %1)::Float64
463
    └──      return %2
464
     => Float64
465

466
julia> Base.code_ircode(+, (Float64, Int64); optimize_until = "compact 1")
467
1-element Vector{Any}:
468
 388 1 ─ %1 = Base.promote(_2, _3)::Tuple{Float64, Float64}
469
    │   %2 = Core._apply_iterate(Base.iterate, Base.:+, %1)::Float64
470
    └──      return %2
471
     => Float64
472
```
473
"""
474
function code_ircode(@nospecialize(f), @nospecialize(types = default_tt(f)); kwargs...)
153✔
475
    if isa(f, Core.OpaqueClosure)
135✔
476
        error("OpaqueClosure not supported")
×
477
    end
478
    tt = signature_type(f, types)
135✔
479
    return code_ircode_by_type(tt; kwargs...)
135✔
480
end
481

482
function code_ircode(@nospecialize(argtypes::Union{Tuple,Type{<:Tuple}}); kwargs...)
42✔
483
    tt = to_tuple_type(argtypes)
24✔
484
    return code_ircode_by_type(tt; kwargs...)
21✔
485
end
486

487
"""
488
    code_ircode_by_type(types::Type{<:Tuple}; ...)
489

490
Similar to [`code_ircode`](@ref), except the argument is a tuple type describing
491
a full signature to query.
492
"""
493
function code_ircode_by_type(
255✔
494
    @nospecialize(tt::Type);
495
    world::UInt=get_world_counter(),
496
    interp=nothing,
497
    optimize_until::Union{Int,String,Nothing}=nothing,
498
)
499
    passed_interp = interp
99✔
500
    interp = passed_interp === nothing ? invoke_default_compiler(:_default_interp, world) : interp
99✔
501
    (ccall(:jl_is_in_pure_context, Bool, ()) || world == typemax(UInt)) &&
99✔
502
        error("code reflection cannot be used from generated functions")
503
    tt = to_tuple_type(tt)
99✔
504
    matches = invoke_interp_compiler(passed_interp, :_findall_matches, interp, tt)
99✔
505
    matches === nothing && raise_match_failure(:code_ircode, tt)
99✔
506
    asts = []
99✔
507
    for match in matches.matches
99✔
508
        match = match::Core.MethodMatch
99✔
509
        (code, ty) = invoke_interp_compiler(passed_interp, :typeinf_ircode, interp, match, optimize_until)
99✔
510
        if code === nothing
93✔
511
            push!(asts, match.method => Any)
×
512
        else
513
            push!(asts, code => ty)
93✔
514
        end
515
    end
93✔
516
    return asts
93✔
517
end
518

519
function _builtin_return_type(passed_interp, interp,
63✔
520
                              @nospecialize(f::Core.Builtin), @nospecialize(types))
521
    argtypes = Any[to_tuple_type(types).parameters...]
63✔
522
    rt = invoke_interp_compiler(passed_interp, :builtin_tfunction, interp, f, argtypes, nothing)
63✔
523
    return invoke_interp_compiler(passed_interp, :widenconst, rt)
63✔
524
end
525

526
function _builtin_effects(passed_interp, interp,
93✔
527
                          @nospecialize(f::Core.Builtin), @nospecialize(types))
528
    argtypes = Any[to_tuple_type(types).parameters...]
93✔
529
    rt = invoke_interp_compiler(passed_interp, :builtin_tfunction, interp, f, argtypes, nothing)
93✔
530
    return invoke_interp_compiler(passed_interp, :builtin_effects,
93✔
531
        invoke_interp_compiler(passed_interp, :typeinf_lattice, interp),
532
        f, argtypes, rt)
533
end
534

535
function _builtin_exception_type(passed_interp, interp,
24✔
536
                                 @nospecialize(f::Core.Builtin), @nospecialize(types))
537
    effects = _builtin_effects(passed_interp, interp, f, types)
24✔
538
    return invoke_interp_compiler(passed_interp, :is_nothrow, effects) ? Union{} : Any
24✔
539
end
540

541
check_generated_context(world::UInt) =
1,032✔
542
    (ccall(:jl_is_in_pure_context, Bool, ()) || world == typemax(UInt)) &&
543
        error("code reflection cannot be used from generated functions")
544

545
# TODO rename `Base.return_types` to `Base.infer_return_types`
546

547
"""
548
    Base.return_types(
549
        f, types=default_tt(f);
550
        world::UInt=get_world_counter(),
551
        interp::NativeInterpreter=Core.Compiler.NativeInterpreter(world)) -> rts::Vector{Any}
552

553
Return a list of possible return types for a given function `f` and argument types `types`.
554
The list corresponds to the results of type inference on all the possible method match
555
candidates for `f` and `types` (see also [`methods(f, types)`](@ref methods).
556

557
# Arguments
558
- `f`: The function to analyze.
559
- `types` (optional): The argument types of the function. Defaults to the default tuple type of `f`.
560
- `world` (optional): The world counter to use for the analysis. Defaults to the current world counter.
561
- `interp` (optional): The abstract interpreter to use for the analysis. Defaults to a new `Core.Compiler.NativeInterpreter` with the specified `world`.
562

563
# Returns
564
- `rts::Vector{Any}`: The list of return types that are figured out by inference on
565
  methods matching with the given `f` and `types`. The list's order matches the order
566
  returned by `methods(f, types)`.
567

568
# Examples
569

570
```julia
571
julia> Base.return_types(sum, Tuple{Vector{Int}})
572
1-element Vector{Any}:
573
 Int64
574

575
julia> methods(sum, (Union{Vector{Int},UnitRange{Int}},))
576
# 2 methods for generic function "sum" from Base:
577
 [1] sum(r::AbstractRange{<:Real})
578
     @ range.jl:1399
579
 [2] sum(a::AbstractArray; dims, kw...)
580
     @ reducedim.jl:1010
581

582
julia> Base.return_types(sum, (Union{Vector{Int},UnitRange{Int}},))
583
2-element Vector{Any}:
584
 Int64 # the result of inference on sum(r::AbstractRange{<:Real})
585
 Int64 # the result of inference on sum(a::AbstractArray; dims, kw...)
586
```
587

588
!!! warning
589
    The `Base.return_types` function should not be used from generated functions;
590
    doing so will result in an error.
591
"""
592
function return_types(@nospecialize(f), @nospecialize(types=default_tt(f));
313✔
593
                      world::UInt=get_world_counter(),
594
                      interp=nothing)
595
    passed_interp = interp
152✔
596
    interp = passed_interp === nothing ? invoke_default_compiler(:_default_interp, world) : interp
152✔
597
    check_generated_context(world)
152✔
598
    if isa(f, Core.OpaqueClosure)
152✔
599
        _, rt = only(code_typed_opaque_closure(f, types; Compiler))
×
600
        return Any[rt]
×
601
    elseif isa(f, Core.Builtin)
152✔
602
        return Any[_builtin_return_type(passed_interp, interp, f, types)]
×
603
    end
604
    tt = signature_type(f, types)
152✔
605
    matches = invoke_interp_compiler(passed_interp, :_findall_matches, interp, tt)
152✔
606
    matches === nothing && raise_match_failure(:return_types, tt)
152✔
607
    rts = Any[]
152✔
608
    for match in matches.matches
152✔
609
        ty = invoke_interp_compiler(passed_interp, :typeinf_type, interp, match::Core.MethodMatch)
152✔
610
        push!(rts, something(ty, Any))
304✔
611
    end
152✔
612
    return rts
152✔
613
end
614

615
"""
616
    Base.infer_return_type(
617
        f, types=default_tt(f);
618
        world::UInt=get_world_counter(),
619
        interp::Core.Compiler.AbstractInterpreter=Core.Compiler.NativeInterpreter(world)) -> rt::Type
620

621
Return an inferred return type of the function call specified by `f` and `types`.
622

623
# Arguments
624
- `f`: The function to analyze.
625
- `types` (optional): The argument types of the function. Defaults to the default tuple type of `f`.
626
- `world` (optional): The world counter to use for the analysis. Defaults to the current world counter.
627
- `interp` (optional): The abstract interpreter to use for the analysis. Defaults to a new `Core.Compiler.NativeInterpreter` with the specified `world`.
628

629
# Returns
630
- `rt::Type`: An inferred return type of the function call specified by the given call signature.
631

632
!!! note
633
    Note that, different from [`Base.return_types`](@ref), this doesn't give you the list
634
    return types of every possible method matching with the given `f` and `types`.
635
    It returns a single return type, taking into account all potential outcomes of
636
    any function call entailed by the given signature type.
637

638
# Examples
639

640
```julia
641
julia> checksym(::Symbol) = :symbol;
642

643
julia> checksym(x::Any) = x;
644

645
julia> Base.infer_return_type(checksym, (Union{Symbol,String},))
646
Union{String, Symbol}
647

648
julia> Base.return_types(checksym, (Union{Symbol,String},))
649
2-element Vector{Any}:
650
 Symbol
651
 Union{String, Symbol}
652
```
653

654
It's important to note the difference here: `Base.return_types` gives back inferred results
655
for each method that matches the given signature `checksum(::Union{Symbol,String})`.
656
On the other hand `Base.infer_return_type` returns one collective result that sums up all those possibilities.
657

658
!!! warning
659
    The `Base.infer_return_type` function should not be used from generated functions;
660
    doing so will result in an error.
661
"""
662
function infer_return_type(@nospecialize(f), @nospecialize(types=default_tt(f));
2,489✔
663
                           world::UInt=get_world_counter(),
664
                           interp=nothing)
665
    passed_interp = interp
100✔
666
    interp = passed_interp === nothing ? invoke_default_compiler(:_default_interp, world) : interp
100✔
667
    check_generated_context(world)
100✔
668
    if isa(f, Core.OpaqueClosure)
100✔
669
        return last(only(code_typed_opaque_closure(f, types; interp=passed_interp)))
×
670
    elseif isa(f, Core.Builtin)
100✔
671
        return _builtin_return_type(passed_interp, interp, f, types)
×
672
    end
673
    tt = signature_type(f, types)
100✔
674
    matches = invoke_interp_compiler(passed_interp, :_findall_matches, interp, tt)
100✔
675
    matches === nothing && raise_match_failure(:infer_return_type, tt)
100✔
676
    rt = Union{}
100✔
677
    for match in matches.matches
100✔
678
        ty = invoke_interp_compiler(passed_interp, :typeinf_type, interp, match::Core.MethodMatch)
100✔
679
        rt = invoke_interp_compiler(passed_interp, :tmerge, rt, something(ty, Any))
200✔
680
    end
100✔
681
    return rt
100✔
682
end
683

684
"""
685
    Base.infer_exception_types(
686
        f, types=default_tt(f);
687
        world::UInt=get_world_counter(),
688
        interp::NativeInterpreter=Core.Compiler.NativeInterpreter(world)) -> excts::Vector{Any}
689

690
Return a list of possible exception types for a given function `f` and argument types `types`.
691
The list corresponds to the results of type inference on all the possible method match
692
candidates for `f` and `types` (see also [`methods(f, types)`](@ref methods).
693
It works like [`Base.return_types`](@ref), but it infers the exception types instead of the return types.
694

695
# Arguments
696
- `f`: The function to analyze.
697
- `types` (optional): The argument types of the function. Defaults to the default tuple type of `f`.
698
- `world` (optional): The world counter to use for the analysis. Defaults to the current world counter.
699
- `interp` (optional): The abstract interpreter to use for the analysis. Defaults to a new `Core.Compiler.NativeInterpreter` with the specified `world`.
700

701
# Returns
702
- `excts::Vector{Any}`: The list of exception types that are figured out by inference on
703
  methods matching with the given `f` and `types`. The list's order matches the order
704
  returned by `methods(f, types)`.
705

706
# Examples
707

708
```julia
709
julia> throw_if_number(::Number) = error("number is given");
710

711
julia> throw_if_number(::Any) = nothing;
712

713
julia> Base.infer_exception_types(throw_if_number, (Int,))
714
1-element Vector{Any}:
715
 ErrorException
716

717
julia> methods(throw_if_number, (Any,))
718
# 2 methods for generic function "throw_if_number" from Main:
719
 [1] throw_if_number(x::Number)
720
     @ REPL[1]:1
721
 [2] throw_if_number(::Any)
722
     @ REPL[2]:1
723

724
julia> Base.infer_exception_types(throw_if_number, (Any,))
725
2-element Vector{Any}:
726
 ErrorException # the result of inference on `throw_if_number(::Number)`
727
 Union{}        # the result of inference on `throw_if_number(::Any)`
728
```
729

730
!!! warning
731
    The `Base.infer_exception_types` function should not be used from generated functions;
732
    doing so will result in an error.
733
"""
734
function infer_exception_types(@nospecialize(f), @nospecialize(types=default_tt(f));
6✔
735
                               world::UInt=get_world_counter(),
736
                               interp=nothing)
737
    passed_interp = interp
3✔
738
    interp = passed_interp === nothing ? invoke_default_compiler(:_default_interp, world) : interp
3✔
739
    check_generated_context(world)
3✔
740
    if isa(f, Core.OpaqueClosure)
3✔
741
        return Any[Any] # TODO
×
742
    elseif isa(f, Core.Builtin)
3✔
743
        return Any[_builtin_exception_type(passed_interp, interp, f, types)]
×
744
    end
745
    tt = signature_type(f, types)
3✔
746
    matches = invoke_interp_compiler(passed_interp, :_findall_matches, interp, tt)
3✔
747
    matches === nothing && raise_match_failure(:infer_exception_types, tt)
3✔
748
    excts = Any[]
3✔
749
    for match in matches.matches
3✔
750
        frame = invoke_interp_compiler(passed_interp, :typeinf_frame, interp, match::Core.MethodMatch, #=run_optimizer=#false)
3✔
751
        if frame === nothing
3✔
752
            exct = Any
×
753
        else
754
            exct = invoke_interp_compiler(passed_interp, :widenconst, frame.result.exc_result)
3✔
755
        end
756
        push!(excts, exct)
3✔
757
    end
3✔
758
    return excts
3✔
759
end
760

761
"""
762
    Base.infer_exception_type(
763
        f, types=default_tt(f);
764
        world::UInt=get_world_counter(),
765
        interp::Core.Compiler.AbstractInterpreter=Core.Compiler.NativeInterpreter(world)) -> exct::Type
766

767
Return the type of exception potentially thrown by the function call specified by `f` and `types`.
768

769
# Arguments
770
- `f`: The function to analyze.
771
- `types` (optional): The argument types of the function. Defaults to the default tuple type of `f`.
772
- `world` (optional): The world counter to use for the analysis. Defaults to the current world counter.
773
- `interp` (optional): The abstract interpreter to use for the analysis. Defaults to a new `Core.Compiler.NativeInterpreter` with the specified `world`.
774

775
# Returns
776
- `exct::Type`: The inferred type of exception that can be thrown by the function call
777
  specified by the given call signature.
778

779
!!! note
780
    Note that, different from [`Base.infer_exception_types`](@ref), this doesn't give you the list
781
    exception types for every possible matching method with the given `f` and `types`.
782
    It returns a single exception type, taking into account all potential outcomes of
783
    any function call entailed by the given signature type.
784

785
# Examples
786

787
```julia
788
julia> f1(x) = x * 2;
789

790
julia> Base.infer_exception_type(f1, (Int,))
791
Union{}
792
```
793

794
The exception inferred as `Union{}` indicates that `f1(::Int)` will not throw any exception.
795

796
```julia
797
julia> f2(x::Int) = x * 2;
798

799
julia> Base.infer_exception_type(f2, (Integer,))
800
MethodError
801
```
802

803
This case is pretty much the same as with `f1`, but there's a key difference to note. For
804
`f2`, the argument type is limited to `Int`, while the argument type is given as `Tuple{Integer}`.
805
Because of this, taking into account the chance of the method error entailed by the call
806
signature, the exception type is widened to `MethodError`.
807

808
!!! warning
809
    The `Base.infer_exception_type` function should not be used from generated functions;
810
    doing so will result in an error.
811
"""
812
function infer_exception_type(@nospecialize(f), @nospecialize(types=default_tt(f));
3✔
813
                              world::UInt=get_world_counter(),
814
                              interp=nothing)
815
    passed_interp = interp
3✔
816
    interp = passed_interp === nothing ? invoke_default_compiler(:_default_interp, world) : interp
3✔
817
    check_generated_context(world)
3✔
818
    if isa(f, Core.OpaqueClosure)
3✔
819
        return Any # TODO
×
820
    elseif isa(f, Core.Builtin)
3✔
821
        return _builtin_exception_type(passed_interp, interp, f, types)
×
822
    end
823
    tt = signature_type(f, types)
3✔
824
    exct = invoke_interp_compiler(passed_interp, :_infer_exception_type, interp, tt, false)
3✔
825
    exct === nothing && raise_match_failure(:infer_exception_type, tt)
3✔
826
    return exct
3✔
827
end
828

829
"""
830
    Base.infer_effects(
831
        f, types=default_tt(f);
832
        optimize::Bool=true,
833
        world::UInt=get_world_counter(),
834
        interp::Core.Compiler.AbstractInterpreter=Core.Compiler.NativeInterpreter(world)) -> effects::Effects
835

836
Return the possible computation effects of the function call specified by `f` and `types`.
837

838
# Arguments
839
- `f`: The function to analyze.
840
- `types` (optional): The argument types of the function. Defaults to the default tuple type of `f`.
841
- `optimize` (optional): Whether to run additional effects refinements based on post-optimization analysis.
842
- `world` (optional): The world counter to use for the analysis. Defaults to the current world counter.
843
- `interp` (optional): The abstract interpreter to use for the analysis. Defaults to a new `Core.Compiler.NativeInterpreter` with the specified `world`.
844

845
# Returns
846
- `effects::Effects`: The computed effects of the function call specified by the given call signature.
847
  See the documentation of [`Effects`](@ref Core.Compiler.Effects) or [`Base.@assume_effects`](@ref)
848
  for more information on the various effect properties.
849

850
!!! note
851
    Note that, different from [`Base.return_types`](@ref), this doesn't give you the list
852
    effect analysis results for every possible matching method with the given `f` and `types`.
853
    It returns a single effect, taking into account all potential outcomes of any function
854
    call entailed by the given signature type.
855

856
# Examples
857

858
```julia
859
julia> f1(x) = x * 2;
860

861
julia> Base.infer_effects(f1, (Int,))
862
(+c,+e,+n,+t,+s,+m,+i)
863
```
864

865
This function will return an `Effects` object with information about the computational
866
effects of the function `f1` when called with an `Int` argument.
867

868
```julia
869
julia> f2(x::Int) = x * 2;
870

871
julia> Base.infer_effects(f2, (Integer,))
872
(+c,+e,!n,+t,+s,+m,+i)
873
```
874

875
This case is pretty much the same as with `f1`, but there's a key difference to note. For
876
`f2`, the argument type is limited to `Int`, while the argument type is given as `Tuple{Integer}`.
877
Because of this, taking into account the chance of the method error entailed by the call
878
signature, the `:nothrow` bit gets tainted.
879

880
!!! warning
881
    The `Base.infer_effects` function should not be used from generated functions;
882
    doing so will result in an error.
883

884
$(Compiler.effects_key_string)
885

886
# See Also
887
- [`Compiler.Effects`](@ref): A type representing the computational effects of a method call.
888
- [`Base.@assume_effects`](@ref): A macro for making assumptions about the effects of a method.
889
"""
890
function infer_effects(@nospecialize(f), @nospecialize(types=default_tt(f));
4,164✔
891
                       optimize::Bool=true,
892
                       world::UInt=get_world_counter(),
893
                       interp=nothing)
894
    passed_interp = interp
771✔
895
    interp = passed_interp === nothing ? invoke_default_compiler(:_default_interp, world) : interp
771✔
896
    check_generated_context(world)
771✔
897
    if isa(f, Core.Builtin)
771✔
898
        return _builtin_effects(passed_interp, interp, f, types)
×
899
    end
900
    tt = signature_type(f, types)
771✔
901
    effects = invoke_interp_compiler(passed_interp, :_infer_effects, interp, tt, optimize)
771✔
902
    effects === nothing && raise_match_failure(:infer_effects, tt)
771✔
903
    return effects
771✔
904
end
905

906
"""
907
    print_statement_costs(io::IO, f, types)
908

909
Print type-inferred and optimized code for `f` given argument types `types`,
910
prepending each line with its cost as estimated by the compiler's inlining engine.
911
"""
912
function print_statement_costs(io::IO, @nospecialize(f), @nospecialize(t); kwargs...)
3✔
913
    tt = signature_type(f, t)
3✔
914
    print_statement_costs(io, tt; kwargs...)
3✔
915
end
916

917
function print_statement_costs(io::IO, @nospecialize(tt::Type);
6✔
918
                               world::UInt=get_world_counter(),
919
                               interp=nothing)
920
    passed_interp = interp
3✔
921
    interp = passed_interp === nothing ? invoke_default_compiler(:_default_interp, world) : interp
3✔
922
    tt = to_tuple_type(tt)
3✔
923
    world == typemax(UInt) && error("code reflection cannot be used from generated functions")
3✔
924
    matches = invoke_interp_compiler(passed_interp, :_findall_matches, interp, tt)
3✔
925
    matches === nothing && raise_match_failure(:print_statement_costs, tt)
3✔
926
    cst = Int[]
3✔
927
    for match in matches.matches
3✔
928
        match = match::Core.MethodMatch
3✔
929
        println(io, match.method)
3✔
930
        code = invoke_interp_compiler(passed_interp, :typeinf_code, interp, match, true)
3✔
931
        if code === nothing
3✔
932
            println(io, "  inference not successful")
×
933
        else
934
            empty!(cst)
3✔
935
            resize!(cst, length(code.code))
3✔
936
            maxcost = invoke_interp_compiler(passed_interp, :statement_costs!, interp, cst, code.code, code, match)
3✔
937
            nd = ndigits(maxcost)
3✔
938
            irshow_config = IRShow.IRShowConfig() do io, linestart, idx
3✔
939
                print(io, idx > 0 ? lpad(cst[idx], nd+1) : " "^(nd+1), " ")
48✔
940
                return ""
48✔
941
            end
942
            IRShow.show_ir(io, code, irshow_config)
3✔
943
        end
944
        println(io)
3✔
945
    end
3✔
946
end
947

948
print_statement_costs(args...; kwargs...) = print_statement_costs(stdout, args...; kwargs...)
×
949

950
function _which(@nospecialize(tt::Type);
1,611✔
951
    method_table #=::Union{Nothing,Core.MethodTable,Compiler.MethodTableView}=# =nothing,
952
    world::UInt=get_world_counter(),
953
    raise::Bool=true)
954
    world == typemax(UInt) && error("code reflection cannot be used from generated functions")
36✔
955
    match, = invoke_mt_compiler(method_table, :findsup_mt, tt, world, method_table)
36✔
956
    if match === nothing
36✔
957
        raise && error("no unique matching method found for the specified argument types")
×
958
        return nothing
×
959
    end
960
    return match
36✔
961
end
962

963
"""
964
    which(f, types)
965

966
Return the method of `f` (a `Method` object) that would be called for arguments of the given `types`.
967

968
If `types` is an abstract type, then the method that would be called by `invoke` is returned.
969

970
See also [`parentmodule`](@ref), [`@which`](@ref Main.InteractiveUtils.@which), [`@edit`](@ref Main.InteractiveUtils.@edit).
971
"""
972
function which(@nospecialize(f), @nospecialize(t))
101✔
973
    tt = signature_type(f, t)
101✔
974
    world = get_world_counter()
101✔
975
    match, _ = invoke_default_compiler(:_findsup, tt, nothing, world)
101✔
976
    if match === nothing
101✔
977
        me = MethodError(f, t, world)
2✔
978
        ee = ErrorException(sprint(io -> begin
2✔
979
            println(io, "Calling invoke(f, t, args...) would throw:");
2✔
980
            Base.showerror(io, me);
2✔
981
        end))
982
        throw(ee)
2✔
983
    end
984
    return match.method
99✔
985
end
986

987
"""
988
    which(types::Type{<:Tuple})
989

990
Return the method that would be called by the given type signature (as a tuple type).
991
"""
992
function which(@nospecialize(tt#=::Type=#))
3✔
993
    return _which(tt).method
3✔
994
end
995
which(@nospecialize(argtypes::Tuple)) = which(to_tuple_type(argtypes))
×
996

997
"""
998
    which(module, symbol)
999

1000
Return the module in which the binding for the variable referenced by `symbol` in `module` was created.
1001
"""
1002
function which(m::Module, s::Symbol)
×
1003
    if !isdefined(m, s)
×
1004
        error("\"$s\" is not defined in module $m")
×
1005
    end
1006
    return binding_module(m, s)
×
1007
end
1008

1009
# function reflection
1010

1011
"""
1012
    nameof(f::Function)::Symbol
1013

1014
Get the name of a generic `Function` as a symbol. For anonymous functions,
1015
this is a compiler-generated name. For explicitly-declared subtypes of
1016
`Function`, it is the name of the function's type.
1017
"""
1018
function nameof(f::Function)
×
1019
    return typeof(f).name.singletonname
51✔
1020
end
1021

1022
function nameof(f::Core.IntrinsicFunction)
1023
    name = ccall(:jl_intrinsic_name, Ptr{UInt8}, (Core.IntrinsicFunction,), f)
33✔
1024
    return ccall(:jl_symbol, Ref{Symbol}, (Ptr{UInt8},), name)
33✔
1025
end
1026

1027
"""
1028
    parentmodule(f::Function)::Module
1029

1030
Determine the module containing the (first) definition of a generic
1031
function.
1032
"""
1033
parentmodule(f::Function) = parentmodule(typeof(f))
×
1034

1035
"""
1036
    parentmodule(f::Function, types)::Module
1037

1038
Determine the module containing the first method of a generic function `f` matching
1039
the specified `types`.
1040
"""
1041
function parentmodule(@nospecialize(f), @nospecialize(types))
×
1042
    m = methods(f, types)
×
1043
    if isempty(m)
×
1044
        error("no matching methods")
×
1045
    end
1046
    return parentmodule(first(m))
×
1047
end
1048

1049
"""
1050
    parentmodule(m::Method)::Module
1051

1052
Return the module in which the given method `m` is defined.
1053

1054
!!! compat "Julia 1.10"
1055
    Passing a `Method` as an argument requires Julia 1.10 or later.
1056
"""
1057
parentmodule(m::Method) = m.module
4,466,194✔
1058

1059
"""
1060
    hasmethod(f, t::Type{<:Tuple}[, kwnames]; world=get_world_counter())::Bool
1061

1062
Determine whether the given generic function has a method matching the given
1063
`Tuple` of argument types with the upper bound of world age given by `world`.
1064

1065
If a tuple of keyword argument names `kwnames` is provided, this also checks
1066
whether the method of `f` matching `t` has the given keyword argument names.
1067
If the matching method accepts a variable number of keyword arguments, e.g.
1068
with `kwargs...`, any names given in `kwnames` are considered valid. Otherwise
1069
the provided names must be a subset of the method's keyword arguments.
1070

1071
See also [`applicable`](@ref).
1072

1073
!!! compat "Julia 1.2"
1074
    Providing keyword argument names requires Julia 1.2 or later.
1075

1076
# Examples
1077
```jldoctest
1078
julia> hasmethod(length, Tuple{Array})
1079
true
1080

1081
julia> f(; oranges=0) = oranges;
1082

1083
julia> hasmethod(f, Tuple{}, (:oranges,))
1084
true
1085

1086
julia> hasmethod(f, Tuple{}, (:apples, :bananas))
1087
false
1088

1089
julia> g(; xs...) = 4;
1090

1091
julia> hasmethod(g, Tuple{}, (:a, :b, :c, :d))  # g accepts arbitrary kwargs
1092
true
1093
```
1094
"""
1095
function hasmethod(@nospecialize(f), @nospecialize(t))
2,940✔
1096
    return Core._hasmethod(signature_type(f, t))
299,306✔
1097
end
1098

1099
function Core.kwcall(kwargs::NamedTuple, ::typeof(hasmethod), @nospecialize(f), @nospecialize(t))
1100
    world = kwargs.world::UInt # make sure this is the only local, to avoid confusing kwarg_decl()
858✔
1101
    return ccall(:jl_gf_invoke_lookup, Any, (Any, Any, UInt), signature_type(f, t), nothing, world) !== nothing
900✔
1102
end
1103

1104
function hasmethod(f, t, kwnames::Tuple{Vararg{Symbol}}; world::UInt=get_world_counter())
×
1105
    @nospecialize
×
1106
    world == typemax(UInt) && error("code reflection cannot be used from generated functions")
×
1107
    isempty(kwnames) && return hasmethod(f, t; world)
×
1108
    t = to_tuple_type(t)
×
1109
    ft = Core.Typeof(f)
×
1110
    u = unwrap_unionall(t)::DataType
×
1111
    tt = rewrap_unionall(Tuple{typeof(Core.kwcall), NamedTuple, ft, u.parameters...}, t)
×
1112
    match = ccall(:jl_gf_invoke_lookup, Any, (Any, Any, UInt), tt, nothing, world)
×
1113
    match === nothing && return false
×
1114
    kws = ccall(:jl_uncompress_argnames, Array{Symbol,1}, (Any,), (match::Method).slot_syms)
×
1115
    kws = kws[((match::Method).nargs + 1):end] # remove positional arguments
×
1116
    isempty(kws) && return true # some kwfuncs simply forward everything directly
×
1117
    for kw in kws
×
1118
        endswith(String(kw), "...") && return true
×
1119
    end
×
1120
    return issubset(kwnames, kws)
×
1121
end
1122

1123
"""
1124
    fbody = bodyfunction(basemethod::Method)
1125

1126
Find the keyword "body function" (the function that contains the body of the method
1127
as written, called after all missing keyword-arguments have been assigned default values).
1128
`basemethod` is the method you obtain via [`which`](@ref) or [`methods`](@ref).
1129
"""
1130
function bodyfunction(basemethod::Method)
×
1131
    fmod = parentmodule(basemethod)
×
1132
    # The lowered code for `basemethod` should look like
1133
    #   %1 = mkw(kwvalues..., #self#, args...)
1134
    #        return %1
1135
    # where `mkw` is the name of the "active" keyword body-function.
1136
    ast = uncompressed_ast(basemethod)
×
1137
    if isa(ast, Core.CodeInfo) && length(ast.code) >= 2
×
1138
        callexpr = ast.code[end-1]
×
1139
        if isa(callexpr, Expr) && callexpr.head === :call
×
1140
            fsym = callexpr.args[1]
×
1141
            while true
×
1142
                if isa(fsym, Symbol)
×
1143
                    return getfield(fmod, fsym)
×
1144
                elseif isa(fsym, GlobalRef)
×
1145
                    if fsym.mod === Core && fsym.name === :_apply
×
1146
                        fsym = callexpr.args[2]
×
1147
                    elseif fsym.mod === Core && fsym.name === :_apply_iterate
×
1148
                        fsym = callexpr.args[3]
×
1149
                    end
1150
                    if isa(fsym, Symbol)
×
1151
                        return getfield(fmod, fsym)::Function
×
1152
                    elseif isa(fsym, GlobalRef)
×
1153
                        return getfield(fsym.mod, fsym.name)::Function
×
1154
                    elseif isa(fsym, Core.SSAValue)
×
1155
                        fsym = ast.code[fsym.id]
×
1156
                    else
1157
                        return nothing
×
1158
                    end
1159
                elseif isa(fsym, Core.SSAValue)
×
1160
                    fsym = ast.code[fsym.id]
×
1161
                else
1162
                    return nothing
×
1163
                end
1164
            end
×
1165
        end
1166
    end
1167
    return nothing
×
1168
end
1169

1170
"""
1171
    Base.isambiguous(m1, m2; ambiguous_bottom=false)::Bool
1172

1173
Determine whether two methods `m1` and `m2` may be ambiguous for some call
1174
signature. This test is performed in the context of other methods of the same
1175
function; in isolation, `m1` and `m2` might be ambiguous, but if a third method
1176
resolving the ambiguity has been defined, this returns `false`.
1177
Alternatively, in isolation `m1` and `m2` might be ordered, but if a third
1178
method cannot be sorted with them, they may cause an ambiguity together.
1179

1180
For parametric types, the `ambiguous_bottom` keyword argument controls whether
1181
`Union{}` counts as an ambiguous intersection of type parameters – when `true`,
1182
it is considered ambiguous, when `false` it is not.
1183

1184
# Examples
1185
```jldoctest
1186
julia> foo(x::Complex{<:Integer}) = 1
1187
foo (generic function with 1 method)
1188

1189
julia> foo(x::Complex{<:Rational}) = 2
1190
foo (generic function with 2 methods)
1191

1192
julia> m1, m2 = collect(methods(foo));
1193

1194
julia> typeintersect(m1.sig, m2.sig)
1195
Tuple{typeof(foo), Complex{Union{}}}
1196

1197
julia> Base.isambiguous(m1, m2, ambiguous_bottom=true)
1198
true
1199

1200
julia> Base.isambiguous(m1, m2, ambiguous_bottom=false)
1201
false
1202
```
1203
"""
1204
function isambiguous(m1::Method, m2::Method; ambiguous_bottom::Bool=false)
4,805✔
1205
    m1 === m2 && return false
2,159✔
1206
    ti = typeintersect(m1.sig, m2.sig)
2,159✔
1207
    ti === Bottom && return false
2,159✔
1208
    function inner(ti)
4,240✔
1209
        ti === Bottom && return false
2,081✔
1210
        if !ambiguous_bottom
2,081✔
1211
            has_bottom_parameter(ti) && return false
2,072✔
1212
        end
1213
        world = get_world_counter()
69✔
1214
        world == typemax(UInt) && return true # intersecting methods are always ambiguous in the generator world, which is true, albeit maybe confusing for some
69✔
1215
        min = Ref{UInt}(typemin(UInt))
69✔
1216
        max = Ref{UInt}(typemax(UInt))
69✔
1217
        has_ambig = Ref{Int32}(0)
69✔
1218
        ms = collect(Core.MethodMatch, _methods_by_ftype(ti, nothing, -1, world, true, min, max, has_ambig)::Vector)
138✔
1219
        has_ambig[] == 0 && return false
69✔
1220
        if !ambiguous_bottom
66✔
1221
            filter!(ms) do m::Core.MethodMatch
57✔
1222
                return !has_bottom_parameter(m.spec_types)
×
1223
            end
1224
        end
1225
        # if ml-matches reported the existence of an ambiguity over their
1226
        # intersection, see if both m1 and m2 seem to be involved in it
1227
        # (if one was fully dominated by a different method, we want to will
1228
        # report the other ambiguous pair)
1229
        have_m1 = have_m2 = false
66✔
1230
        for match in ms
66✔
1231
            m = match.method
156✔
1232
            m === m1 && (have_m1 = true)
156✔
1233
            m === m2 && (have_m2 = true)
156✔
1234
        end
156✔
1235
        if !have_m1 || !have_m2
126✔
1236
            # ml-matches did not need both methods to expose the reported ambiguity
1237
            return false
6✔
1238
        end
1239
        if !ambiguous_bottom
60✔
1240
            # since we're intentionally ignoring certain ambiguities (via the
1241
            # filter call above), see if we can now declare the intersection fully
1242
            # covered even though it is partially ambiguous over Union{} as a type
1243
            # parameter somewhere
1244
            minmax = nothing
51✔
1245
            for match in ms
51✔
1246
                m = match.method
126✔
1247
                match.fully_covers || continue
126✔
1248
                if minmax === nothing || morespecific(m, minmax)
153✔
1249
                    minmax = m
51✔
1250
                end
1251
            end
126✔
1252
            if minmax === nothing || minmax == m1 || minmax == m2
102✔
1253
                return true
51✔
1254
            end
1255
            for match in ms
×
1256
                m = match.method
×
1257
                m === minmax && continue
×
1258
                if !morespecific(minmax, m)
×
1259
                    if match.fully_covers || !morespecific(m, minmax)
×
1260
                        return true
×
1261
                    end
1262
                end
1263
            end
×
1264
            return false
×
1265
        end
1266
        return true
9✔
1267
    end
1268
    if !(ti <: m1.sig && ti <: m2.sig)
2,159✔
1269
        # When type-intersection fails, it's often also not commutative. Thus
1270
        # checking the reverse may allow detecting ambiguity solutions
1271
        # correctly in more cases (and faster).
1272
        ti2 = typeintersect(m2.sig, m1.sig)
546✔
1273
        if ti2 <: m1.sig && ti2 <: m2.sig
546✔
1274
            ti = ti2
×
1275
        elseif ti != ti2
546✔
1276
            # TODO: this would be the more correct way to handle this case, but
1277
            #       people complained so we don't do it
1278
            #inner(ti2) || return false # report that the type system failed to decide if it was ambiguous by saying they definitely are
1279
            return false # report that the type system failed to decide if it was ambiguous by saying they definitely are not
492✔
1280
        else
1281
            return false # report that the type system failed to decide if it was ambiguous by saying they definitely are not
54✔
1282
        end
1283
    end
1284
    inner(ti) || return false
3,186✔
1285
    # otherwise type-intersection reported an ambiguity we couldn't solve
1286
    return true
40✔
1287
end
1288

1289
"""
1290
    @invoke f(arg::T, ...; kwargs...)
1291

1292
Provides a convenient way to call [`invoke`](@ref) by expanding
1293
`@invoke f(arg1::T1, arg2::T2; kwargs...)` to `invoke(f, Tuple{T1,T2}, arg1, arg2; kwargs...)`.
1294
When an argument's type annotation is omitted, it's replaced with `Core.Typeof` that argument.
1295
To invoke a method where an argument is untyped or explicitly typed as `Any`, annotate the
1296
argument with `::Any`.
1297

1298
It also supports the following syntax:
1299
- `@invoke (x::X).f` expands to `invoke(getproperty, Tuple{X,Symbol}, x, :f)`
1300
- `@invoke (x::X).f = v::V` expands to `invoke(setproperty!, Tuple{X,Symbol,V}, x, :f, v)`
1301
- `@invoke (xs::Xs)[i::I]` expands to `invoke(getindex, Tuple{Xs,I}, xs, i)`
1302
- `@invoke (xs::Xs)[i::I] = v::V` expands to `invoke(setindex!, Tuple{Xs,V,I}, xs, v, i)`
1303

1304
# Examples
1305

1306
```jldoctest
1307
julia> @macroexpand @invoke f(x::T, y)
1308
:(Core.invoke(f, Base.Tuple{T, Core.Typeof(y)}, x, y))
1309

1310
julia> @invoke 420::Integer % Unsigned
1311
0x00000000000001a4
1312

1313
julia> @macroexpand @invoke (x::X).f
1314
:(Core.invoke(Base.getproperty, Base.Tuple{X, Core.Typeof(:f)}, x, :f))
1315

1316
julia> @macroexpand @invoke (x::X).f = v::V
1317
:(Core.invoke(Base.setproperty!, Base.Tuple{X, Core.Typeof(:f), V}, x, :f, v))
1318

1319
julia> @macroexpand @invoke (xs::Xs)[i::I]
1320
:(Core.invoke(Base.getindex, Base.Tuple{Xs, I}, xs, i))
1321

1322
julia> @macroexpand @invoke (xs::Xs)[i::I] = v::V
1323
:(Core.invoke(Base.setindex!, Base.Tuple{Xs, V, I}, xs, v, i))
1324
```
1325

1326
!!! compat "Julia 1.7"
1327
    This macro requires Julia 1.7 or later.
1328

1329
!!! compat "Julia 1.9"
1330
    This macro is exported as of Julia 1.9.
1331

1332
!!! compat "Julia 1.10"
1333
    The additional syntax is supported as of Julia 1.10.
1334
"""
1335
macro invoke(ex)
165✔
1336
    topmod = _topmod(__module__)
165✔
1337
    f, args, kwargs = destructure_callex(topmod, ex)
165✔
1338
    types = Expr(:curly, :Tuple)
165✔
1339
    out = Expr(:call, GlobalRef(Core, :invoke))
165✔
1340
    isempty(kwargs) || push!(out.args, Expr(:parameters, Any[esc(kw) for kw in kwargs]...))
166✔
1341
    push!(out.args, esc(f))
165✔
1342
    push!(out.args, types)
165✔
1343
    for arg in args
165✔
1344
        if isexpr(arg, :(::))
322✔
1345
            push!(out.args, esc(arg.args[1]))
273✔
1346
            push!(types.args, esc(arg.args[2]))
273✔
1347
        else
1348
            push!(out.args, esc(arg))
49✔
1349
            push!(types.args, Expr(:call, GlobalRef(Core, :Typeof), esc(arg)))
49✔
1350
        end
1351
    end
322✔
1352
    return out
165✔
1353
end
1354

1355
getglobalref(gr::GlobalRef, world::UInt) = ccall(:jl_eval_globalref, Any, (Any, UInt), gr, world)
94,301✔
1356

1357
function invokelatest_gr(gr::GlobalRef, args...; kwargs...)
184,932✔
1358
    @inline
94,291✔
1359
    kwargs = merge(NamedTuple(), kwargs)
94,291✔
1360
    world = get_world_counter()
94,301✔
1361
    f = getglobalref(gr, world)
94,301✔
1362
    if isempty(kwargs)
94,291✔
1363
        return invoke_in_world(world, f, args...)
3,290✔
1364
    end
1365
    return invoke_in_world(world, Core.kwcall, kwargs, f, args...)
91,011✔
1366
end
1367

1368
"""
1369
    @invokelatest f(args...; kwargs...)
1370

1371
Provides a convenient way to call [`invokelatest`](@ref).
1372
`@invokelatest f(args...; kwargs...)` will simply be expanded into
1373
`Base.invokelatest(f, args...; kwargs...)`.
1374

1375
It also supports the following syntax:
1376
- `@invokelatest x.f` expands to `Base.invokelatest(getproperty, x, :f)`
1377
- `@invokelatest x.f = v` expands to `Base.invokelatest(setproperty!, x, :f, v)`
1378
- `@invokelatest xs[i]` expands to `Base.invokelatest(getindex, xs, i)`
1379
- `@invokelatest xs[i] = v` expands to `Base.invokelatest(setindex!, xs, v, i)`
1380

1381
!!! note
1382
    If `f` is a global, it will be resolved consistently
1383
    in the (latest) world as the call target. However, all other arguments
1384
    (as well as `f` itself if it is not a literal global) will be evaluated
1385
    in the current world age.
1386

1387
!!! compat "Julia 1.7"
1388
    This macro requires Julia 1.7 or later.
1389

1390
!!! compat "Julia 1.9"
1391
    Prior to Julia 1.9, this macro was not exported, and was called as `Base.@invokelatest`.
1392

1393
!!! compat "Julia 1.10"
1394
    The additional `x.f` and `xs[i]` syntax requires Julia 1.10.
1395
"""
1396
macro invokelatest(ex)
2,698✔
1397
    topmod = _topmod(__module__)
2,698✔
1398
    f, args, kwargs = destructure_callex(topmod, ex)
2,698✔
1399

1400
    if !isa(f, GlobalRef)
2,698✔
1401
        out_f = Expr(:call, GlobalRef(Base, :invokelatest))
2,694✔
1402
        isempty(kwargs) || push!(out_f.args, Expr(:parameters, Any[esc(kw) for kw in kwargs]...))
2,698✔
1403

1404
        if isexpr(f, :(.))
2,694✔
1405
            s = :s
20✔
1406
            check = quote
20✔
1407
                $s = $(esc(f.args[1]))
296✔
1408
                isa($s, Module)
1409
            end
1410
            push!(out_f.args, Expr(:(.), s, esc(f.args[2])))
20✔
1411
        else
1412
            push!(out_f.args, esc(f))
2,674✔
1413
        end
1414
        append!(out_f.args, Any[esc(arg) for arg in args])
26,583✔
1415

1416
        if @isdefined(s)
2,694✔
1417
            f = :(GlobalRef($s, $(esc(f.args[2]))))
20✔
1418
        elseif isa(f, Symbol)
2,674✔
1419
            check = esc(:($(Expr(:isglobal, f))))
24✔
1420
        else
1421
            return out_f
2,650✔
1422
        end
1423
    end
1424

1425
    out_gr = Expr(:call, GlobalRef(Base, :invokelatest_gr))
48✔
1426
    isempty(kwargs) || push!(out_gr.args, Expr(:parameters, Any[esc(kw) for kw in kwargs]...))
52✔
1427
    push!(out_gr.args, isa(f, GlobalRef) ? QuoteNode(f) :
92✔
1428
                       isa(f, Symbol) ? QuoteNode(GlobalRef(__module__, f)) :
1429
                       f)
1430
    append!(out_gr.args, Any[esc(arg) for arg in args])
97✔
1431

1432
    if isa(f, GlobalRef)
48✔
1433
        return out_gr
4✔
1434
    end
1435

1436
    # f::Symbol
1437
    return :($check ? $out_gr : $out_f)
44✔
1438
end
1439

1440
function destructure_callex(topmod::Module, @nospecialize(ex))
125✔
1441
    function flatten(xs)
125✔
1442
        out = Any[]
×
1443
        for x in xs
×
1444
            if isexpr(x, :tuple)
×
1445
                append!(out, x.args)
×
1446
            else
1447
                push!(out, x)
×
1448
            end
1449
        end
×
1450
        return out
×
1451
    end
1452

1453
    kwargs = Any[]
125✔
1454
    if isexpr(ex, :call) # `f(args...)`
125✔
1455
        f = first(ex.args)
125✔
1456
        args = Any[]
125✔
1457
        for x in ex.args[2:end]
125✔
1458
            if isexpr(x, :parameters)
1,056✔
1459
                append!(kwargs, x.args)
×
1460
            elseif isexpr(x, :kw)
1,056✔
1461
                push!(kwargs, x)
3✔
1462
            else
1463
                push!(args, x)
1,053✔
1464
            end
1465
        end
1,056✔
1466
    elseif isexpr(ex, :.)   # `x.f`
×
1467
        f = GlobalRef(topmod, :getproperty)
×
1468
        args = flatten(ex.args)
×
1469
    elseif isexpr(ex, :ref) # `x[i]`
×
1470
        f = GlobalRef(topmod, :getindex)
×
1471
        args = flatten(ex.args)
×
1472
    elseif isexpr(ex, :(=)) # `x.f = v` or `x[i] = v`
×
1473
        lhs, rhs = ex.args
×
1474
        if isexpr(lhs, :.)
×
1475
            f = GlobalRef(topmod, :setproperty!)
×
1476
            args = flatten(Any[lhs.args..., rhs])
×
1477
        elseif isexpr(lhs, :ref)
×
1478
            f = GlobalRef(topmod, :setindex!)
×
1479
            args = flatten(Any[lhs.args[1], rhs, lhs.args[2]])
×
1480
        else
1481
            throw(ArgumentError("expected a `setproperty!` expression `x.f = v` or `setindex!` expression `x[i] = v`"))
×
1482
        end
1483
    else
1484
        throw(ArgumentError("expected a `:call` expression `f(args...; kwargs...)`"))
×
1485
    end
1486
    return f, args, kwargs
125✔
1487
end
1488

1489
"""
1490
    Base.drop_all_caches()
1491

1492
Internal function to drop all native code caches and increment world age.
1493
This invalidates all compiled code as if a method was added that intersects
1494
with all existing methods.
1495
"""
1496
function drop_all_caches()
×
1497
    ccall(:jl_drop_all_caches, Cvoid, ())
×
1498

1499
    # Reset loading.jl world age so that loading code is regenerated
1500
    _require_world_age[] = typemax(UInt)
×
1501

1502
    # Call Base.Compiler.activate!() after dropping caching to activate coverage of the Compiler code itself
1503
    Base.Compiler.activate!()
×
1504
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