Could `Base._return_type` ever be inferable?


#1

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
foo(3) 

# 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.


#2

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

julia> VERSION
v"0.6.2"

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,))
Int64

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


#3

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
Stacktrace:
 [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)


#4
julia> foo(::Int) = 3;

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

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

julia> @code_warntype f()
Variables:

Body:
  begin
      return Int64
  end::Type{Int64}

#5

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?


#6

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


#7

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


#8

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 ?