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