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

JuliaLang / julia / #38162

06 Aug 2025 08:25PM UTC coverage: 25.688% (-43.6%) from 69.336%
#38162

push

local

web-flow
fix runtime cglobal builtin function implementation (#59210)

This had failed to be updated for the LazyLibrary changes to codegen.

12976 of 50513 relevant lines covered (25.69%)

676965.51 hits per line

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

9.17
/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)
×
20
    if @isdefined(IRShow)
×
21
        debuginfo = IRShow.debuginfo(debuginfo)
×
22
    elseif debuginfo === :default
×
23
        debuginfo = :source
×
24
    end
25
    if debuginfo !== :source && debuginfo !== :none
×
26
        throw(ArgumentError("'debuginfo' must be either :source or :none"))
×
27
    end
28
    world = get_world_counter()
×
29
    world == typemax(UInt) && error("code reflection cannot be used from generated functions")
×
30
    ret = CodeInfo[]
×
31
    for m in method_instances(argtypes, world)
×
32
        if generated && hasgenerator(m)
×
33
            if may_invoke_generator(m)
×
34
                code = ccall(:jl_code_for_staged, Ref{CodeInfo}, (Any, UInt, Ptr{Cvoid}), m, world, C_NULL)
×
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)
×
42
            debuginfo === :none && remove_linenums!(code)
×
43
        end
44
        push!(ret, code)
×
45
    end
×
46
    return ret
×
47
end
48

49
function code_lowered(@nospecialize(f), @nospecialize(t=Tuple); generated::Bool=true, debuginfo::Symbol=:default)
×
50
    tt = signature_type(f, t)
×
51
    return code_lowered(tt; generated, debuginfo)
×
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)
×
59
    tt = to_tuple_type(argtypes)
×
60
    results = Core.MethodInstance[]
×
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")
×
63
    for match in _methods_by_ftype(tt, -1, world)::Vector
×
64
        instance = specialize_method(match::Core.MethodMatch)
×
65
        push!(results, instance)
×
66
    end
×
67
    return results
×
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))
×
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,
×
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(
×
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...)
×
256
    if isa(f, Core.OpaqueClosure)
×
257
        return code_typed_opaque_closure(f, types; kwargs...)
×
258
    end
259
    tt = signature_type(f, types)
×
260
    return code_typed_by_type(tt; kwargs...)
×
261
end
262

263
# support 'functor'-like queries, such as `(::Foo)(::Int, ::Int)` via `code_typed((Foo, Int, Int))`
264
function code_typed(@nospecialize(argtypes::Union{Tuple,Type{<:Tuple}}); kwargs...)
×
265
    tt = to_tuple_type(argtypes)
×
266
    return code_typed_by_type(tt; kwargs...)
×
267
end
268

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

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

287
const REFLECTION_COMPILER = RefValue{Union{Nothing, Module}}(nothing)
288

289
function invoke_in_typeinf_world(args...)
×
290
    vargs = Any[args...]
×
291
    return ccall(:jl_call_in_typeinf_world, Any, (Ptr{Any}, Cint), vargs, length(vargs))
×
292
end
293

294
function invoke_default_compiler(fname::Symbol, args...)
×
295
    if REFLECTION_COMPILER[] === nothing
×
296
        return invoke_in_typeinf_world(getglobal(Compiler, fname), args...)
×
297
    else
298
        return getglobal(REFLECTION_COMPILER[], fname)(args...)
×
299
    end
300
end
301

302
function invoke_interp_compiler(interp, fname::Symbol, args...)
×
303
    if interp === nothing
×
304
        return invoke_default_compiler(fname, args...)
×
305
    else
306
        T = typeof(interp)
×
307
        while true
×
308
            Tname = typename(T).name
×
309
            Tname === :Any && error("Expected Interpreter")
×
310
            Tname === :AbstractInterpreter && break
×
311
            T = supertype(T)
×
312
        end
×
313
        return getglobal(typename(T).module, fname)(args...)
×
314
    end
315
end
316

317
"""
318
    code_typed_by_type(types::Type{<:Tuple}; ...)
319

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

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

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

399
"""
400
    code_ircode(f, [types])
401

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

405
See also: [`code_typed`](@ref)
406

407
# Internal Keyword Arguments
408

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

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

422
# Examples
423

424
One can put the argument types in a tuple to get the corresponding `code_ircode`.
425

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

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

450
function code_ircode(@nospecialize(argtypes::Union{Tuple,Type{<:Tuple}}); kwargs...)
×
451
    tt = to_tuple_type(argtypes)
×
452
    return code_ircode_by_type(tt; kwargs...)
×
453
end
454

455
"""
456
    code_ircode_by_type(types::Type{<:Tuple}; ...)
457

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

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

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

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

509
check_generated_context(world::UInt) =
×
510
    (ccall(:jl_is_in_pure_context, Bool, ()) || world == typemax(UInt)) &&
511
        error("code reflection cannot be used from generated functions")
512

513
# TODO rename `Base.return_types` to `Base.infer_return_types`
514

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

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

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

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

536
# Examples
537

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

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

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

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

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

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

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

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

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

606
# Examples
607

608
```julia
609
julia> checksym(::Symbol) = :symbol;
610

611
julia> checksym(x::Any) = x;
612

613
julia> Base.infer_return_type(checksym, (Union{Symbol,String},))
614
Union{String, Symbol}
615

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

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

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

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

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

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

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

674
# Examples
675

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

679
julia> throw_if_number(::Any) = nothing;
680

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

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

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

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

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

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

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

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

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

753
# Examples
754

755
```julia
756
julia> f1(x) = x * 2;
757

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

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

764
```julia
765
julia> f2(x::Int) = x * 2;
766

767
julia> Base.infer_exception_type(f2, (Integer,))
768
MethodError
769
```
770

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

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

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

804
Returns the possible computation effects of the function call specified by `f` and `types`.
805

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

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

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

824
# Examples
825

826
```julia
827
julia> f1(x) = x * 2;
828

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

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

836
```julia
837
julia> f2(x::Int) = x * 2;
838

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

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

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

852
$(Compiler.effects_key_string)
853

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

874
"""
875
    print_statement_costs(io::IO, f, types)
