You figured out that I had a typo where I renamed f() to snoop(). If you're
interested in how Julia deals with types, and you may not be, forget the
weird function-on-the-right thing, and take a look at code_lowered() and
code_typed().
Most of the bug you found happens during a call to typeintersect, which
finds the common subtype of two given types. First look at normal
operation. The call happens twice, once in the definition of the type
test{T}, when T is a TypeVar, and once when T is an Int.
julia> T=TypeVar(:T, true)
julia> h()=typeintersect(NTuple{T,Int},(Int,Int))
julia> g()=typeintersect(NTuple{2,Int},(Int,Int))
What you found, we'll call f().
julia> f()=typeintersect(NTuple{Float64,Int},(Int,Int))
Now, for each of these, look at code_lowered() and code_typed(), and you'll
see that substitution happens at earlier steps when there isn't a TypeVar.
julia> code_lowered(f,())
julia> code_typed(f,())
julia> code_llvm(f, ())
NTuple is a strange beast. It isn't a TypeConstructor, such as you would
form with "typealias IntDict{V} Dict{Int,V}". It isn't a normal parametric
type either, because it compares with a tuple, but when it becomes a tuple
depends on when you ask.
In short, my suggested fix was dead wrong and breaks hoards of unit tests.
I'm learning a lot, but you get all the blame. :)
- Drew