Could `Base._return_type` ever be inferable?


I’m far from an expert on how Julia inference works, but I ran into a situation where I could more succinctly define some type-stable custom promotion/conversion rules if Base._return_type was inferable, and was curious if this was possible theoretically. Basically this:

foo(::Int) = 3
foo(::Symbol) = :a

# Julia knows here the return type is going to be Int64

# why can't it know here that the return type of *this* call is Type{Int64} ? 
Base._return_type(foo, (Int,)) 

I dug into the code a bit and it seems like the key is whether what the _methods function does is inferable, although I haven’t gotten any further and was curious to hear from any experts on this.

EDIT: minor change of Int -> Int64 above for clarity.


I am not sure I understand your question correctly, because the type is inferred:

julia> VERSION

julia> foo(::Int) = 3
foo (generic function with 2 methods)

julia> foo(::Symbol) = :a
foo (generic function with 2 methods)

julia> Base._return_type(foo, (Int,))

And the return type is not Type{Int} (which would be the type of the type Int), but Int.


Sorry, to clarify, I mean inferred in the following sense,

julia> using Base.Test

julia> @inferred Base._return_type(foo, (Int,))
ERROR: return type Type{Int64} does not match inferred return type Any
 [1] error(::String) at ./error.jl:21

So the type of what Base._return_type returns is indeed Type{Int64}, but its not inferred at all (and that’s what I’m curious if it would be possible)

julia> foo(::Int) = 3;

julia> foo(::Symbol) = :a;

julia> f() = Base._return_type(foo, Tuple{Int});

julia> @code_warntype f()

      return Int64


Huh, that’s interesting. So its inferred inside another function but somehow not on its own? Is this something special about Base._return_type or is it some other Julia “gotcha” I’m missing?


I guess the gotcha is to put stuff in functions if you want all optimizations to kick in.


Makes sense, thanks. This is pretty awesome and even somewhat surprising that Julia can actually do this, I gotta say.


I’m guessing the compiler sees return_type as a pure function, and replaces a pure function call with constant arguments by a constant when compiling f ?