JuliaLang / julia

The Julia Programming Language
https://julialang.org/
MIT License
45.87k stars 5.49k forks source link

recursive closure doesn't infer #29298

Open SimonDanisch opened 6 years ago

SimonDanisch commented 6 years ago

There is likely a more minimal example, but I couldn't come up with anything significantly more basic.

using Base: tail

struct Structure{F, Args}
    f::F
    args::Args
end

@inline tmap(f::F, args::NTuple{N, Any}) where {F, N} = @inbounds return (f(args[1]), tmap(f, tail(args))...)
@inline tmap(f, ::Tuple{}) = ()

@inline rec_func(x::AbstractArray, I) = x[I]
@inline rec_func(structure::Structure, I) = structure.f(tmap(x-> rec_func(x, I), structure.args)...)

function test(structure, I)
    rec_func(structure, I)
end

x = Structure(+, (Structure(-, (rand(100), rand(100))), rand(100)))
@code_warntype test(x, CartesianIndex(1))

I tried a couple of things:

[1]

# instead of tmap + closure
apply_rec(args::Tuple{}, I) = () # recursion ancor
@inline function apply_rec(args::NTuple{N, Any}, I) where N
    # recursevily apply br_getindex to arg
    return (rec_func(args[1], I), apply_rec(tail(args), I)...)
end
JeffBezanson commented 6 years ago

replacing I with CartesianIndex(1) solved the issue

Which I?

SimonDanisch commented 6 years ago

structure.f(tmap(x-> rec_func(x, I), structure.args)...) -> rec_func(x, I)

adienes commented 2 weeks ago

seems fixed nowadays. infers to

julia> @code_warntype test(x, CartesianIndex(1))
MethodInstance for test(::Structure{typeof(+), Tuple{Structure{typeof(-), Tuple{Vector{Float64}, Vector{Float64}}}, Vector{Float64}}}, ::CartesianIndex{1})
  from test(structure, I) @ Main REPL[7]:1
Arguments
  #self#::Core.Const(Main.test)
  structure::Structure{typeof(+), Tuple{Structure{typeof(-), Tuple{Vector{Float64}, Vector{Float64}}}, Vector{Float64}}}
  I::CartesianIndex{1}
Body::Float64
1 ─ %1 = Main.rec_func(structure, I)::Float64
└──      return %1