Base.return_types and `Test.@inferred` conditionally failing unlike `@code_warntype`

Benny
Wed, 29 May 2024 07:35:17 +0000
General Usage

Experimenting with world age and ran into a weird thing. This is the session that makes sense:

julia> function evalbad(i)
         ex = :(globali() = $i)
         eval(ex) # evaluates new global method at runtime
         globali() # compiles method existing at compile-time
       end
evalbad (generic function with 1 method)

julia> globali() = 1
globali (generic function with 1 method)

julia> map([Bool, Int32, Int64, Float32, Float64, ComplexF64, String]) do i
         Base.return_types(evalbad, Tuple{i})[1] end |> println
DataType[Int64, Int64, Int64, Int64, Int64, Int64, Int64]

But in a session where the world-age-issue method defined the global method, Base.return_types fails for Int64 specifically. Test.@inferred then also fails for that input (didn’t try other inputs because it would execute the call). @code_warntype works; Test.@inferred only works after the @code_warntype; Base.return_types only works after both @code_warntype and Test.@inferred. I knew that reflection can diverge from actually compiled code because of incorrect assumptions of input type specialization, but this seems different because of the diverging side effects, like type inference isn’t one algorithm.

julia> function evalbad(i)
         ex = :(globali() = $i)
         eval(ex) # evaluates new global method at runtime
         globali() # compiles method existing at compile-time
       end
evalbad (generic function with 1 method)

julia> evalbad(1)
ERROR: MethodError: no method matching globali()
The applicable method may be too new: running in world age...

julia> globali() # definitely exists
1

julia> map([Bool, Int32, Int64, Float32, Float64, ComplexF64, String]) do i
         Base.return_types(evalbad, Tuple{i})[1] end |> println
DataType[Int64, Int64, Any, Int64, Int64, Int64, Int64]

julia> using Test; @inferred evalbad(2)
ERROR: return type Int64 does not match inferred return type Any...

julia> @inferred evalbad(3)
ERROR: return type Int64 does not match inferred return type Any...

julia> @code_warntype evalbad(4)
MethodInstance for evalbad(::Int64)
...
Body::Int64
...
│   %5 = Main.globali()::Core.Const(3)
...

julia> map([Bool, Int32, Int64, Float32, Float64, ComplexF64, String]) do i
         Base.return_types(evalbad, Tuple{i})[1] end |> println
DataType[Int64, Int64, Any, Int64, Int64, Int64, Int64]

julia> @inferred evalbad(5) # now it works
3

julia> map([Bool, Int32, Int64, Float32, Float64, ComplexF64, String]) do i
         Base.return_types(evalbad, Tuple{i})[1] end |> println
DataType[Int64, Int64, Int64, Int64, Int64, Int64, Int64]

On v1.10.3.

7 posts - 2 participants