Repository: JuliaLang/julia
File: JuliaLowering/test/closures.jl (Julia)

Code before:
@test JuliaLowering.include_string(test_mod, """
begin
    function f_many_closure_sp()
        function (); function (); function (x::T) where T; (x, T) end; end; end
    end
    f_many_closure_sp()()()(1)
end
""") == (1, Int)

@test_broken JuliaLowering.include_string(test_mod, """
begin
    function f_many_closure_sp_capt(x::T where T)
        function (); function (); function (); (x, T) end; end; end
    end
    f_many_closure_sp_capt(1)()()()
end
""") == (1, Int)

@test_broken JuliaLowering.include_string(test_mod, """
begin
    function f_argcapt_sp(x::T) where T
        (inner_x::T)->(x, inner_x, T)
    end
    f_argcapt_sp(1)(2)
end
""") == (1, 2, Int)

# Note this doesn't work in flisp either
@test_broken JuliaLowering.include_string(test_mod, """
begin
    function f_typevarcapt_sp(x::T) where T
        function inner(y::U) where {U<:T}
            (x,y,T,U)
        end
    end
    f_typevarcapt_sp(1)(2)
end
""") == (1,2,Int,Int)

# https://github.com/JuliaLang/JuliaLowering.jl/issues/134#issuecomment-3739626003
JuliaLowering.include_string(test_mod, """
function f_update_outer_capture()
    local response # declare outside closure
    f = ()->begin
        response = 1
    end
    f()
    return (f, response)
end
""")
let (f, response) = test_mod.f_update_outer_capture()

Review comment (bug):
This one seems to be a bug, yes.

I thought I tried to make this work. But maybe I'm just remembering reading the flisp code which goes to extra lengths to get selected cases working when inner method declarations depend on static parameters from the outer function.

If I remember flisp makes this work by making the type of `inner` parametric on `T`

Code after:
@test JuliaLowering.include_string(test_mod, """
begin
    function f_many_closure_sp()
        function (); function (); function (x::T) where T; (x, T) end; end; end
    end
    f_many_closure_sp()()()(1)
end
""") == (1, Int)

@test JuliaLowering.include_string(test_mod, """
begin
    function f_many_closure_sp_capt(x::T) where T
        function (); function (); function (); (x, T) end; end; end
    end
    f_many_closure_sp_capt(1)()()()
end
""") == (1, Int)

@test_broken JuliaLowering.include_string(test_mod, """
begin
    function f_argcapt_sp(x::T) where T
        (inner_x::T)->(x, inner_x, T)
    end
    f_argcapt_sp(1)(2)
end
""") == (1, 2, Int)

# Inner method typevar `U` depending on a static parameter `T` so hoisting the
# method def for `inner` out to top level would require detecting this and
# making `inner` parametric on `T`.  Note this doesn't work in flisp either.
@test_broken JuliaLowering.include_string(test_mod, """
begin
    function f_typevarcapt_sp(x::T) where T
        function inner(y::U) where {U<:T}
            (x,y,T,U)
        end
    end
    f_typevarcapt_sp(1)(2)
end
""") == (1,2,Int,Int)

# https://github.com/JuliaLang/JuliaLowering.jl/issues/134#issuecomment-3739626003
JuliaLowering.include_string(test_mod, """
function f_update_outer_capture()
    local response # declare outside closure
    f = ()->begin
        response = 1
    end
    f()
    return (f, response)
end