local f = function(T::Type)
return function(x::T)
x + 1
end
end

which gives “UndefVarError: T not defined” due to the inner x::T.

This is a bit surprising to me, as using dynamic types is allowed for local, i.e. the following is ok:

local f = function(T::Type)
local x::T = 3
x + 1
end

Now, I’m aware that I could rewrite the first example with something like eval(Expr(:function, Expr(:tuple, Expr(:(::), :x, T) ..., but unfortunately, in my specific use case I actually need a capture (thus breaking the eval approach due to eval’s global scope), i.e. what I actually want to achieve is this:

local y
local f = function(T::Type)
return function(x::T)
x + y
end
end

It is expected. The closure you create on multiple invocations of the parent function are of the same type and the method definition including the dispatch specification is statically computed at compile time. The sementic is defined this way since doing it otherwise would be very expensive, either you have to create new type or adding new method to a type at runtime.

That said, it is not impossible to transform the code to do an assertion in this case automatically. However, since it will NOT have the same semantic as specifying the dispatch it’s a little bit confusing (not much) if we do so.

Note that the typeassert isn’t necessary if you’re just trying to produce efficient code:

julia> function f(x)
x + 1
end
f (generic function with 1 method)
julia> @code_llvm f(10)
define i64 @julia_f_70822(i64) #0 {
top:
%1 = add i64 %0, 1
ret i64 %1
}