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

JuliaLang / julia / 1293

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

push

buildkite

web-flow
Support superscript small q (#59544)

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

61282 of 79637 relevant lines covered (76.95%)

21700458.33 hits per line

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

69.42
/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}});
×
76
                         world=Base.get_world_counter(), method_table=nothing)
77
    tt = to_tuple_type(argtypes)
×
78
    mi = ccall(:jl_method_lookup_by_tt, Any,
×
79
                (Any, Csize_t, Any),
80
                tt, world, method_table)
81
    return mi::Union{Nothing, MethodInstance}
×
82
end
83

84
function method_instance(@nospecialize(f), @nospecialize(t);
×
85
                         world=Base.get_world_counter(), method_table=nothing)
86
    tt = signature_type(f, t)
×
87
    return method_instance(tt; world, method_table)
×
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
    function CodegenParams(; track_allocations::Bool=true, code_coverage::Bool=true,
475✔
174
                   prefer_specsig::Bool=false,
175
                   gnu_pubnames::Bool=true, debug_info_kind::Cint = default_debug_info_kind(),
176
                   debug_info_level::Cint = Cint(JLOptions().debug_level), safepoint_on_entry::Bool=true,
177
                   gcstack_arg::Bool=true, use_jlplt::Bool=true, force_emit_all::Bool=false)
178
        return new(
171✔
179
            Cint(track_allocations), Cint(code_coverage),
180
            Cint(prefer_specsig),
181
            Cint(gnu_pubnames), debug_info_kind,
182
            debug_info_level, Cint(safepoint_on_entry),
183
            Cint(gcstack_arg), Cint(use_jlplt), Cint(force_emit_all))
184
    end
185
end
186

187
# this type mirrors jl_emission_params_t (documented in julia.h)
188
struct EmissionParams
189
    emit_metadata::Cint
190

191
    function EmissionParams(; emit_metadata::Bool=true)
×
192
        return new(Cint(emit_metadata))
×
193
    end
194
end
195

196
"""
197
    code_typed(f, types; kw...)
198

199
Returns an array of type-inferred lowered form (IR) for the methods matching the given
200
generic function and type signature.
201

202
# Keyword Arguments
203

204
- `optimize::Bool = true`: optional, controls whether additional optimizations,
205
  such as inlining, are also applied.
206
- `debuginfo::Symbol = :default`: optional, controls the amount of code metadata present
207
  in the output, possible options are `:source` or `:none`.
208

209
# Internal Keyword Arguments
210

211
This section should be considered internal, and is only for who understands Julia compiler
212
internals.
213

214
- `world::UInt = Base.get_world_counter()`: optional, controls the world age to use
215
  when looking up methods, use current world age if not specified.
216
- `interp::Core.Compiler.AbstractInterpreter = Core.Compiler.NativeInterpreter(world)`:
217
  optional, controls the abstract interpreter to use, use the native interpreter if not specified.
218

219
# Examples
220

221
One can put the argument types in a tuple to get the corresponding `code_typed`.
222

223
```julia
224
julia> code_typed(+, (Float64, Float64))
225
1-element Vector{Any}:
226
 CodeInfo(
227
1 ─ %1 = Base.add_float(x, y)::Float64
228
└──      return %1
229
) => Float64
230

231
julia> code_typed((typeof(-), Float64, Float64))
232
1-element Vector{Any}:
233
 CodeInfo(
234
1 ─ %1 = Base.sub_float(x, y)::Float64
235
└──      return %1
236
) => Float64
237

238
julia> code_typed((Type{Int}, UInt8))
239
1-element Vector{Any}:
240
 CodeInfo(
241
1 ─ %1 = Core.zext_int(Core.Int64, x)::Int64
242
└──      return %1
243
) => Int64
244

245
julia> code_typed((Returns{Int64},))
246
1-element Vector{Any}:
247
 CodeInfo(
248
1 ─ %1 =   builtin Base.getfield(obj, :value)::Int64
249
└──      return %1
250
) => Int64
251
```
252
"""
253
function code_typed end
254

255
function code_typed(@nospecialize(f), @nospecialize(types=default_tt(f)); kwargs...)
342✔
256
    if isa(f, Core.OpaqueClosure)
255✔
257
        return code_typed_opaque_closure(f, types; kwargs...)
3✔
258
    end
259
    tt = signature_type(f, types)
255✔
260
    return code_typed_by_type(tt; kwargs...)
252✔
261
end
262

263
# support queries with signatures rather than objects to better support
264
# non-singleton function objects such as `(::Foo)(::Int, ::Int)`
265
# via `code_typed((Foo, Int, Int))` or `code_typed(Tuple{Foo, Int, Int})`.
266
function code_typed(@nospecialize(argtypes::Union{Tuple,Type{<:Tuple}}); kwargs...)
165✔
267
    tt = to_tuple_type(argtypes)
144✔
268
    return code_typed_by_type(tt; kwargs...)
81✔
269
end
270

271
# returns argument tuple type which is supposed to be used for `code_typed` and its family;
272
# if there is a single method this functions returns the method argument signature,
273
# otherwise returns `Tuple` that doesn't match with any signature
274
function default_tt(@nospecialize(f))
275
    ms = methods(f)
133✔
276
    if length(ms) == 1
133✔
277
        return tuple_type_tail(only(ms).sig)
133✔
278
    else
279
        return Tuple
×
280
    end
281
end
282

283
function raise_match_failure(name::Symbol, @nospecialize(tt))
×
284
    @noinline
×
285
    sig_str = sprint(Base.show_tuple_as_call, Symbol(""), tt)
×
286
    error("$name: unanalyzable call given $sig_str")
×
287
end
288

289
const REFLECTION_COMPILER = RefValue{Union{Nothing, Module}}(nothing)
290

291
function invoke_in_typeinf_world(args...)
292
    vargs = Any[args...]
254✔
293
    return ccall(:jl_call_in_typeinf_world, Any, (Ptr{Any}, Cint), vargs, length(vargs))
127✔
294
end
295

296
function invoke_default_compiler(fname::Symbol, args...)
1,297,541✔
297
    if REFLECTION_COMPILER[] === nothing
1,297,541✔
298
        return invoke_in_typeinf_world(getglobal(Compiler, fname), args...)
1,296,031✔
299
    else
300
        return getglobal(REFLECTION_COMPILER[], fname)(args...)
1,510✔
301
    end
302
end
303

304
function invoke_interp_compiler(interp, fname::Symbol, args...)
1,937,359✔
305
    if interp === nothing
1,937,608✔
306
        return invoke_default_compiler(fname, args...)
1,937,047✔
307
    else
308
        T = typeof(interp)
561✔
309
        while true
1,122✔
310
            Tname = typename(T).name
1,122✔
311
            Tname === :Any && error("Expected Interpreter")
1,122✔
312
            Tname === :AbstractInterpreter && break
1,122✔
313
            T = supertype(T)
1,122✔
314
        end
561✔
315
        return getglobal(typename(T).module, fname)(args...)
561✔
316
    end
317
end
318

319
"""
320
    code_typed_by_type(types::Type{<:Tuple}; ...)
321

322
Similar to [`code_typed`](@ref), except the argument is a tuple type describing
323
a full signature to query.
324
"""
325
function code_typed_by_type(@nospecialize(tt::Type);
402✔
326
                            optimize::Bool=true,
327
                            debuginfo::Symbol=:default,
328
                            world::UInt=get_world_counter(),
329
                            interp=nothing)
