Need help with incomprehensible typeinference

Here's a full REPL session. where inference seems to break, but maybe I'm missing something with globals and softscope.
julia> using ExtensibleEffects

julia> using TypeClasses

julia> using Test

julia>

julia> vector_of_eff_of_vector = map(x -> noeffect([x]), [1, 20])
2-element Vector{ExtensibleEffects.Eff{NoEffect{Vector{Int64}}, Tuple{}}}:
 Eff(effectful=NoEffect{Vector{Int64}}([1]), length(cont)=0)
 Eff(effectful=NoEffect{Vector{Int64}}([20]), length(cont)=0)

julia> e1 = vector_of_eff_of_vector[1]
Eff(effectful=NoEffect{Vector{Int64}}([1]), length(cont)=0)

julia> e2 = vector_of_eff_of_vector[2]
Eff(effectful=NoEffect{Vector{Int64}}([20]), length(cont)=0)

julia> function prepare_test(e1, e2)
           combine(v1, v2) = [v1; v2]
           curried_combine(v1) = v2 -> combine(v1, v2)

           e1_f = map(curried_combine, e1)
           f_flatmap(f) = TypeClasses.map(v2 -> f(v2), e2)
           f_flatmap, e1_f
       end
prepare_test (generic function with 1 method)

julia>

julia> f_flatmap, e1_f = prepare_test(e1, e2)
(f_flatmap, Eff(effectful=NoEffect{var"#3#7"{Vector{Int64}, var"#combine#5"}}(var"#3#7"{Vector{Int64}, var"#combine#5"}([1], var"#combine#5"())), length(cont)=0))

julia> @inferred TypeClasses.flatmap(f_flatmap, e1_f)  # infers perfectly
Eff(effectful=NoEffect{Vector{Int64}}([1, 20]), length(cont)=0)

julia> function test_infers(e1, e2)
           f_flatmap, e1_f = prepare_test(e1, e2)
           TypeClasses.flatmap(f_flatmap, e1_f)
       end
test_infers (generic function with 1 method)

julia>

julia> @inferred test_infers(e1, e2)  # infers perfectly
Eff(effectful=NoEffect{Vector{Int64}}([1, 20]), length(cont)=0)

julia>     combine(v1, v2) = [v1; v2]
ERROR: error in method definition: function TypeClasses.combine must be explicitly imported to be extended
Stacktrace:
 [1] top-level scope
   @ none:0
 [2] top-level scope
   @ REPL[14]:1

julia>     curried_combine(v1) = v2 -> combine(v1, v2)
curried_combine (generic function with 1 method)

julia>     e1_f = map(curried_combine, e1)
Eff(effectful=NoEffect{var"#10#11"{Vector{Int64}}}(var"#10#11"{Vector{Int64}}([1])), length(cont)=0)

julia>     f_flatmap(f) = TypeClasses.map(v2 -> f(v2), e2)
ERROR: cannot define function f_flatmap; it already has a value
Stacktrace:
 [1] top-level scope
   @ none:0
 [2] top-level scope
   @ REPL[17]:1

julia>     f_flatmap, e1_f
(f_flatmap, Eff(effectful=NoEffect{var"#10#11"{Vector{Int64}}}(var"#10#11"{Vector{Int64}}([1])), length(cont)=0))

julia> function prepare_test(e1, e2)
           combine(v1, v2) = [v1; v2]
           curried_combine(v1) = v2 -> combine(v1, v2)

           e1_f = map(curried_combine, e1)
           f_flatmap(f) = TypeClasses.map(v2 -> f(v2), e2)
           f_flatmap, e1_f
       end
prepare_test (generic function with 1 method)

julia>

julia> f_flatmap, e1_f = prepare_test(e1, e2)
(f_flatmap, Eff(effectful=NoEffect{var"#14#18"{Vector{Int64}, var"#combine#16"}}(var"#14#18"{Vector{Int64}, var"#combine#16"}([1], var"#combine#16"())), length(cont)=0))

