Skip to content

Re-enable tab completion of kwargs for large method tables #58012

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jun 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion stdlib/REPL/src/REPLCompletions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -910,7 +910,13 @@ function complete_keyword_argument!(suggestions::Vector{Completion},
kwargs_flag == 2 && return false # one of the previous kwargs is invalid

methods = Completion[]
complete_methods!(methods, funct, Any[Vararg{Any}], kwargs_ex, shift ? -1 : MAX_METHOD_COMPLETIONS, arg_pos == :kwargs)
# Limit kwarg completions to cases when function is concretely known; looking up
# matching methods for abstract functions — particularly `Any` or `Function` — can
# take many seconds to run over the thousands of possible methods. Note that
# isabstracttype would return naively return true for common constructor calls
# like Array, but the REPL's introspection here may know their Type{T}.
isconcretetype(funct) || return false
complete_methods!(methods, funct, Any[Vararg{Any}], kwargs_ex, -1, arg_pos == :kwargs)
# TODO: use args_ex instead of Any[Vararg{Any}] and only provide kwarg completion for
# method calls compatible with the current arguments.

Expand Down
29 changes: 29 additions & 0 deletions stdlib/REPL/test/replcompletions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2632,6 +2632,35 @@ const issue57780_orig = copy(issue57780)
test_complete_context("empty!(issue57780).", Main)
@test issue57780 == issue57780_orig

function g54131 end
for i in 1:498
@eval g54131(::Val{$i}) = i
end
g54131(::Val{499}; kwarg=true) = 499*kwarg
struct F54131; end
Base.getproperty(::F54131, ::Symbol) = Any[cos, sin, g54131][rand(1:3)]
f54131 = F54131()
@testset "performance of kwarg completion with large method tables" begin
# The goal here is to simply ensure we aren't hitting catestrophically bad
# behaviors when shift isn't pressed. The difference between good and bad
# is on the order of tens of milliseconds vs tens of seconds; using 1 sec as
# a very rough canary that is hopefully robust even in the noisy CI coalmines
s = "g54131(kwa"
a, b, c = completions(s, lastindex(s), @__MODULE__, #= shift =# false)
@test REPLCompletions.KeywordArgumentCompletion("kwarg") in a
@test (@elapsed completions(s, lastindex(s), @__MODULE__, false)) < 1

s = "f54131.x("
a, b, c = completions(s, lastindex(s), @__MODULE__, false)
@test only(a) isa REPLCompletions.TextCompletion
@test (@elapsed completions(s, lastindex(s), @__MODULE__, false)) < 1

s = "f54131.x(kwa"
a, b, c = completions(s, lastindex(s), @__MODULE__, false)
@test_broken REPLCompletions.KeywordArgumentCompletion("kwarg") in a
@test (@elapsed completions(s, lastindex(s), @__MODULE__, false)) < 1
end

# Completion inside string interpolation
let s = "\"example: \$varflo"
c, r = test_complete_foo(s)
Expand Down