So far, method parameters are always specialized in the compiled method, even when just named as part of the parameter sequence instead of being used in the method body:
That’s a valid definition (interesting!). I’ve tried it out: when combined @nospecialize it specializes like a method with a type parameter. (Since @nospecialize doesn’t like the (x, y), it has to be put at the beginning of the function body.)
It doesn’t work, very unintuitively. I guess Vararg isn’t a normal type?
julia> k((x, y)::(Vararg{T, 2} where {T})) = 0
k (generic function with 1 method)
julia> methods(k)
# 1 method for generic function "k" from Main:
[1] k(::Vararg{Any, 2})
@ REPL[46]:1
julia> k(1, 2.0)
0
julia> Vararg{T, 2} where {T}
Vararg{Any, 2}
julia> Tuple{Vararg{T, 2} where {T}}
Tuple{Any, Any}
julia> NTuple{2, T} where {T}
Tuple{T, T} where T
I recently incurred into a similar issue, I needed a way to optionally specialize a function depending on a preference. I need to keep the type parameters around because the split is between when the package is loaded for trimming/compiled and when loaded in a dynamic environment. I could just rely on precompilation, but I am dealing with monster tuple types so the compiler overspecializes on every single type.
A (very hackish) solution I’ve landed on for now is having a @autospecialize x f(x::T) where T = 0 macro, that if you turn specialization on, it’s an identity, but if you turn it off it rewrites the function signature and removes all return types annotations and where parameters associated with the declared arguments.
To keep access to the type parameters it just moves them into the preamble for them to be a runtime value instead.
It’s not generic and you kind of have to write the function signatures taking into account the limitations
I really do wish there was a better system though for telling the compiler “this type parameter can be checked at runtime, don’t specialize on it”