Description
While looking through some code that failed to infer properly, I noticed one source of sub-optimal type information was patterns like this:
julia> function foo(a, b)
ntuple(i->(a+b; i), Val(4))
end
foo (generic function with 1 method)
this is problematic if inference can't figure out the types of a
and b
quickly, because of the following:
julia> code_typed(foo, Tuple{Any, Any}, trace=true)
Refused to call generated function with non-concrete argument types ntuple(::getfield(Main, Symbol("##15#16")){_A,_B} where _B where _A, ::Val{4}) [GeneratedNotConcrete]
1-element Array{Any,1}:
CodeInfo(
1 ─ %1 = Main.:(##15#16)::Const(##15#16, false)
│ %2 = Core.typeof(a)::DataType
│ %3 = Core.typeof(b)::DataType
│ %4 = Core.apply_type(%1, %2, %3)::Type{##15#16{_A,_B}} where _B where _A
│ %5 = %new(%4, a, b)::##15#16{_A,_B} where _B where _A
│ %6 = Main.ntuple(%5, $(QuoteNode(Val{4}())))::Any
└── return %6
) => Any
Inference can't figure out the type of the first argument, so it refuses to call the generated function. Looking at the source for ntuple:
Lines 45 to 56 in abb09f8
it's syntactically obvious that the generator never actually looks at that type. It seems desirable, both from an inference precision perspective and to avoid calling the generator too many times to recognize that situation, call the generator only once per Val{n}
and use that specialization, even if we can't determine the types of the unused arguments.
Activity