Multiple dispatch causes warntype in closure?

Hello, using 0.7.0. I’m trying to do some refactoring by using multiple-dispatch. In the example below, generator1() has a “better design” compared to generator2(). Unfortunately, generator1() causes some warntype

is there any method to avoid the problem? thanks. :cry:

function generator1()::Function

    # multiple-dispatched f() that always return Int64
    function f(x::Vector{Int64})::Int64
        return sum(x)
    end

    function f(x::Matrix{Int64})::Int64
        return prod(x)
    end

    # warntype here ???
    function g(xx)::Int64
        return f(xx) + 1
    end

    return g
end

g1 = generator1()
@code_warntype g1([1, 2])

julia> @code_warntype g1([1, 2])
Body::Int64
14 1 ─ %1  = (Core.getfield)(#self#, :f)::Core.Box                                                                  │
   │   %2  = (Core.isdefined)(%1, :contents)::Bool                                                                  │
   └──       goto #3 if not %2                                                                                      │
   2 ─       goto #4                                                                                                │
   3 ─       $(Expr(:throw_undef_if_not, :f, false))                                                                │
   4 ┄ %6  = (Core.getfield)(%1, :contents)::Any                                                                    │
   │   %7  = (%6)(xx)::Any                                                                                          │
   │   %8  = (%7 + 1)::Any                                                                                          │
   │   %9  = (Base.convert)(Main.Int64, %8)::Any                                                                    │
   │         (Core.typeassert)(%9, Main.Int64)                                                                      │
   │   %11 = π (%9, Int64)                                                                                          │
   └──       return %11

##############################
##############################
##############################
function generator2()::Function
    # NOT using multiple dispatch...
    function f_vec(x::Vector{Int64})::Int64
        return sum(x)
    end

    function f_mat(x::Matrix{Int64})::Int64
        return prod(x)
    end

    # need to EXPLICITLY call f_vec() or f_mat()
    function g(xx::Vector{Int64})::Int64
        return f_vec(xx) + 1
    end

    function g(xx::Matrix{Int64})::Int64
        return f_mat(xx) + 1
    end

    return g
end

g2 = generator2()
@code_warntype g2([1, 2])   # FINE

It’s the same issue from this earlier topic you posted: Strange @code_warntype - #10 by kristoffer.carlsson

You can work around the issue by explicitly capturing f in a let block:

julia> function generator1()::Function
           function f(x::Vector{Int64})
               return sum(x)
           end

           function f(x::Matrix{Int64})
               return prod(x)
           end

           g = let f_ = f
             function(xx)
               f_(xx) + 1
             end
           end

           return g
       end
2 Likes