876

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

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

916
print_statement_costs(args...; kwargs...) = print_statement_costs(stdout, args...; kwargs...)
×
917

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

931
"""
932
    which(f, types)
933

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

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

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

955
"""
956
    which(types::Type{<:Tuple})
957

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

965
"""
966
    which(module, symbol)
967

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

977
# function reflection
978

979
"""
980
    nameof(f::Function)::Symbol
981

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

990
function nameof(f::Core.IntrinsicFunction)
991
    name = ccall(:jl_intrinsic_name, Ptr{UInt8}, (Core.IntrinsicFunction,), f)
×
992
    return ccall(:jl_symbol, Ref{Symbol}, (Ptr{UInt8},), name)
×
993
end
994

995
"""
996
    parentmodule(f::Function)::Module
997

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

1003
"""
1004
    parentmodule(f::Function, types)::Module
1005

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

1017
"""
1018
    parentmodule(m::Method)::Module
1019

1020
Return the module in which the given method `m` is defined.
1021

1022
!!! compat "Julia 1.9"
1023
    Passing a `Method` as an argument requires Julia 1.9 or later.
1024
"""
1025
parentmodule(m::Method) = m.module
×
1026

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

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

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

1039
See also [`applicable`](@ref).
1040

1041
!!! compat "Julia 1.2"
1042
    Providing keyword argument names requires Julia 1.2 or later.
1043

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

1049
julia> f(; oranges=0) = oranges;
1050

1051
julia> hasmethod(f, Tuple{}, (:oranges,))
1052
true
1053

1054
julia> hasmethod(f, Tuple{}, (:apples, :bananas))
1055
false
1056

1057
julia> g(; xs...) = 4;
1058

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

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

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

1091
"""
1092
    fbody = bodyfunction(basemethod::Method)
1093

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

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

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

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

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

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

1160
julia> m1, m2 = collect(methods(foo));
1161

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

1165
julia> Base.isambiguous(m1, m2, ambiguous_bottom=true)
1166
true
1167

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

1257
"""
1258
    @invoke f(arg::T, ...; kwargs...)
1259

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

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

1272
# Examples
1273

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

1278
julia> @invoke 420::Integer % Unsigned
1279
0x00000000000001a4
1280

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

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

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

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

1294
!!! compat "Julia 1.7"
1295
    This macro requires Julia 1.7 or later.
1296

1297
!!! compat "Julia 1.9"
1298
    This macro is exported as of Julia 1.9.
1299

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

1323
getglobalref(gr::GlobalRef, world::UInt) = ccall(:jl_eval_globalref, Any, (Any, UInt), gr, world)
953✔
1324

1325
function invokelatest_gr(gr::GlobalRef, args...; kwargs...)
1,152✔
1326
    @inline
951✔
1327
    kwargs = merge(NamedTuple(), kwargs)
951✔
1328
    world = get_world_counter()
953✔
1329
    f = getglobalref(gr, world)
953✔
1330
    if isempty(kwargs)
951✔
1331
        return invoke_in_world(world, f, args...)
852✔
1332
    end
1333
    return invoke_in_world(world, Core.kwcall, kwargs, f, args...)
101✔
1334
end
1335

1336
"""
1337
    @invokelatest f(args...; kwargs...)
1338

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

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

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

1355
!!! compat "Julia 1.7"
1356
    This macro requires Julia 1.7 or later.
1357

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

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

1368
    if !isa(f, GlobalRef)
30✔
1369
        out_f = Expr(:call, GlobalRef(Base, :invokelatest))
30✔
1370
        isempty(kwargs) || push!(out_f.args, Expr(:parameters, kwargs...))
32✔
1371

1372
        if isexpr(f, :(.))
30✔
1373
            s = gensym()
×
1374
            check = quote
×
1375
                $s = $(f.args[1])
4✔
1376
                isa($s, Module)
1377
            end
1378
            push!(out_f.args, Expr(:(.), s, f.args[2]))
×
1379
        else
1380
            push!(out_f.args, f)
30✔
1381
        end
1382
        append!(out_f.args, args)
30✔
1383

1384
        if @isdefined(s)
30✔
1385
            f = :(GlobalRef($s, $(f.args[2])))
×
1386
        elseif !isa(f, Symbol)
30✔
1387
            return esc(out_f)
26✔
1388
        else
1389
            check = :($(Expr(:isglobal, f)))
4✔
1390
        end
1391
    end
1392

1393
    out_gr = Expr(:call, GlobalRef(Base, :invokelatest_gr))
4✔
1394
    isempty(kwargs) || push!(out_gr.args, Expr(:parameters, kwargs...))
6✔
1395
    push!(out_gr.args, isa(f, GlobalRef) ? QuoteNode(f) :
8✔
1396
                       isa(f, Symbol) ? QuoteNode(GlobalRef(__module__, f)) :
1397
                       f)
1398
    append!(out_gr.args, args)
4✔
1399

1400
    if isa(f, GlobalRef)
4✔
1401
        return esc(out_gr)
×
1402
    end
1403

1404
    # f::Symbol
1405
    return esc(:($check ? $out_gr : $out_f))
4✔
1406
end
1407

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

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