@@ -318,7 +318,7 @@ function show_error_hints(io, ex, args...)
318
318
isnothing (hinters) && return
319
319
for handler in hinters
320
320
try
321
- Base . invokelatest (handler, io, ex, args... )
321
+ @ invokelatest handler ( io, ex, args... )
322
322
catch err
323
323
tn = typeof (handler). name
324
324
@error " Hint-handler $handler for $(typeof (ex)) in $(tn. module) caused an error"
@@ -330,17 +330,97 @@ end
330
330
include (" opaque_closure.jl" )
331
331
332
332
"""
333
- Experimental.@overlay mt [function def]
333
+ Base. Experimental.@overlay mt [function def]
334
334
335
335
Define a method and add it to the method table `mt` instead of to the global method table.
336
336
This can be used to implement a method override mechanism. Regular compilation will not
337
337
consider these methods, and you should customize the compilation flow to look in these
338
338
method 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
+ ```
339
360
"""
340
361
macro 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)
344
424
end
345
425
346
426
function overlay_def! (mt, @nospecialize ex)
0 commit comments