@@ -318,7 +318,7 @@ function show_error_hints(io, ex, args...)
318318 isnothing (hinters) && return
319319 for handler in hinters
320320 try
321- Base . invokelatest (handler, io, ex, args... )
321+ @ invokelatest handler ( io, ex, args... )
322322 catch err
323323 tn = typeof (handler). name
324324 @error " Hint-handler $handler for $(typeof (ex)) in $(tn. module) caused an error"
@@ -330,17 +330,97 @@ end
330330include (" opaque_closure.jl" )
331331
332332"""
333- Experimental.@overlay mt [function def]
333+ Base. Experimental.@overlay mt [function def]
334334
335335Define a method and add it to the method table `mt` instead of to the global method table.
336336This can be used to implement a method override mechanism. Regular compilation will not
337337consider these methods, and you should customize the compilation flow to look in these
338338method tables (e.g., using [`Core.Compiler.OverlayMethodTable`](@ref)).
339+
340+ !!! note
341+ Please be aware that when defining overlay methods using `@overlay`, it is not necessary
342+ to have an original method that corresponds exactly in terms of how the method dispatches.
343+ This means that the method overlay mechanism enabled by `@overlay` is not implemented by
344+ replacing the methods themselves, but through an additional and prioritized method
345+ lookup during the method dispatch.
346+
347+ Considering this, it is important to understand that in compilations using an overlay
348+ method table like the following, the method dispatched by `callx(x)` is not the regular
349+ method `callx(::Float64)`, but the overlay method `callx(x::Real)`:
350+ ```julia
351+ callx(::Real) = :real
352+ @overlay SOME_OVERLAY_MT callx(::Real) = :overlay_real
353+ callx(::Float64) = :float64
354+
355+ # some overlay callsite
356+ let x::Float64
357+ callx(x) #> :overlay_real
358+ end
359+ ```
339360"""
340361macro overlay (mt, def)
341- def = macroexpand (__module__, def) # to expand @inline, @generated, etc
342- is_function_def (def) || error (" @overlay requires a function definition" )
343- return esc (overlay_def! (mt, def))
362+ inner = Base. unwrap_macrocalls (def)
363+ is_function_def (inner) || error (" @overlay requires a function definition" )
364+ overlay_def! (mt, inner)
365+ return esc (def)
366+ end
367+
368+ """
369+ Base.Experimental.@consistent_overlay mt [function def]
370+
371+ This macro operates almost identically to [`Base.Experimental.@overlay`](@ref), defining a
372+ new overlay method. The key difference with this macro is that it informs the compiler that
373+ the invocation of the overlay method it defines is `:consistent` with a regular,
374+ non-overlayed method call.
375+
376+ More formally, when evaluating a generic function call ``f(x)`` at a specific world age
377+ ``i``, if a regular method call ``fᵢ(x)`` is redirected to an overlay method call ``fᵢ′(x)``
378+ defined by this macro, it must be ensured that ``fᵢ(x) ≡ fᵢ′(x)``.
379+
380+ For a detailed definition of `:consistent`-cy, consult the corresponding section in
381+ [`Base.@assume_effects`](@ref).
382+
383+ !!! note
384+ Note that the requirements for `:consistent`-cy include not only that the return values
385+ are egal, but also that the manner of termination is the same.
386+ However, it's important to aware that when they throw exceptions, the exceptions
387+ themselves don't necessarily have to be egal as explained in the note of `:consistent`.
388+ In other words, if ``fᵢ(x)`` throws an exception, ``fᵢ′(x)`` is required to also throw
389+ one, but the exact exceptions may differ.
390+
391+ !!! note
392+ Please note that the `:consistent`-cy requirement applies not to method itself but to
393+ _method invocation_. This means that for the use of `@consistent_overlay`, it is
394+ necessary for method invocations with the native regular compilation and those with
395+ a compilation with overlay method table to be `:consistent`.
396+
397+ For example, it is important to understand that, `@consistent_overlay` can be used like
398+ the following:
399+ ```julia
400+ callsin(x::Real) = x < 0 ? error(x) : sin(x)
401+ @consistent_overlay SOME_OVERLAY_MT callsin(x::Float64) =
402+ x < 0 ? error_somehow(x) : sin(x)
403+ ```
404+ However, be aware that this `@consistent_overlay` will immediately become invalid if a
405+ new method for `callsin` is defined subsequently, such as:
406+ ```julia
407+ callsin(x::Float64) = cos(x)
408+ ```
409+
410+ This specifically implies that the use of `@consistent_overlay` should be restricted as
411+ much as possible to cases where a regular method with a concrete signature is replaced
412+ by an overlay method with the same concrete signature.
413+
414+ This constraint is closely related to the note in [`Base.Experimental.@overlay`](@ref);
415+ you are advised to consult that as well.
416+ """
417+ macro consistent_overlay (mt, def)
418+ inner = Base. unwrap_macrocalls (def)
419+ is_function_def (inner) || error (" @consistent_overlay requires a function definition" )
420+ overlay_def! (mt, inner)
421+ override = Core. Compiler. EffectsOverride (; consistent_overlay= true )
422+ Base. pushmeta! (def:: Expr , Base. form_purity_expr (override))
423+ return esc (def)
344424end
345425
346426function overlay_def! (mt, @nospecialize ex)
0 commit comments