Issue 1:
Over at #15030, I'm trying to rewrite ntuple(f, Val{N}) so that we don't need @generated functions. It's not yet viable because, for this particular problem, codegen quality is poor. I think I've narrowed it down to a failure to substitute integer-valued GenSyms during codegen. Here's a lispy rewrite of that code that produces very simple lowered & typed code:

using Base: @_inline_meta

# The "reference implementation"
myntuple1(f, ::Type{Val{3}}) = (f(1), f(2), f(3))

# The implementation I want
function myntuple2{N}(f, ::Type{Val{N}})
@_inline_meta # this doesn't seem to affect anything
_ntuple((), f, Val{N})
end

# Build up the output until it has length N
_ntuple{N}(out::NTuple{N}, f, ::Type{Val{N}}) = out
function _ntuple{N}(out, f, ::Type{Val{N}})
@_inline_meta
_ntuple(out, (out..., 0), f, Val{N}) # compile-time evaluation of length(out)+1
end
function _ntuple{N,M}(out, ::NTuple{M}, f, ::Type{Val{N}})
@_inline_meta
_ntuple((out..., f(M)), f, Val{N})
end

Results:

julia> @code_typed myntuple1(identity, Val{3})
1-element Array{Any,1}:
:($(Expr(:lambda, Any[symbol("#self#"),:f,symbol("#unused#")], Any[Any[Any[symbol("#self#"),#myntuple1,0],Any[:f,Base.#identity,64]],Any[],Any[]], :(begin # /tmp/ntuple2.jl, line 4:
return (top(tuple))(1,2,3)::Tuple{Int64,Int64,Int64}
end::Tuple{Int64,Int64,Int64}))))

julia> @code_typed myntuple2(identity, Val{3})
1-element Array{Any,1}:
:($(Expr(:lambda, Any[symbol("#self#"),:f,symbol("#unused#")], Any[Any[Any[symbol("#self#"),#myntuple2,0],Any[:f,Base.#identity,0]],Any[],Any[Tuple{Int64,Int64},Int64,Int64]], :(begin # /tmp/ntuple2.jl, line 8:
$(Expr(:meta, :inline)) # /tmp/ntuple2.jl, line 9: # /tmp/ntuple2.jl, line 14: # /tmp/ntuple2.jl, line 15: # /tmp/ntuple2.jl, line 18: # /tmp/ntuple2.jl, line 19: # /tmp/ntuple2.jl, line 14: # /tmp/ntuple2.jl, line 15: # /tmp/ntuple2.jl, line 18: # /tmp/ntuple2.jl, line 19:
GenSym(1) = 1
GenSym(2) = 2 # /tmp/ntuple2.jl, line 14: # /tmp/ntuple2.jl, line 15: # /tmp/ntuple2.jl, line 18: # /tmp/ntuple2.jl, line 19:
return (top(tuple))(GenSym(1),GenSym(2),3)::Tuple{Int64,Int64,Int64}
end::Tuple{Int64,Int64,Int64}))))

julia> @code_native myntuple1(identity, Val{3})
.text
Filename: ntuple2.jl
Source line: 0
pushq %rbp
movq %rsp, %rbp
Source line: 4
movq $3, 16(%rdi)
movq $2, 8(%rdi)
movq $1, (%rdi)
movq %rdi, %rax
popq %rbp
retq

julia> @code_native myntuple2(identity, Val{3})
.text
Filename: ntuple2.jl
Source line: 0
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $104, %rsp
movq %rdi, %rbx
leaq -56(%rbp), %r12
leaq -88(%rbp), %rdi
movq $0, -120(%rbp)
movq $0, -112(%rbp)
movq $0, -104(%rbp)
movq $0, -96(%rbp)
movq $0, -72(%rbp)
movq $0, -64(%rbp)
movq $0, -56(%rbp)
movq $0, -48(%rbp)
movq $20, -136(%rbp)
movabsq $jl_tls_states, %r13
movq (%r13), %rax
movq %rax, -128(%rbp)
leaq -136(%rbp), %rax
movq %rax, (%r13)
Source line: 19
movq %rbx, -88(%rbp)
movabsq $140407980499072, %r14 # imm = 0x7FB347CD2080
movq %r14, -80(%rbp)
movabsq $jl_apply_generic, %r15
movl $2, %esi
callq *%r15
movq %rax, -112(%rbp)
movq %rbx, -56(%rbp)
leaq 48(%r14), %rax
movq %rax, -48(%rbp)
movl $2, %esi
movq %r12, %rdi
callq *%r15
movq %rax, -104(%rbp)
movq %rbx, -72(%rbp)
orq $96, %r14
movq %r14, -64(%rbp)
movl $2, %esi
leaq -72(%rbp), %rdi
callq *%r15
movq %rax, -96(%rbp)
movabsq $jl_f_tuple, %rax
xorl %edi, %edi
movl $3, %edx
leaq -112(%rbp), %rsi
callq *%rax
movq %rax, -120(%rbp)
Source line: 12
movq -128(%rbp), %rcx
movq %rcx, (%r13)
addq $104, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq

Is there any chance this has an easy fix? Like, add a "substitute constant-valued GenSyms" pass during codegen?

Issue 2:
In #10961, @swt30 found and fixed a performance problem with collect. It was type-unstable because it had been defined as collect(T::Type, itr) instead of collect{T}(::Type{T}, itr). But @code_warntype gave it a pass:

julia> @code_warntype collect([1,2,3])
Variables:
itr::Array{Int64,1}

Body:
begin # array.jl, line 273:
return collect(Int64,itr::Array{Int64,1})::Array{Int64,1}
end::Array{Int64,1}

julia> @code_warntype collect(Int, [1,2,3])
T::Type{Int64}
itr::Array{Int64,1}
i::Int64
a::Array{Int64,1}
… # Long, but no red flags

It's particularly tricky in this case because inference gets it right outside the function, and then when you look inside with @code_warntype the macro automatically considers the type of its type arguments to be Type{T} and not DataType. Often this is what you want (in fact, I did this in one of my first PRs), but it isn't correct in this case.

This is what we should have seen:

julia> code_warntype(collect, Tuple{DataType, Array{Int,1}})
Variables:
T::DataType
itr::Array{Int64,1}
i::Int64
a::Array{T,N}
...

I'm not sure how to fix this — we want the Type{T} definition while looking up the method, but then we don't want to pass inference more information than it'll normally get when running the code.