330
    passed_interp = interp
69✔
331
    interp = passed_interp === nothing ? invoke_default_compiler(:_default_interp, world) : interp
69✔
332
    (ccall(:jl_is_in_pure_context, Bool, ()) || world == typemax(UInt)) &&
69✔
333
        error("code reflection cannot be used from generated functions")
334
    if @isdefined(IRShow)
66✔
335
        debuginfo = IRShow.debuginfo(debuginfo)
66✔
336
    elseif debuginfo === :default
×
337
        debuginfo = :source
×
338
    end
339
    if debuginfo !== :source && debuginfo !== :none
66✔
340
        throw(ArgumentError("'debuginfo' must be either :source or :none"))
×
341
    end
342
    tt = to_tuple_type(tt)
66✔
343
    matches = invoke_interp_compiler(passed_interp, :_findall_matches, interp, tt)
66✔
344
    matches === nothing && raise_match_failure(:code_typed, tt)
66✔
345
    asts = []
66✔
346
    for match in matches.matches
66✔
347
        match = match::Core.MethodMatch
66✔
348
        code = invoke_interp_compiler(passed_interp, :typeinf_code, interp, match, optimize)
66✔
349
        if code === nothing
63✔
350
            push!(asts, match.method => Any)
×
351
        else
352
            debuginfo === :none && remove_linenums!(code)
63✔
353
            push!(asts, code => code.rettype)
63✔
354
        end
355
    end
63✔
356
    return asts
63✔
357
end
358

359
function get_oc_code_rt(passed_interp, oc::Core.OpaqueClosure, types, optimize::Bool)
×
360
    @nospecialize oc types
×
361
    ccall(:jl_is_in_pure_context, Bool, ()) &&
×
362
        error("code reflection cannot be used from generated functions")
363
    m = oc.source
×
364
    if isa(m, Method)
×
365
        if isdefined(m, :source)
×
366
            if optimize
×
367
                tt = Tuple{typeof(oc.captures), to_tuple_type(types).parameters...}
×
368
                mi = specialize_method(m, tt, Core.svec())
×
369
                interp = invoke_interp_compiler(passed_interp, :_default_interp, m.primary_world)
×
370
                code = invoke_interp_compiler(passed_interp, :typeinf_code, interp, mi, optimize)
×
371
                if code isa CodeInfo
×
372
                    return Pair{CodeInfo, Any}(code, code.rettype)
×
373
                end
374
                error("inference not successful")
×
375
            else
376
                code = _uncompressed_ir(m)
×
377
                return Pair{CodeInfo, Any}(code, typeof(oc).parameters[2])
×
378
            end
379
        else
380
            # OC constructed from optimized IR
381
            codeinst = m.specializations.cache
×
382
            # XXX: the inferred field is not normally a CodeInfo, but this assumes it is guaranteed to be always
383
            return Pair{CodeInfo, Any}(codeinst.inferred, codeinst.rettype)
×
384
        end
385
    else
386
        error("encountered invalid Core.OpaqueClosure object")
×
387
    end
388
end
389

390
function code_typed_opaque_closure(oc::Core.OpaqueClosure, types;
6✔
391
                                   debuginfo::Symbol=:default,
392
                                   optimize::Bool=true,
393
                                   interp=nothing,
394
                                   _...)
395
    @nospecialize oc types
6✔
396
    (code, rt) = get_oc_code_rt(interp, oc, types, optimize)
6✔
397
    debuginfo === :none && remove_linenums!(code)
6✔
398
    return Any[Pair{CodeInfo,Any}(code, rt)]
6✔
399
end
400

401
"""
402
    code_ircode(f, [types])
403

404
Return an array of pairs of `IRCode` and inferred return type if type inference succeeds.
405
The `Method` is included instead of `IRCode` otherwise.
406

407
See also: [`code_typed`](@ref)
408

409
# Internal Keyword Arguments
410

411
This section should be considered internal, and is only for who understands Julia compiler
412
internals.
413

414
- `world::UInt = Base.get_world_counter()`: optional, controls the world age to use
415
  when looking up methods, use current world age if not specified.
416
- `interp::Core.Compiler.AbstractInterpreter = Core.Compiler.NativeInterpreter(world)`:
417
  optional, controls the abstract interpreter to use, use the native interpreter if not specified.
418
- `optimize_until::Union{Int,String,Nothing} = nothing`: optional,
419
  controls the optimization passes to run.
420
  If it is a string, it specifies the name of the pass up to which the optimizer is run.
421
  If it is an integer, it specifies the number of passes to run.
422
  If it is `nothing` (default), all passes are run.
423

424
# Examples
425

426
One can put the argument types in a tuple to get the corresponding `code_ircode`.
427

428
```julia
429
julia> Base.code_ircode(+, (Float64, Int64))
430
1-element Vector{Any}:
431
 388 1 ─ %1 = Base.sitofp(Float64, _3)::Float64
432
    │   %2 = Base.add_float(_2, %1)::Float64
433
    └──      return %2
434
     => Float64
435

436
julia> Base.code_ircode(+, (Float64, Int64); optimize_until = "compact 1")
437
1-element Vector{Any}:
438
 388 1 ─ %1 = Base.promote(_2, _3)::Tuple{Float64, Float64}
439
    │   %2 = Core._apply_iterate(Base.iterate, Base.:+, %1)::Float64
440
    └──      return %2
441
     => Float64
442
```
443
"""
444
function code_ircode(@nospecialize(f), @nospecialize(types = default_tt(f)); kwargs...)
150✔
445
    if isa(f, Core.OpaqueClosure)
132✔
446
        error("OpaqueClosure not supported")
×
447
    end
448
    tt = signature_type(f, types)
132✔
449
    return code_ircode_by_type(tt; kwargs...)
132✔
450
end
451

452
function code_ircode(@nospecialize(argtypes::Union{Tuple,Type{<:Tuple}}); kwargs...)
42✔
453
    tt = to_tuple_type(argtypes)
24✔
454
    return code_ircode_by_type(tt; kwargs...)
21✔
455
end
456

457
"""
458
    code_ircode_by_type(types::Type{<:Tuple}; ...)
459

460
Similar to [`code_ircode`](@ref), except the argument is a tuple type describing
461
a full signature to query.
462
"""
463
function code_ircode_by_type(
249✔
464
    @nospecialize(tt::Type);
465
    world::UInt=get_world_counter(),
466
    interp=nothing,
467
    optimize_until::Union{Int,String,Nothing}=nothing,
468
)
469
    passed_interp = interp
96✔
470
    interp = passed_interp === nothing ? invoke_default_compiler(:_default_interp, world) : interp
96✔
471
    (ccall(:jl_is_in_pure_context, Bool, ()) || world == typemax(UInt)) &&
96✔
472
        error("code reflection cannot be used from generated functions")
473
    tt = to_tuple_type(tt)
96✔
474
    matches = invoke_interp_compiler(passed_interp, :_findall_matches, interp, tt)
96✔
475
    matches === nothing && raise_match_failure(:code_ircode, tt)
96✔
476
    asts = []
96✔
477
    for match in matches.matches
