# Base.return\_types and \`Test.@inferred\` conditionally failing unlike \`@code\_warntype\`

**URL:** <https://discourse.julialang.org/t/base-return-types-and-test-inferred-conditionally-failing-unlike-code-warntype/114902>\
**Category:** General Usage\
**Tags:** inference, code\_warntype, reflection\
**Created:** [May 29, 2024, 7:35am UTC](https://discourse.julialang.org/t/base-return-types-and-test-inferred-conditionally-failing-unlike-code-warntype/114902 "2024-05-29T07:35:17Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [May 29, 2024, 7:35am UTC](https://discourse.julialang.org/t/base-return-types-and-test-inferred-conditionally-failing-unlike-code-warntype/114902/1 "2024-05-29T07:35:17Z")

</div>

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

```julia
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](https://github.com/JuliaLang/julia/issues/32834), but this seems different because of the diverging side effects, like type inference isn’t one algorithm.

```julia
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.

---

<div class="post-metadata">

**Author:** ![Marcell\_Havlik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marcell_havlik/32/37424_2.png) [@Marcell\_Havlik](https://discourse.julialang.org/u/Marcell_Havlik)\
**Post date:** [May 29, 2024, 8:01am UTC](https://discourse.julialang.org/t/base-return-types-and-test-inferred-conditionally-failing-unlike-code-warntype/114902/2 "2024-05-29T08:01:04Z")

</div>

I think  
` ex = :(globali() = $i)`  
creates the globali in another scope or it creates a “symbol” function name in that scope…

` ex = :(Main.globali() = $i)`  
should work.

Also I think this is something where I tried to make situations to be understood for myself: [GitHub - Cvikli/JuliaMacroCheatSheet: Macro CheatSheet](https://github.com/Cvikli/JuliaMacroCheatSheet?tab=readme-ov-file#macro-hygiene-aka-scope-management)

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [May 29, 2024, 8:08am UTC](https://discourse.julialang.org/t/base-return-types-and-test-inferred-conditionally-failing-unlike-code-warntype/114902/3 "2024-05-29T08:08:45Z")

</div>

> [@Marcell\_Havlik](#):
>
> I think  
> ` ex = :(globali() = $i)`  
> creates the globali in another scope

Making the `Expr` instance itself doesn’t specify or do anything to any global scope, and the `eval` evaluates it in Main. That’s why the `globali()` call works in the 2nd session. This does not involve macro hygiene choosing whether symbols are taken from the definition’s module or call’s module.

---

<div class="post-metadata">

**Author:** ![Marcell\_Havlik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marcell_havlik/32/37424_2.png) [@Marcell\_Havlik](https://discourse.julialang.org/u/Marcell_Havlik)\
**Post date:** [May 29, 2024, 8:23am UTC](https://discourse.julialang.org/t/base-return-types-and-test-inferred-conditionally-failing-unlike-code-warntype/114902/4 "2024-05-29T08:23:15Z")

</div>

You are correct. I mistaken with macros, eval behaves a little bit different.

Basically what you want to achieve is. Create something in the function’s scope and call it from the function scope.

Because if you would create this the first time in the `Main` module then it would give us world age problem.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [May 29, 2024, 8:27am UTC](https://discourse.julialang.org/t/base-return-types-and-test-inferred-conditionally-failing-unlike-code-warntype/114902/5 "2024-05-29T08:27:10Z")

</div>

> [@Marcell\_Havlik](#):
>
> Basically what you want to achieve is. Create something in the function’s scope and call it from the function scope.

I’m aware of `invokelatest`, and I ran into this because I was trying out RuntimeGeneratedFunctions.jl. I was atypically using `Base.return_types` in a loop to contrast type inference among the various options (`evalbad`, `evallatest`, `rgf`), but evidently it’s not reliable. Having elaborated on the context, I want to emphasize that dynamic method evaluation and execution is not the intended topic. This thread is intended for the reflection issue.

---

<div class="post-metadata">

**Author:** ![Marcell\_Havlik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marcell_havlik/32/37424_2.png) [@Marcell\_Havlik](https://discourse.julialang.org/u/Marcell_Havlik)\
**Post date:** [May 29, 2024, 8:30am UTC](https://discourse.julialang.org/t/base-return-types-and-test-inferred-conditionally-failing-unlike-code-warntype/114902/6 "2024-05-29T08:30:50Z")

</div>

I know I am not the best at macros and evals. So I definitely think there is a better solution then this.  
But this worked for me now:

```julia
macro create_globali(t) 
    fn_name=:globali
    :($(esc(fn_name))() = $(esc(t)))
end
function evalbad(i)
    @create_globali i
    globali() # compiles method existing at compile-time
end

```

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [May 30, 2024, 6:28am UTC](https://discourse.julialang.org/t/base-return-types-and-test-inferred-conditionally-failing-unlike-code-warntype/114902/7 "2024-05-30T06:28:57Z")

</div>

That would expand to a local `globali() = i` at the definition of `evalbad`, it does not instantiate then `eval` an expression with a _value_ at each _call_ and thus wouldn’t involve world age issues. I figured and verified that `Base.return_types` infers it just fine as `localmacroexpr(::T)::T`.
