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

Code before:
    @test JuliaLowering.include_string(test_mod, """
    begin
        function f_body_nospecialize_default(x, y=1)
            @nospecialize
            (x, y)
        end
        (f_body_nospecialize_default(10, 20), f_body_nospecialize_default(30))
    end
    """) == ((10, 20), (30, 1))
    # The 2-arg method has nospecialize on y (bit 2), the 1-arg forwarding method has no y
    ms = collect(methods(test_mod.f_body_nospecialize_default))
    @test count(m -> m.nargs == 3 && m.nospecialize == -1, ms) == 1
    @test_broken count(m -> m.nargs == 2 && m.nospecialize == -1, ms) == 1

    # Body-level @nospecialize for methods with keyword arguments
    @test JuliaLowering.include_string(test_mod, """
    function f_body_nospecialize_with_kwargs(a; kw=1)
        @nospecialize a
        (a, kw)
    end
    (f_body_nospecialize_with_kwargs(1; kw=2), f_body_nospecialize_with_kwargs(3))
    """) == ((1,2), (3,1))
    # Although not tested here, the keyword body method (`var"#f_body_nospecialize_with_kwargs#0"`)'s
    # third argument (corresponding to `a`) should probably be nospecialized too.
    @test_broken only(methods(test_mod.f_body_nospecialize_with_kwargs)).nospecialize == 1
    @test_broken only(methods(Core.kwcall, (NamedTuple,typeof(test_mod.f_body_nospecialize_with_kwargs),Any))) == 1 << 2
end

@testset "Keyword functions" begin
    JuliaLowering.include_string(test_mod, """
    function f_kw_simple(a::Int=1, b::Float64=1.0; x::Char='a', y::Bool=true)
        (a, b, x, y)
    end
    """)

    @test test_mod.f_kw_simple()               === (1, 1.0, 'a', true)
    @test test_mod.f_kw_simple(x='b')          === (1, 1.0, 'b', true)
    @test test_mod.f_kw_simple(y=false)        === (1, 1.0, 'a', false)
    @test test_mod.f_kw_simple(x='b', y=false) === (1, 1.0, 'b', false)

    @test test_mod.f_kw_simple(20)                 === (20, 1.0, 'a', true)
    @test test_mod.f_kw_simple(20; x='b')          === (20, 1.0, 'b', true)
    @test test_mod.f_kw_simple(20; y=false)        === (20, 1.0, 'a', false)
    @test test_mod.f_kw_simple(20; x='b', y=false) === (20, 1.0, 'b', false)

    @test test_mod.f_kw_simple(20, 2.0)                 === (20, 2.0, 'a', true)
    @test test_mod.f_kw_simple(20, 2.0; x='b')          === (20, 2.0, 'b', true)
    @test test_mod.f_kw_simple(20, 2.0; y=false)        === (20, 2.0, 'a', false)
    @test test_mod.f_kw_simple(20, 2.0; x='b', y=false) === (20, 2.0, 'b', false)

    # Bad types for keyword args throw a type error

Review comment (bug):
```suggestion
    @test_broken only(methods(Core.kwcall, (NamedTuple,typeof(test_mod.f_body_nospecialize_with_kwargs),Any))).nospecialize == 1 << 2
```

Code after:
    @test JuliaLowering.include_string(test_mod, """
    begin
        function f_body_nospecialize_default(x, y=1)
            @nospecialize
            (x, y)
        end
        (f_body_nospecialize_default(10, 20), f_body_nospecialize_default(30))
    end
    """) == ((10, 20), (30, 1))
    # The 2-arg method has nospecialize on y (bit 2), the 1-arg forwarding method has no y
    ms = collect(methods(test_mod.f_body_nospecialize_default))
    @test count(m -> m.nargs == 3 && m.nospecialize == -1, ms) == 1
    @test_broken count(m -> m.nargs == 2 && m.nospecialize == -1, ms) == 1

    # Body-level @nospecialize for methods with keyword arguments
    @test JuliaLowering.include_string(test_mod, """
    function f_body_nospecialize_with_kwargs(a; kw=1)
        @nospecialize a
        (a, kw)
    end
    (f_body_nospecialize_with_kwargs(1; kw=2), f_body_nospecialize_with_kwargs(3))
    """) == ((1,2), (3,1))
    # Although not tested here, the keyword body method (`var"#f_body_nospecialize_with_kwargs#0"`)'s
    # third argument (corresponding to `a`) should probably be nospecialized too.
    @test_broken only(methods(test_mod.f_body_nospecialize_with_kwargs)).nospecialize == 1
    @test_broken only(methods(Core.kwcall, (NamedTuple,typeof(test_mod.f_body_nospecialize_with_kwargs),Any))).nospecialize == 1 << 2
end

@testset "Keyword functions" begin
    JuliaLowering.include_string(test_mod, """
    function f_kw_simple(a::Int=1, b::Float64=1.0; x::Char='a', y::Bool=true)
        (a, b, x, y)
    end
    """)

    @test test_mod.f_kw_simple()               === (1, 1.0, 'a', true)
    @test test_mod.f_kw_simple(x='b')          === (1, 1.0, 'b', true)
    @test test_mod.f_kw_simple(y=false)        === (1, 1.0, 'a', false)
    @test test_mod.f_kw_simple(x='b', y=false) === (1, 1.0, 'b', false)

    @test test_mod.f_kw_simple(20)                 === (20, 1.0, 'a', true)
    @test test_mod.f_kw_simple(20; x='b')          === (20, 1.0, 'b', true)
    @test test_mod.f_kw_simple(20; y=false)        === (20, 1.0, 'a', false)
    @test test_mod.f_kw_simple(20; x='b', y=false) === (20, 1.0, 'b', false)

    @test test_mod.f_kw_simple(20, 2.0)                 === (20, 2.0, 'a', true)
    @test test_mod.f_kw_simple(20, 2.0; x='b')          === (20, 2.0, 'b', true)
    @test test_mod.f_kw_simple(20, 2.0; y=false)        === (20, 2.0, 'a', false)
    @test test_mod.f_kw_simple(20, 2.0; x='b', y=false) === (20, 2.0, 'b', false)

    # Bad types for keyword args throw a type error