@generated function type inference failure


#1

I noticed that type inference on the following fairly simple code fails, but works if you just remove the @generated. I’m wondering if this is a known issue? It appears present both on 0.5 and master. If its a bug, does anyone have any workarounds? Thanks.

julia> struct MyType{T} end

julia> foo() = baz([MyType{1}(),MyType{2}()][1])
foo (generic function with 1 method)

julia> @generated function baz(a::MyType) 1 end
baz (generic function with 1 method)

julia> @code_warntype foo()
Variables:
  #self#::#foo
  T::Any

Body:
  begin 
      SSAValue(0) = (Core.tuple)($(QuoteNode(MyType{1}())), $(QuoteNode(MyType{2}())))::Tuple{MyType{1},MyType{2}}
      $(Expr(:inbounds, false))
      # meta: location array.jl vect 70
      SSAValue(1) = (Base.nfields)(SSAValue(0))::Int64
      # meta: pop location
      $(Expr(:inbounds, :pop))
      SSAValue(3) = $(Expr(:invoke, MethodInstance for copy!(::Array{MyType,1}, ::Tuple{MyType{1},MyType{2}}), :(Base.copy!), :($(Expr(:foreigncall, :(:jl_alloc_array_1d), Array{MyType,1}, svec(Any, Int64), :($(QuoteNode(Array{MyType,1}))), 0, SSAValue(1), 0))), SSAValue(0)))
      return (Main.baz)((Base.arrayref)(SSAValue(3), 1)::MyType)::Any
  end::Any

#2

It does not come from generated functions. You constructed an array with non-leaf type. The type inference does not do constant propagation across array construction/loading.


#3

And it works without generated function because the compiler can infer the return type/value with non-leaftype input. For generated function, it is impossible (theoritically) to do that. This is a reason to only use generated function when necessary and expect worse performance with non-leaf type info.


#4

Interesting, thanks for the explanation, I think that made sense. I didn’t know about this limitation of @generated functions before.