96✔
478
        match = match::Core.MethodMatch
96✔
479
        (code, ty) = invoke_interp_compiler(passed_interp, :typeinf_ircode, interp, match, optimize_until)
96✔
480
        if code === nothing
90✔
481
            push!(asts, match.method => Any)
×
482
        else
483
            push!(asts, code => ty)
90✔
484
        end
485
    end
90✔
486
    return asts
90✔
487
end
488

489
function _builtin_return_type(passed_interp, interp,
63✔
490
                              @nospecialize(f::Core.Builtin), @nospecialize(types))
491
    argtypes = Any[to_tuple_type(types).parameters...]
63✔
492
    rt = invoke_interp_compiler(passed_interp, :builtin_tfunction, interp, f, argtypes, nothing)
63✔
493
    return invoke_interp_compiler(passed_interp, :widenconst, rt)
63✔
494
end
495

496
function _builtin_effects(passed_interp, interp,
93✔
497
                          @nospecialize(f::Core.Builtin), @nospecialize(types))
498
    argtypes = Any[to_tuple_type(types).parameters...]
93✔
499
    rt = invoke_interp_compiler(passed_interp, :builtin_tfunction, interp, f, argtypes, nothing)
93✔
500
    return invoke_interp_compiler(passed_interp, :builtin_effects,
93✔
501
        invoke_interp_compiler(passed_interp, :typeinf_lattice, interp),
502
        f, argtypes, rt)
503
end
504

505
function _builtin_exception_type(passed_interp, interp,
24✔
506
                                 @nospecialize(f::Core.Builtin), @nospecialize(types))
507
    effects = _builtin_effects(passed_interp, interp, f, types)
24✔
508
    return invoke_interp_compiler(passed_interp, :is_nothrow, effects) ? Union{} : Any
24✔
509
end
510

511
check_generated_context(world::UInt) =
934✔
512
    (ccall(:jl_is_in_pure_context, Bool, ()) || world == typemax(UInt)) &&
513
        error("code reflection cannot be used from generated functions")
514

515
# TODO rename `Base.return_types` to `Base.infer_return_types`
516

517
"""
518
    Base.return_types(
519
        f, types=default_tt(f);
520
        world::UInt=get_world_counter(),
521
        interp::NativeInterpreter=Core.Compiler.NativeInterpreter(world)) -> rts::Vector{Any}
522

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

527
# Arguments
528
- `f`: The function to analyze.
529
- `types` (optional): The argument types of the function. Defaults to the default tuple type of `f`.
530
- `world` (optional): The world counter to use for the analysis. Defaults to the current world counter.
531
- `interp` (optional): The abstract interpreter to use for the analysis. Defaults to a new `Core.Compiler.NativeInterpreter` with the specified `world`.
532

533
# Returns
534
- `rts::Vector{Any}`: The list of return types that are figured out by inference on
535
  methods matching with the given `f` and `types`. The list's order matches the order
536
  returned by `methods(f, types)`.
537

538
# Examples
539

540
```julia
541
julia> Base.return_types(sum, Tuple{Vector{Int}})
542
1-element Vector{Any}:
543
 Int64
544

545
julia> methods(sum, (Union{Vector{Int},UnitRange{Int}},))
546
# 2 methods for generic function "sum" from Base:
547
 [1] sum(r::AbstractRange{<:Real})
548
     @ range.jl:1399
549
 [2] sum(a::AbstractArray; dims, kw...)
550
     @ reducedim.jl:1010
551

552
julia> Base.return_types(sum, (Union{Vector{Int},UnitRange{Int}},))
553
2-element Vector{Any}:
554
 Int64 # the result of inference on sum(r::AbstractRange{<:Real})
555
 Int64 # the result of inference on sum(a::AbstractArray; dims, kw...)
556
```
557

558
!!! warning
559
    The `Base.return_types` function should not be used from generated functions;
560
    doing so will result in an error.
561
"""
562
function return_types(@nospecialize(f), @nospecialize(types=default_tt(f));
311✔
563
                      world::UInt=get_world_counter(),
564
                      interp=nothing)
565
    passed_interp = interp
151✔
566
    interp = passed_interp === nothing ? invoke_default_compiler(:_default_interp, world) : interp
151✔
567
    check_generated_context(world)
151✔
568
    if isa(f, Core.OpaqueClosure)
151✔
569
        _, rt = only(code_typed_opaque_closure(f, types; Compiler))
×
570
        return Any[rt]
×
571
    elseif isa(f, Core.Builtin)
151✔
572
        return Any[_builtin_return_type(passed_interp, interp, f, types)]
×
573
    end
574
    tt = signature_type(f, types)
151✔
575
    matches = invoke_interp_compiler(passed_interp, :_findall_matches, interp, tt)
151✔
576
    matches === nothing && raise_match_failure(:return_types, tt)
151✔
577
    rts = Any[]
151✔
578
    for match in matches.matches
151✔
579
        ty = invoke_interp_compiler(passed_interp, :typeinf_type, interp, match::Core.MethodMatch)
179✔
580
        push!(rts, something(ty, Any))
358✔
581
    end
179✔
582
    return rts
151✔
583
end
584

585
"""
586
    Base.infer_return_type(
587
        f, types=default_tt(f);
588
        world::UInt=get_world_counter(),
589
        interp::Core.Compiler.AbstractInterpreter=Core.Compiler.NativeInterpreter(world)) -> rt::Type
590

591
Returns an inferred return type of the function call specified by `f` and `types`.
592

593
# Arguments
594
- `f`: The function to analyze.
595
- `types` (optional): The argument types of the function. Defaults to the default tuple type of `f`.
596
- `world` (optional): The world counter to use for the analysis. Defaults to the current world counter.
597
- `interp` (optional): The abstract interpreter to use for the analysis. Defaults to a new `Core.Compiler.NativeInterpreter` with the specified `world`.
598

599
# Returns
600
- `rt::Type`: An inferred return type of the function call specified by the given call signature.
601

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

608
# Examples
609

610
```julia
611
julia> checksym(::Symbol) = :symbol;
612

613
julia> checksym(x::Any) = x;
614

615
julia> Base.infer_return_type(checksym, (Union{Symbol,String},))
616
Union{String, Symbol}
617

618
julia> Base.return_types(checksym, (Union{Symbol,String},))
619
2-element Vector{Any}:
620
 Symbol
621
 Union{String, Symbol}
622
```
623

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

628
!!! warning
629
    The `Base.infer_return_type` function should not be used from generated functions;
630
    doing so will result in an error.
631
"""
632
function infer_return_type(@nospecialize(f), @nospecialize(types=default_tt(f));
2,511✔
633
                           world::UInt=get_world_counter(),
634
                           interp=nothing)
635
    passed_interp = interp
123✔
636
    interp = passed_interp === nothing ? invoke_default_compiler(:_default_interp, world) : interp
123✔
637
    check_generated_context(world)
123✔
638
    if isa(f, Core.OpaqueClosure)
123✔
639
        return last(only(code_typed_opaque_closure(f, types; interp=passed_interp)))
×
640
    elseif isa(f, Core.Builtin)
123✔
641
        return _builtin_return_type(passed_interp, interp, f, types)
×
642
    end
643
    tt = signature_type(f, types)
123✔
644
    matches = invoke_interp_compiler(passed_interp, :_findall_matches, interp, tt)
123✔
645
    matches === nothing && raise_match_failure(:infer_return_type, tt)
123✔
646
    rt = Union{}
123✔
647
    for match in matches.matches
123✔
648
        ty = invoke_interp_compiler(passed_interp, :typeinf_type, interp, match::Core.MethodMatch)
123✔
649
        rt = invoke_interp_compiler(passed_interp, :tmerge, rt, something(ty, Any))
246✔
650
    end
123✔
651
    return rt
123✔
652
end
653

654
"""
655
    Base.infer_exception_types(
656
        f, types=default_tt(f);
657
        world::UInt=get_world_counter(),
658
        interp::NativeInterpreter=Core.Compiler.NativeInterpreter(world)) -> excts::Vector{Any}
659

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

665
# Arguments
666
- `f`: The function to analyze.
667
- `types` (optional): The argument types of the function. Defaults to the default tuple type of `f`.
668
- `world` (optional): The world counter to use for the analysis. Defaults to the current world counter.
669
- `interp` (optional): The abstract interpreter to use for the analysis. Defaults to a new `Core.Compiler.NativeInterpreter` with the specified `world`.
670

671
# Returns
672
- `excts::Vector{Any}`: The list of exception types that are figured out by inference on
673
  methods matching with the given `f` and `types`. The list's order matches the order
674
  returned by `methods(f, types)`.
675

676
# Examples
677

678
```julia
679
julia> throw_if_number(::Number) = error("number is given");
680

681
julia> throw_if_number(::Any) = nothing;
682

683
julia> Base.infer_exception_types(throw_if_number, (Int,))
684
1-element Vector{Any}:
685
 ErrorException
686

687
julia> methods(throw_if_number, (Any,))
688
# 2 methods for generic function "throw_if_number" from Main:
689
 [1] throw_if_number(x::Number)
690
     @ REPL[1]:1
691
 [2] throw_if_number(::Any)
692
     @ REPL[2]:1
693

694
julia> Base.infer_exception_types(throw_if_number, (Any,))
695
2-element Vector{Any}:
696
 ErrorException # the result of inference on `throw_if_number(::Number)`
697
 Union{}        # the result of inference on `throw_if_number(::Any)`
698
```
699

700
!!! warning
701
    The `Base.infer_exception_types` function should not be used from generated functions;
702
    doing so will result in an error.
703
"""
704
function infer_exception_types(@nospecialize(f), @nospecialize(types=default_tt(f));
6✔
705
                               world::UInt=get_world_counter(),
706
                               interp=nothing)
707
    passed_interp = interp
3✔
708
    interp = passed_interp === nothing ? invoke_default_compiler(:_default_interp, world) : interp
3✔
709
    check_generated_context(world)
3✔
710
    if isa(f, Core.OpaqueClosure)
3✔
711
        return Any[Any] # TODO
×
712
    elseif isa(f, Core.Builtin)
3✔
713
        return Any[_builtin_exception_type(passed_interp, interp, f, types)]
×
714
    end
715
    tt = signature_type(f, types)
3✔
716
    matches = invoke_interp_compiler(passed_interp, :_findall_matches, interp, tt)
3✔
717
    matches === nothing && raise_match_failure(:infer_exception_types, tt)
3✔
718
    excts = Any[]
3✔
719
    for match in matches.matches