julia> @inferred TypeClasses.flatmap(f_flatmap, e1_f)  # infers perfectly
Eff(effectful=NoEffect{Vector{Int64}}([1, 20]), length(cont)=0)

julia> function test_infers(e1, e2)
           f_flatmap, e1_f = prepare_test(e1, e2)
           TypeClasses.flatmap(f_flatmap, e1_f)
       end
test_infers (generic function with 1 method)

julia>

julia> @inferred test_infers(e1, e2)  # infers perfectly
Eff(effectful=NoEffect{Vector{Int64}}([1, 20]), length(cont)=0)

julia> function prepare_test(e1, e2)
           combine(v1, v2) = [v1; v2]
           curried_combine(v1) = v2 -> combine(v1, v2)

           e1_f = map(curried_combine, e1)
           f_flatmap(f) = TypeClasses.map(v2 -> f(v2), e2)
           f_flatmap, e1_f
       end
prepare_test (generic function with 1 method)

julia> function test_infers(e1, e2)
           f_flatmap, e1_f = prepare_test(e1, e2)
           TypeClasses.flatmap(f_flatmap, e1_f)
       end
test_infers (generic function with 1 method)

julia>

julia> @inferred test_infers(e1, e2)  # infers perfectly
ERROR: return type ExtensibleEffects.Eff{NoEffect{Vector{Int64}}, Tuple{}} does not match inferred return type ExtensibleEffects.Eff
Stacktrace:
 [1] error(s::String)
   @ Base .\error.jl:33
 [2] top-level scope
   @ REPL[26]:100: 
Copy and pasting this into my Julia 1.7.2 REPL results in `@inferred test_infers(e1, e2)` failing.
using Pkg
Pkg.activate(; temp = true)
Pkg.add(["ExtensibleEffects", "TypeClasses", "Test"])

using ExtensibleEffects
using TypeClasses
using Test

vector_of_eff_of_vector = map(x -> noeffect([x]), [1, 20])

e1 = vector_of_eff_of_vector[1]
e2 = vector_of_eff_of_vector[2]

function prepare_test(e1, e2)
    combine(v1, v2) = [v1; v2]
    curried_combine(v1) = v2 -> combine(v1, v2)

    e1_f = map(curried_combine, e1)
    f_flatmap(f) = TypeClasses.map(v2 -> f(v2), e2)
    f_flatmap, e1_f
end

f_flatmap, e1_f = prepare_test(e1, e2)

@inferred TypeClasses.flatmap(f_flatmap, e1_f)  # infers perfectly

function test_infers(e1, e2)
    f_flatmap, e1_f = prepare_test(e1, e2)
    TypeClasses.flatmap(f_flatmap, e1_f)
end

@inferred test_infers(e1, e2)  # infers perfectly

curried_combine(v1) = v2 -> combine(v1, v2)

e1_f = map(curried_combine, e1)

f_flatmap, e1_f

function prepare_test(e1, e2)
    combine(v1, v2) = [v1; v2]
    curried_combine(v1) = v2 -> combine(v1, v2)

    e1_f = map(curried_combine, e1)
    f_flatmap(f) = TypeClasses.map(v2 -> f(v2), e2)
    f_flatmap, e1_f
end

f_flatmap, e1_f = prepare_test(e1, e2)

@inferred TypeClasses.flatmap(f_flatmap, e1_f)  # infers perfectly

function test_infers(e1, e2)
    f_flatmap, e1_f = prepare_test(e1, e2)
    TypeClasses.flatmap(f_flatmap, e1_f)
end

@inferred test_infers(e1, e2)  # infers perfectly

function prepare_test(e1, e2)
    combine(v1, v2) = [v1; v2]
    curried_combine(v1) = v2 -> combine(v1, v2)

    e1_f = map(curried_combine, e1)
    f_flatmap(f) = TypeClasses.map(v2 -> f(v2), e2)
    f_flatmap, e1_f
