diff --git a/stdlib/REPL/src/REPLCompletions.jl b/stdlib/REPL/src/REPLCompletions.jl index 8c72b20019d7ac..b40b4abc5af635 100644 --- a/stdlib/REPL/src/REPLCompletions.jl +++ b/stdlib/REPL/src/REPLCompletions.jl @@ -596,9 +596,10 @@ function complete_methods!(out::Vector{Completion}, @nospecialize(func), args_ex most_specific = ccall(:jl_gf_invoke_lookup, Any, (Any, UInt), intersec, typemax(UInt)) # `most_specific == method` indicates that there is no strictly more specific # method signature for these input types. - # `isnothing(most_specific)` indicates that the completed function call will - # not actually work. This can happen in case of method ambiguity. - # The completion is kept since it can be helpful to debug such ambiguity errors + # `isnothing(most_specific)` indicates that the completed function invoke will + # not actually work. This can happen in case of method ambiguity, or if the + # inferred argument types are not tight enough, which would make an invoke + # error because of the ambiguity, but the concrete function call still work. if isnothing(most_specific) || (most_specific::Method) == method push!(out, MethodCompletion(func, t_in, method, orig_method)) end diff --git a/stdlib/REPL/test/replcompletions.jl b/stdlib/REPL/test/replcompletions.jl index 1bc10725589f8c..d0499f7da6b595 100644 --- a/stdlib/REPL/test/replcompletions.jl +++ b/stdlib/REPL/test/replcompletions.jl @@ -96,6 +96,11 @@ let ex = quote test10(a, d::Integer, z::Signed...) = pass test10(s::String...) = pass + test11(a::Integer, b, c) = pass + test11(u, v::Integer, w) = pass + test11(x::Int, y::Int, z) = pass + test11(_, _, s::String) = pass + kwtest(; x=1, y=2, w...) = pass kwtest2(a; x=1, y=2, w...) = pass @@ -655,6 +660,57 @@ let s = "CompletionFoo.test10(\"a\", Union{Signed,Bool,String}[3][1], " @test !any(str->occursin("test10(a::Integer, b::Integer, c)", str), c) end +# Test method completion with ambiguity +let s = "CompletionFoo.test11(Integer[false][1], Integer[14][1], " + c, r, res = test_complete(s) + @test !res + @test length(c) == 4 + @test all(startswith("test11("), c) + @test allunique(c) +end + +let s = "CompletionFoo.test11(Integer[-7][1], Integer[0x6][1], 6," + c, r, res = test_complete(s) + @test !res + @test length(c) == 3 + @test any(str->occursin("test11(a::Integer, b, c)", str), c) + @test any(str->occursin("test11(u, v::Integer, w)", str), c) + @test any(str->occursin("test11(x::$Int, y::$Int, z)", str), c) +end + +let s = "CompletionFoo.test11(3, 4," + c, r, res = test_complete(s) + @test !res + @test length(c) == 2 + @test any(str->occursin("test11(x::$Int, y::$Int, z)", str), c) + @test any(str->occursin("test11(::Any, ::Any, s::String)", str), c) +end + +let s = "CompletionFoo.test11(0x8, 5," + c, r, res = test_complete(s) + @test !res + @test length(c) == 3 + @test any(str->occursin("test11(a::Integer, b, c)", str), c) + @test any(str->occursin("test11(u, v::Integer, w)", str), c) + @test any(str->occursin("test11(::Any, ::Any, s::String)", str), c) +end + +let s = "CompletionFoo.test11(0x8, 'c'," + c, r, res = test_complete(s) + @test !res + @test length(c) == 2 + @test any(str->occursin("test11(a::Integer, b, c)", str), c) + @test any(str->occursin("test11(::Any, ::Any, s::String)", str), c) +end + +let s = "CompletionFoo.test11('d', 3," + c, r, res = test_complete(s) + @test !res + @test length(c) == 2 + @test any(str->occursin("test11(u, v::Integer, w)", str), c) + @test any(str->occursin("test11(::Any, ::Any, s::String)", str), c) +end + # Test of inference based getfield completion let s = "(1+2im)." c,r = test_complete(s)