3✔
720
        frame = invoke_interp_compiler(passed_interp, :typeinf_frame, interp, match::Core.MethodMatch, #=run_optimizer=#false)
3✔
721
        if frame === nothing
3✔
722
            exct = Any
×
723
        else
724
            exct = invoke_interp_compiler(passed_interp, :widenconst, frame.result.exc_result)
3✔
725
        end
726
        push!(excts, exct)
3✔
727
    end
3✔
728
    return excts
3✔
729
end
730

731
"""
732
    Base.infer_exception_type(
733
        f, types=default_tt(f);
734
        world::UInt=get_world_counter(),
735
        interp::Core.Compiler.AbstractInterpreter=Core.Compiler.NativeInterpreter(world)) -> exct::Type
736

737
Returns the type of exception potentially thrown by the function call specified by `f` and `types`.
738

739
# Arguments
740
- `f`: The function to analyze.
741
- `types` (optional): The argument types of the function. Defaults to the default tuple type of `f`.
742
- `world` (optional): The world counter to use for the analysis. Defaults to the current world counter.
743
- `interp` (optional): The abstract interpreter to use for the analysis. Defaults to a new `Core.Compiler.NativeInterpreter` with the specified `world`.
744

745
# Returns
746
- `exct::Type`: The inferred type of exception that can be thrown by the function call
747
  specified by the given call signature.
748

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

755
# Examples
756

757
```julia
758
julia> f1(x) = x * 2;
759

760
julia> Base.infer_exception_type(f1, (Int,))
761
Union{}
762
```
763

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

766
```julia
767
julia> f2(x::Int) = x * 2;
768

769
julia> Base.infer_exception_type(f2, (Integer,))
770
MethodError
771
```
772

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

778
!!! warning
779
    The `Base.infer_exception_type` function should not be used from generated functions;
780
    doing so will result in an error.
781
"""
782
function infer_exception_type(@nospecialize(f), @nospecialize(types=default_tt(f));
3✔
783
                              world::UInt=get_world_counter(),
784
                              interp=nothing)
785
    passed_interp = interp
3✔
786
    interp = passed_interp === nothing ? invoke_default_compiler(:_default_interp, world) : interp
3✔
787
    check_generated_context(world)
3✔
788
    if isa(f, Core.OpaqueClosure)
3✔
789
        return Any # TODO
×
790
    elseif isa(f, Core.Builtin)
3✔
791
        return _builtin_exception_type(passed_interp, interp, f, types)
×
792
    end
793
    tt = signature_type(f, types)
3✔
794
    exct = invoke_interp_compiler(passed_interp, :_infer_exception_type, interp, tt, false)
3✔
795
    exct === nothing && raise_match_failure(:infer_exception_type, tt)
3✔
796
    return exct
3✔
797
end
798

799
"""
800
    Base.infer_effects(
801
        f, types=default_tt(f);
802
        optimize::Bool=true,
803
        world::UInt=get_world_counter(),
804
        interp::Core.Compiler.AbstractInterpreter=Core.Compiler.NativeInterpreter(world)) -> effects::Effects
805

806
Returns the possible computation effects of the function call specified by `f` and `types`.
807

808
# Arguments
809
- `f`: The function to analyze.
810
- `types` (optional): The argument types of the function. Defaults to the default tuple type of `f`.
811
- `optimize` (optional): Whether to run additional effects refinements based on post-optimization analysis.
812
- `world` (optional): The world counter to use for the analysis. Defaults to the current world counter.
813
- `interp` (optional): The abstract interpreter to use for the analysis. Defaults to a new `Core.Compiler.NativeInterpreter` with the specified `world`.
814

815
# Returns
816
- `effects::Effects`: The computed effects of the function call specified by the given call signature.
817
  See the documentation of [`Effects`](@ref Core.Compiler.Effects) or [`Base.@assume_effects`](@ref)
818
  for more information on the various effect properties.
819

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

826
# Examples
827

828
```julia
829
julia> f1(x) = x * 2;
830

831
julia> Base.infer_effects(f1, (Int,))
832
(+c,+e,+n,+t,+s,+m,+i)
833
```
834

835
This function will return an `Effects` object with information about the computational
836
effects of the function `f1` when called with an `Int` argument.
837

838
```julia
839
julia> f2(x::Int) = x * 2;
840

841
julia> Base.infer_effects(f2, (Integer,))
842
(+c,+e,!n,+t,+s,+m,+i)
843
```
844

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

850
!!! warning
851
    The `Base.infer_effects` function should not be used from generated functions;
852
    doing so will result in an error.
853

854
$(Compiler.effects_key_string)
855

856
# See Also
857
- [`Compiler.Effects`](@ref): A type representing the computational effects of a method call.
858
- [`Base.@assume_effects`](@ref): A macro for making assumptions about the effects of a method.
859
"""
860
function infer_effects(@nospecialize(f), @nospecialize(types=default_tt(f));
4,289✔
861
                       optimize::Bool=true,
862
                       world::UInt=get_world_counter(),
863
                       interp=nothing)
864
    passed_interp = interp
651✔
865
    interp = passed_interp === nothing ? invoke_default_compiler(:_default_interp, world) : interp
651✔
866
    check_generated_context(world)
651✔
867
    if isa(f, Core.Builtin)
651✔
868
        return _builtin_effects(passed_interp, interp, f, types)
×
869
    end
870
    tt = signature_type(f, types)
651✔
871
    effects = invoke_interp_compiler(passed_interp, :_infer_effects, interp, tt, optimize)
651✔
872
    effects === nothing && raise_match_failure(:infer_effects, tt)
651✔
873
    return effects
651✔
874
end
875

876
"""
877
    print_statement_costs(io::IO, f, types)
878

879
Print type-inferred and optimized code for `f` given argument types `types`,
880
prepending each line with its cost as estimated by the compiler's inlining engine.
881
"""
882
function print_statement_costs(io::IO, @nospecialize(f), @nospecialize(t); kwargs...)
3✔
883
    tt = signature_type(f, t)
3✔
884
    print_statement_costs(io, tt; kwargs...)
3✔
885
end
886

887
function print_statement_costs(io::IO, @nospecialize(tt::Type);
6✔
888
                               world::UInt=get_world_counter(),
889
                               interp=nothing)
890
    passed_interp = interp
3✔
891
    interp = passed_interp === nothing ? invoke_default_compiler(:_default_interp, world) : interp
3✔
892
    tt = to_tuple_type(tt)
3✔
893
    world == typemax(UInt) && error("code reflection cannot be used from generated functions")
3✔
894
    matches = invoke_interp_compiler(passed_interp, :_findall_matches, interp, tt)
3✔
895
    matches === nothing && raise_match_failure(:print_statement_costs, tt)
3✔
896
    cst = Int[]
3✔
897
    for match in matches.matches
3✔
898
        match = match::Core.MethodMatch
3✔
899
        println(io, match.method)
3✔
900
        code = invoke_interp_compiler(passed_interp, :typeinf_code, interp, match, true)
3✔
901
        if code === nothing
3✔
902
            println(io, "  inference not successful")
×
903
        else
904
            empty!(cst)
3✔
905
            resize!(cst, length(code.code))
3✔
906
            maxcost = invoke_interp_compiler(passed_interp, :statement_costs!, interp, cst, code.code, code, match)
3✔
907
            nd = ndigits(maxcost)
3✔
908
            irshow_config = IRShow.IRShowConfig() do io, linestart, idx
3✔
909
                print(io, idx > 0 ? lpad(cst[idx], nd+1) : " "^(nd+1), " ")
48✔
910
                return ""
48✔
911
            end
912
            IRShow.show_ir(io, code, irshow_config)
3✔
913
        end
914
        println(io)
3✔
915
    end
3✔
916
end
917

918
print_statement_costs(args...; kwargs...) = print_statement_costs(stdout, args...; kwargs...)
×
919

920
function _which(@nospecialize(tt::Type);
1,473✔
921
    method_table #=::Union{Nothing,Core.MethodTable,Compiler.MethodTableView}=# =nothing,
922
    world::UInt=get_world_counter(),
923
    raise::Bool=true)
924
    world == typemax(UInt) && error("code reflection cannot be used from generated functions")
36✔
925
    match, = invoke_default_compiler(:findsup_mt, tt, world, method_table)
36✔
926
    if match === nothing
36✔
927
        raise && error("no unique matching method found for the specified argument types")
×
928
        return nothing
×
929
    end
930
    return match
36✔
931
end
932

933
"""
934
    which(f, types)
935

936
Returns the method of `f` (a `Method` object) that would be called for arguments of the given `types`.
937

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

940
See also: [`parentmodule`](@ref), [`@which`](@ref Main.InteractiveUtils.@which), and [`@edit`](@ref Main.InteractiveUtils.@edit).
941
"""
942
function which(@nospecialize(f), @nospecialize(t))
81✔
943
    tt = signature_type(f, t)
81✔
944
    world = get_world_counter()
81✔
945
    match, _ = invoke_default_compiler(:_findsup, tt, nothing, world)
81✔
946
    if match === nothing
81✔
947
        me = MethodError(f, t, world)
2✔
948
        ee = ErrorException(sprint(io -> begin
2✔
949
            println(io, "Calling invoke(f, t, args...) would throw:");
2✔
950
            Base.showerror(io, me);
2✔
951
        end))
952
        throw(ee)
2✔
953
    end
954
    return match.method
79✔
955
end
956

957
"""
958
    which(types::Type{<:Tuple})
959

960
Returns the method that would be called by the given type signature (as a tuple type).
961
"""
962
function which(@nospecialize(tt#=::Type=#))
3✔
963
    return _which(tt).method
3✔
964
end
965
which(@nospecialize(argtypes::Tuple)) = which(to_tuple_type(argtypes))
×
966

967
"""
968
    which(module, symbol)
969

970
Return the module in which the binding for the variable referenced by `symbol` in `module` was created.
971
"""
972
function which(m::Module, s::Symbol)
×
973
    if !isdefined(m, s)
×
974
        error("\"$s\" is not defined in module $m")
×
975
    end
976
    return binding_module(m, s)
×
977
end
978

979
# function reflection
980

981
"""
982
    nameof(f::Function)::Symbol
983

984
Get the name of a generic `Function` as a symbol. For anonymous functions,
985
this is a compiler-generated name. For explicitly-declared subtypes of
986
`Function`, it is the name of the function's type.
987
"""
988
function nameof(f::Function)
×
989
    return typeof(f).name.singletonname
34✔
990
end
991

992
function nameof(f::Core.IntrinsicFunction)
993
    name = ccall(:jl_intrinsic_name, Ptr{UInt8}, (Core.IntrinsicFunction,), f)
36✔
994
    return ccall(:jl_symbol, Ref{Symbol}, (Ptr{UInt8},), name)
36✔
995
end
996

997
"""
998
    parentmodule(f::Function)::Module
999

1000
Determine the module containing the (first) definition of a generic
1001
function.
1002
"""
1003
parentmodule(f::Function) = parentmodule(typeof(f))
×
1004

1005
"""
1006
    parentmodule(f::Function, types)::Module
1007

1008
Determine the module containing the first method of a generic function `f` matching
1009
the specified `types`.
1010
"""
1011
function parentmodule(@nospecialize(f), @nospecialize(types))
2✔
1012
    m = methods(f, types)
2✔
1013
    if isempty(m)
2✔
1014
        error("no matching methods")
×
1015
    end
1016
    return parentmodule(first(m))
2✔
1017
end
1018

1019
"""
1020
    parentmodule(m::Method)::Module
1021

1022
Return the module in which the given method `m` is defined.
1023

1024
!!! compat "Julia 1.9"
1025
    Passing a `Method` as an argument requires Julia 1.9 or later.
1026
"""
1027
parentmodule(m::Method) = m.module
1,830,100✔
1028

1029
"""
1030
    hasmethod(f, t::Type{<:Tuple}[, kwnames]; world=get_world_counter())::Bool
1031

1032
Determine whether the given generic function has a method matching the given
1033
`Tuple` of argument types with the upper bound of world age given by `world`.
1034

1035
If a tuple of keyword argument names `kwnames` is provided, this also checks
1036
whether the method of `f` matching `t` has the given keyword argument names.
1037
If the matching method accepts a variable number of keyword arguments, e.g.
1038
with `kwargs...`, any names given in `kwnames` are considered valid. Otherwise
1039
the provided names must be a subset of the method's keyword arguments.
1040

1041
See also [`applicable`](@ref).
1042

1043
!!! compat "Julia 1.2"
1044
    Providing keyword argument names requires Julia 1.2 or later.
1045

1046
# Examples
1047
```jldoctest
1048
julia> hasmethod(length, Tuple{Array})
1049
true
1050

1051
julia> f(; oranges=0) = oranges;
1052

1053
julia> hasmethod(f, Tuple{}, (:oranges,))
1054
true
1055

1056
julia> hasmethod(f, Tuple{}, (:apples, :bananas))
1057
false
1058

1059
julia> g(; xs...) = 4;
1060

1061
julia> hasmethod(g, Tuple{}, (:a, :b, :c, :d))  # g accepts arbitrary kwargs
1062
true
1063
```
1064
"""
1065
function hasmethod(@nospecialize(f), @nospecialize(t))
2,860✔
1066
    return Core._hasmethod(signature_type(f, t))
298,923✔
1067
end
1068

1069
function Core.kwcall(kwargs::NamedTuple, ::typeof(hasmethod), @nospecialize(f), @nospecialize(t))
1070
    world = kwargs.world::UInt # make sure this is the only local, to avoid confusing kwarg_decl()
×
1071
    return ccall(:jl_gf_invoke_lookup, Any, (Any, Any, UInt), signature_type(f, t), nothing, world) !== nothing
42✔
1072
end
1073

1074
function hasmethod(f, t, kwnames::Tuple{Vararg{Symbol}}; world::UInt=get_world_counter())
×
1075
    @nospecialize
×
1076
    world == typemax(UInt) && error("code reflection cannot be used from generated functions")
×
1077
    isempty(kwnames) && return hasmethod(f, t; world)
×
1078
    t = to_tuple_type(t)
×
1079
    ft = Core.Typeof(f)
×
1080
    u = unwrap_unionall(t)::DataType
×
1081
    tt = rewrap_unionall(Tuple{typeof(Core.kwcall), NamedTuple, ft, u.parameters...}, t)
×
1082
    match = ccall(:jl_gf_invoke_lookup, Any, (Any, Any, UInt), tt, nothing, world)
×
1083
    match === nothing && return false
×
1084
    kws = ccall(:jl_uncompress_argnames, Array{Symbol,1}, (Any,), (match::Method).slot_syms)
×
1085
    kws = kws[((match::Method).nargs + 1):end] # remove positional arguments
×
1086
    isempty(kws) && return true # some kwfuncs simply forward everything directly
×
1087
    for kw in kws
×
1088
        endswith(String(kw), "...") && return true
×
1089
    end
×
1090
    return issubset(kwnames, kws)
×
1091
end
1092

1093
"""
1094
    fbody = bodyfunction(basemethod::Method)
1095

1096
Find the keyword "body function" (the function that contains the body of the method
1097
as written, called after all missing keyword-arguments have been assigned default values).
1098
`basemethod` is the method you obtain via [`which`](@ref) or [`methods`](@ref).
1099
"""
1100
function bodyfunction(basemethod::Method)
×
1101
    fmod = parentmodule(basemethod)
×
1102
    # The lowered code for `basemethod` should look like
1103
    #   %1 = mkw(kwvalues..., #self#, args...)
1104
    #        return %1
1105
    # where `mkw` is the name of the "active" keyword body-function.
1106
    ast = uncompressed_ast(basemethod)
×
1107
    if isa(ast, Core.CodeInfo) && length(ast.code) >= 2
×
1108
        callexpr = ast.code[end-1]
×
1109
        if isa(callexpr, Expr) && callexpr.head === :call
×
1110
            fsym = callexpr.args[1]
×
1111
            while true
×
1112
                if isa(fsym, Symbol)
×
1113
                    return getfield(fmod, fsym)
×
1114
                elseif isa(fsym, GlobalRef)
×
1115
                    if fsym.mod === Core && fsym.name === :_apply
×
1116
                        fsym = callexpr.args[2]
×
1117
                    elseif fsym.mod === Core && fsym.name === :_apply_iterate
×
1118
                        fsym = callexpr.args[3]
×
1119
                    end
1120
                    if isa(fsym, Symbol)
×
1121
                        return getfield(fmod, fsym)::Function
×
1122
                    elseif isa(fsym, GlobalRef)
×
1123
                        return getfield(fsym.mod, fsym.name)::Function
×
1124
                    elseif isa(fsym, Core.SSAValue)
×
1125
                        fsym = ast.code[fsym.id]
×
1126
                    else
1127
                        return nothing
×
1128
                    end
1129
                elseif isa(fsym, Core.SSAValue)
×
1130
                    fsym = ast.code[fsym.id]
×
1131
                else
1132
                    return nothing
×
1133
                end
1134
            end
×
1135
        end
1136
    end
1137
    return nothing
×
1138
end
1139

1140
"""
1141
    Base.isambiguous(m1, m2; ambiguous_bottom=false)::Bool
1142

1143
Determine whether two methods `m1` and `m2` may be ambiguous for some call
1144
signature. This test is performed in the context of other methods of the same
1145
function; in isolation, `m1` and `m2` might be ambiguous, but if a third method
1146
resolving the ambiguity has been defined, this returns `false`.
1147
Alternatively, in isolation `m1` and `m2` might be ordered, but if a third
1148
method cannot be sorted with them, they may cause an ambiguity together.
1149

1150
For parametric types, the `ambiguous_bottom` keyword argument controls whether
1151
`Union{}` counts as an ambiguous intersection of type parameters – when `true`,
1152
it is considered ambiguous, when `false` it is not.
1153

1154
# Examples
1155
```jldoctest
1156
julia> foo(x::Complex{<:Integer}) = 1
1157
foo (generic function with 1 method)
1158

1159
julia> foo(x::Complex{<:Rational}) = 2
1160
foo (generic function with 2 methods)
1161

1162
julia> m1, m2 = collect(methods(foo));
1163

1164
julia> typeintersect(m1.sig, m2.sig)
1165
Tuple{typeof(foo), Complex{Union{}}}
1166

1167
julia> Base.isambiguous(m1, m2, ambiguous_bottom=true)
1168
true
1169

1170
julia> Base.isambiguous(m1, m2, ambiguous_bottom=false)
1171
false
1172
```
1173
"""
1174
function isambiguous(m1::Method, m2::Method; ambiguous_bottom::Bool=false)
4,717✔
1175
    m1 === m2 && return false
2,129✔
1176
    ti = typeintersect(m1.sig, m2.sig)
2,129✔
1177
    ti === Bottom && return false
2,129✔
1178
    function inner(ti)
4,168✔
1179
        ti === Bottom && return false
2,039✔
1180
        if !ambiguous_bottom
2,039✔
1181
            has_bottom_parameter(ti) && return false
2,030✔
1182
        end
1183
        world = get_world_counter()
69✔
1184
        world == typemax(UInt) && return true # intersecting methods are always ambiguous in the generator world, which is true, albeit maybe confusing for some
69✔
1185
        min = Ref{UInt}(typemin(UInt))
69✔
1186
        max = Ref{UInt}(typemax(UInt))
69✔
1187
        has_ambig = Ref{Int32}(0)
69✔
1188
        ms = collect(Core.MethodMatch, _methods_by_ftype(ti, nothing, -1, world, true, min, max, has_ambig)::Vector)
138✔
1189
        has_ambig[] == 0 && return false
69✔
1190
        if !ambiguous_bottom
66✔
1191
            filter!(ms) do m::Core.MethodMatch
57✔
1192
                return !has_bottom_parameter(m.spec_types)
×
1193
            end
1194
        end
1195
        # if ml-matches reported the existence of an ambiguity over their
1196
        # intersection, see if both m1 and m2 seem to be involved in it
1197
        # (if one was fully dominated by a different method, we want to will
1198
        # report the other ambiguous pair)
1199
        have_m1 = have_m2 = false
66✔
1200
        for match in ms
66✔
1201
            m = match.method
156✔
1202
            m === m1 && (have_m1 = true)
156✔
1203
            m === m2 && (have_m2 = true)
156✔
1204
        end
156✔
1205
        if !have_m1 || !have_m2
126✔
1206
            # ml-matches did not need both methods to expose the reported ambiguity
1207
            return false
6✔
1208
        end
1209
        if !ambiguous_bottom
60✔
1210
            # since we're intentionally ignoring certain ambiguities (via the
1211
            # filter call above), see if we can now declare the intersection fully
1212
            # covered even though it is partially ambiguous over Union{} as a type
1213
            # parameter somewhere
1214
            minmax = nothing
51✔
1215
            for match in ms
51✔
1216
                m = match.method
126✔
1217
                match.fully_covers || continue
126✔
1218
                if minmax === nothing || morespecific(m, minmax)
153✔
1219
                    minmax = m
51✔
1220
                end
1221
            end
126✔
1222
            if minmax === nothing || minmax == m1 || minmax == m2
102✔
1223
                return true
51✔
1224
            end
1225
            for match in ms
×
1226
                m = match.method
×
1227
                m === minmax && continue
×
1228
                if !morespecific(minmax, m)
×
1229
                    if match.fully_covers || !morespecific(m, minmax)
×
1230
                        return true
×
1231
                    end
1232
                end
1233
            end
×
1234
            return false
×
1235
        end
1236
        return true
9✔
1237
    end
1238
    if !(ti <: m1.sig && ti <: m2.sig)
2,129✔
1239
        # When type-intersection fails, it's often also not commutative. Thus
1240
        # checking the reverse may allow detecting ambiguity solutions
1241
        # correctly in more cases (and faster).
1242
        ti2 = typeintersect(m2.sig, m1.sig)
534✔
1243
        if ti2 <: m1.sig && ti2 <: m2.sig
534✔
1244
            ti = ti2
×
1245
        elseif ti != ti2
534✔
1246
            # TODO: this would be the more correct way to handle this case, but
1247
            #       people complained so we don't do it
1248
            #inner(ti2) || return false # report that the type system failed to decide if it was ambiguous by saying they definitely are
1249
            return false # report that the type system failed to decide if it was ambiguous by saying they definitely are not
492✔
1250
        else
1251
            return false # report that the type system failed to decide if it was ambiguous by saying they definitely are not
42✔
1252
        end
1253
    end
1254
    inner(ti) || return false
3,150✔
1255
    # otherwise type-intersection reported an ambiguity we couldn't solve
1256
    return true
40✔
1257
end
1258

1259
"""
1260
    @invoke f(arg::T, ...; kwargs...)
1261

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

1268
It also supports the following syntax:
1269
- `@invoke (x::X).f` expands to `invoke(getproperty, Tuple{X,Symbol}, x, :f)`
1270
- `@invoke (x::X).f = v::V` expands to `invoke(setproperty!, Tuple{X,Symbol,V}, x, :f, v)`
1271
- `@invoke (xs::Xs)[i::I]` expands to `invoke(getindex, Tuple{Xs,I}, xs, i)`
1272
- `@invoke (xs::Xs)[i::I] = v::V` expands to `invoke(setindex!, Tuple{Xs,V,I}, xs, v, i)`
1273

1274
# Examples
1275

1276
```jldoctest
1277
julia> @macroexpand @invoke f(x::T, y)
1278
:(Core.invoke(f, Base.Tuple{T, Core.Typeof(y)}, x, y))
1279

1280
julia> @invoke 420::Integer % Unsigned
1281
0x00000000000001a4
1282

1283
julia> @macroexpand @invoke (x::X).f
1284
:(Core.invoke(Base.getproperty, Base.Tuple{X, Core.Typeof(:f)}, x, :f))
1285

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

1289
julia> @macroexpand @invoke (xs::Xs)[i::I]
1290
:(Core.invoke(Base.getindex, Base.Tuple{Xs, I}, xs, i))
1291

1292
julia> @macroexpand @invoke (xs::Xs)[i::I] = v::V
1293
:(Core.invoke(Base.setindex!, Base.Tuple{Xs, V, I}, xs, v, i))
1294
```
1295

1296
!!! compat "Julia 1.7"
1297
    This macro requires Julia 1.7 or later.
1298

1299
!!! compat "Julia 1.9"
1300
    This macro is exported as of Julia 1.9.
1301

1302
!!! compat "Julia 1.10"
1303
    The additional syntax is supported as of Julia 1.10.
1304
"""
1305
macro invoke(ex)
163✔
1306
    topmod = _topmod(__module__)
163✔
1307
    f, args, kwargs = destructure_callex(topmod, ex)
163✔
1308
    types = Expr(:curly, :Tuple)
163✔
1309
    out = Expr(:call, GlobalRef(Core, :invoke))
163✔
1310
    isempty(kwargs) || push!(out.args, Expr(:parameters, Any[esc(kw) for kw in kwargs]...))
164✔
1311
    push!(out.args, esc(f))
163✔
1312
    push!(out.args, types)
163✔
1313
    for arg in args
163✔
1314
        if isexpr(arg, :(::))
313✔
1315
            push!(out.args, esc(arg.args[1]))
264✔
1316
            push!(types.args, esc(arg.args[2]))
264✔
1317
        else
1318
            push!(out.args, esc(arg))
49✔
1319
            push!(types.args, Expr(:call, GlobalRef(Core, :Typeof), esc(arg)))
49✔
1320
        end
1321
    end
313✔
1322
    return out
163✔
1323
end
1324

1325
getglobalref(gr::GlobalRef, world::UInt) = ccall(:jl_eval_globalref, Any, (Any, UInt), gr, world)
93,693✔
1326

1327
function invokelatest_gr(gr::GlobalRef, args...; kwargs...)
94,189✔
1328
    @inline
93,686✔
1329
    kwargs = merge(NamedTuple(), kwargs)
183,722✔
1330
    world = get_world_counter()
93,693✔
1331
    f = getglobalref(gr, world)
93,693✔
1332
    if isempty(kwargs)
183,722✔
1333
        return invoke_in_world(world, f, args...)
2,986✔
1334
    end
1335
    return invoke_in_world(world, Core.kwcall, kwargs, f, args...)
90,707✔
1336
end
1337

1338
"""
1339
    @invokelatest f(args...; kwargs...)
1340

1341
Provides a convenient way to call [`invokelatest`](@ref).
1342
`@invokelatest f(args...; kwargs...)` will simply be expanded into
1343
`Base.invokelatest(f, args...; kwargs...)`.
1344

1345
It also supports the following syntax:
1346
- `@invokelatest x.f` expands to `Base.invokelatest(getproperty, x, :f)`
1347
- `@invokelatest x.f = v` expands to `Base.invokelatest(setproperty!, x, :f, v)`
1348
- `@invokelatest xs[i]` expands to `Base.invokelatest(getindex, xs, i)`
1349
- `@invokelatest xs[i] = v` expands to `Base.invokelatest(setindex!, xs, v, i)`
1350

1351
!!! note
1352
    If `f` is a global, it will be resolved consistently
1353
    in the (latest) world as the call target. However, all other arguments
1354
    (as well as `f` itself if it is not a literal global) will be evaluated
1355
    in the current world age.
1356

1357
!!! compat "Julia 1.7"
1358
    This macro requires Julia 1.7 or later.
1359

1360
!!! compat "Julia 1.9"
1361
    Prior to Julia 1.9, this macro was not exported, and was called as `Base.@invokelatest`.
1362

1363
!!! compat "Julia 1.10"
1364
    The additional `x.f` and `xs[i]` syntax requires Julia 1.10.
1365
"""
1366
macro invokelatest(ex)
2,593✔
1367
    topmod = _topmod(__module__)
2,593✔
1368
    f, args, kwargs = destructure_callex(topmod, ex)
2,593✔
1369

1370
    if !isa(f, GlobalRef)
2,593✔
1371
        out_f = Expr(:call, GlobalRef(Base, :invokelatest))
2,589✔
1372
        isempty(kwargs) || push!(out_f.args, Expr(:parameters, Any[esc(kw) for kw in kwargs]...))
2,593✔
1373

1374
        if isexpr(f, :(.))
2,589✔
1375
            s = :s
17✔
1376
            check = quote
17✔
1377
                $s = $(esc(f.args[1]))
126✔
1378
                isa($s, Module)
1379
            end
1380
            push!(out_f.args, Expr(:(.), s, esc(f.args[2])))
17✔
1381
        else
1382
            push!(out_f.args, esc(f))
2,572✔
1383
        end
1384
        append!(out_f.args, Any[esc(arg) for arg in args])
25,643✔
1385

1386
        if @isdefined(s)
2,589✔
1387
            f = :(GlobalRef($s, $(esc(f.args[2]))))
17✔
1388
        elseif isa(f, Symbol)
2,572✔
1389
            check = esc(:($(Expr(:isglobal, f))))
14✔
1390
        else
1391
            return out_f
2,558✔
1392
        end
1393
    end
1394

1395
    out_gr = Expr(:call, GlobalRef(Base, :invokelatest_gr))
35✔
1396
    isempty(kwargs) || push!(out_gr.args, Expr(:parameters, Any[esc(kw) for kw in kwargs]...))
39✔
1397
    push!(out_gr.args, isa(f, GlobalRef) ? QuoteNode(f) :
66✔
1398
                       isa(f, Symbol) ? QuoteNode(GlobalRef(__module__, f)) :
1399
                       f)
1400
    append!(out_gr.args, Any[esc(arg) for arg in args])
77✔
1401

1402
    if isa(f, GlobalRef)
35✔
1403
        return out_gr
4✔
1404
    end
1405

1406
    # f::Symbol
1407
    return :($check ? $out_gr : $out_f)
31✔
1408
end
1409

1410
function destructure_callex(topmod::Module, @nospecialize(ex))
111✔
1411
    function flatten(xs)
111✔
1412
        out = Any[]
×
1413
        for x in xs
×
1414
            if isexpr(x, :tuple)
×
1415
                append!(out, x.args)
×
1416
            else
1417
                push!(out, x)
×
1418
            end
1419
        end
×
1420
        return out
×
1421
    end
1422

1423
    kwargs = Any[]
111✔
1424
    if isexpr(ex, :call) # `f(args...)`
111✔
1425
        f = first(ex.args)
111✔
1426
        args = Any[]
111✔
1427
        for x in ex.args[2:end]
111✔
1428
            if isexpr(x, :parameters)
957✔
1429
                append!(kwargs, x.args)
×
1430
            elseif isexpr(x, :kw)
957✔
1431
                push!(kwargs, x)
3✔
1432
            else
1433
                push!(args, x)
954✔
1434
            end
1435
        end
957✔
1436
    elseif isexpr(ex, :.)   # `x.f`
×
1437
        f = GlobalRef(topmod, :getproperty)
×
1438
        args = flatten(ex.args)
×
1439
    elseif isexpr(ex, :ref) # `x[i]`
×
1440
        f = GlobalRef(topmod, :getindex)
×
1441
        args = flatten(ex.args)
×
1442
    elseif isexpr(ex, :(=)) # `x.f = v` or `x[i] = v`
×
1443
        lhs, rhs = ex.args
×
1444
        if isexpr(lhs, :.)
×
1445
            f = GlobalRef(topmod, :setproperty!)
×
1446
            args = flatten(Any[lhs.args..., rhs])
×
1447
        elseif isexpr(lhs, :ref)
×
1448
            f = GlobalRef(topmod, :setindex!)
×
1449
            args = flatten(Any[lhs.args[1], rhs, lhs.args[2]])
×
1450
        else
1451
            throw(ArgumentError("expected a `setproperty!` expression `x.f = v` or `setindex!` expression `x[i] = v`"))
×
1452
        end
1453
    else
1454
        throw(ArgumentError("expected a `:call` expression `f(args...; kwargs...)`"))
×
1455
    end
1456
    return f, args, kwargs
111✔
1457
end
1458

1459
"""
1460
    Base.drop_all_caches()
1461

1462
Internal function to drop all native code caches and increment world age.
1463
This invalidates all compiled code as if a method was added that intersects
1464
with all existing methods.
1465
"""
1466
function drop_all_caches()
×
1467
    ccall(:jl_drop_all_caches, Cvoid, ())
×
1468

1469
    # Reset loading.jl world age so that loading code is regenerated
1470
    _require_world_age[] = typemax(UInt)
×
1471

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