From 88fcf44c1e52cf0e0bd32747b0cb2b77fb9c0f3f Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Wed, 13 Apr 2022 02:05:52 +0900 Subject: [PATCH] elaborate the `@nospecialize` docstring a bit (#44933) Adapted from #41931. --- base/essentials.jl | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/base/essentials.jl b/base/essentials.jl index 4bded3723711f..af965e045cbb5 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -54,12 +54,12 @@ end @nospecialize Applied to a function argument name, hints to the compiler that the method -should not be specialized for different types of that argument, -but instead to use precisely the declared type for each argument. -This is only a hint for avoiding excess code generation. -Can be applied to an argument within a formal argument list, +implementation should not be specialized for different types of that argument, +but instead use the declared type for that argument. +It can be applied to an argument within a formal argument list, or in the function body. -When applied to an argument, the macro must wrap the entire argument expression. +When applied to an argument, the macro must wrap the entire argument expression, e.g., +`@nospecialize(x::Real)` or `@nospecialize(i::Integer...)` rather than wrapping just the argument name. When used in a function body, the macro must occur in statement position and before any code. @@ -87,6 +87,38 @@ end f(y) = [x for x in y] @specialize ``` + +!!! note + `@nospecialize` affects code generation but not inference: it limits the diversity + of the resulting native code, but it does not impose any limitations (beyond the + standard ones) on type-inference. + +# Example + +```julia +julia> f(A::AbstractArray) = g(A) +f (generic function with 1 method) + +julia> @noinline g(@nospecialize(A::AbstractArray)) = A[1] +g (generic function with 1 method) + +julia> @code_typed f([1.0]) +CodeInfo( +1 ─ %1 = invoke Main.g(_2::AbstractArray)::Float64 +└── return %1 +) => Float64 +``` + +Here, the `@nospecialize` annotation results in the equivalent of + +```julia +f(A::AbstractArray) = invoke(g, Tuple{AbstractArray}, A) +``` + +ensuring that only one version of native code will be generated for `g`, +one that is generic for any `AbstractArray`. +However, the specific return type is still inferred for both `g` and `f`, +and this is still used in optimizing the callers of `f` and `g`. """ macro nospecialize(vars...) if nfields(vars) === 1