end

function test_infers(e1, e2)
    f_flatmap, e1_f = prepare_test(e1, e2)
    TypeClasses.flatmap(f_flatmap, e1_f)
end
@inferred test_infers(e1, e2)  # now it breaks?

The session is reproducible on multiple computers. There appears to be a bug with the inference engine.

Minimized script resulting in broken inference
using Pkg
Pkg.activate(; temp = true)
Pkg.add(["ExtensibleEffects", "TypeClasses", "Test"])

using ExtensibleEffects
using TypeClasses
using Test

vector_of_eff_of_vector = map(x -> noeffect([x]), [1, 20])

e1 = vector_of_eff_of_vector[1]
e2 = vector_of_eff_of_vector[2]

function prepare_test(e1, e2)
    combine(v1, v2) = [v1; v2]
    curried_combine(v1) = v2 -> combine(v1, v2)

    e1_f = map(curried_combine, e1)
    f_flatmap(f) = TypeClasses.map(v2 -> f(v2), e2)
    f_flatmap, e1_f
end

function test_infers(e1, e2)
    f_flatmap, e1_f = prepare_test(e1, e2)
    TypeClasses.flatmap(f_flatmap, e1_f)
end

@inferred test_infers(e1, e2)  # now it breaks?
Minimal script where inference succeeds. Running `TypeClasses.flatmap(...)` has a side effect.
using Pkg
Pkg.activate(; temp = true)
Pkg.add(["ExtensibleEffects", "TypeClasses", "Test"])

using ExtensibleEffects
using TypeClasses
using Test

vector_of_eff_of_vector = map(x -> noeffect([x]), [1, 20])

e1 = vector_of_eff_of_vector[1]
e2 = vector_of_eff_of_vector[2]

function prepare_test(e1, e2)
    combine(v1, v2) = [v1; v2]
    curried_combine(v1) = v2 -> combine(v1, v2)

    e1_f = map(curried_combine, e1)
    f_flatmap(f) = TypeClasses.map(v2 -> f(v2), e2)
    f_flatmap, e1_f
end

TypeClasses.flatmap(prepare_test(e1, e2)...)  # infers perfectly

function test_infers(e1, e2)
    f_flatmap, e1_f = prepare_test(e1, e2)
    TypeClasses.flatmap(f_flatmap, e1_f)
end

@inferred test_infers(e1, e2)  # infers perfectly
Minimal script where inference succeeds at first, and then fails. Redefining `prepare_test` invalidates the side effect.
using Pkg
Pkg.activate(; temp = true)
Pkg.add(["ExtensibleEffects", "TypeClasses", "Test"])

using ExtensibleEffects
using TypeClasses
using Test

vector_of_eff_of_vector = map(x -> noeffect([x]), [1, 20])

e1 = vector_of_eff_of_vector[1]
e2 = vector_of_eff_of_vector[2]

function prepare_test(e1, e2)
    combine(v1, v2) = [v1; v2]
    curried_combine(v1) = v2 -> combine(v1, v2)

    e1_f = map(curried_combine, e1)
    f_flatmap(f) = TypeClasses.map(v2 -> f(v2), e2)
    f_flatmap, e1_f
end

TypeClasses.flatmap(prepare_test(e1, e2)...)  # infers perfectly

function test_infers(e1, e2)
    f_flatmap, e1_f = prepare_test(e1, e2)
    TypeClasses.flatmap(f_flatmap, e1_f)
end

@inferred test_infers(e1, e2)  # infers perfectly

function prepare_test(e1, e2)
    combine(v1, v2) = [v1; v2]
    curried_combine(v1) = v2 -> combine(v1, v2)

    e1_f = map(curried_combine, e1)
    f_flatmap(f) = TypeClasses.map(v2 -> f(v2), e2)
    f_flatmap, e1_f
end

@inferred test_infers(e1, e2)  # now it breaks?
2 Likes