Skip to content

Recognize "partially generated" functions #31004

Closed
@Keno

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:

julia/base/ntuple.jl

Lines 45 to 56 in abb09f8

@inline function ntuple(f::F, ::Val{N}) where {F,N}
N::Int
(N >= 0) || throw(ArgumentError(string("tuple length should be ≥0, got ", N)))
if @generated
quote
@nexprs $N i -> t_i = f(i)
@ncall $N tuple t
end
else
Tuple(f(i) for i = 1:N)
end
end

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions