Skip to content

Commit

Permalink
Provide the actual list of factored methods through FactoredMethod
Browse files Browse the repository at this point in the history
  • Loading branch information
Liozou committed Jun 7, 2022
1 parent 6d746f6 commit 872f646
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 26 deletions.
42 changes: 21 additions & 21 deletions base/methodshow.jl
Original file line number Diff line number Diff line change
Expand Up @@ -208,11 +208,10 @@ end
# type for pretty-printing methods corresponding to the same definition site with different
# optional arguments
struct FactoredMethod
m::Method
mandatory::Int # number of non-optional arguments
m::Vector{Method} # the different methods, by order of increasing nargs
kwargs::Vector{Symbol}
end
FactoredMethod(m::Method) = FactoredMethod(m, m.nargs, kwarg_decl(m))
FactoredMethod(m::Method) = FactoredMethod([m], kwarg_decl(m))

struct FactoredMethodList
list::Vector{FactoredMethod}
Expand All @@ -227,26 +226,27 @@ function FactoredMethodList(ms::MethodList)
positions = Vector{Int}[[I[1]]]
for _i in 2:length(ms)
i = I[_i]
last_m = list[end]
last_m = last(last(list).m)
m = ms[i]
newmethod = true
# Check whether m and last_m.m could refer to the same method except for the
# Check whether m and last_m could refer to the same method except for the
# addition of a new optional argument
if !last_m.m.isva && # the vararg variant is always last
isempty(last_m.kwargs) && # the kwargs variant is always last
m.file == last_m.m.file && m.line == last_m.m.line && # same location
startswith(m.slot_syms, last_m.m.slot_syms) && # same argument names so far
(m.nargs == last_m.m.nargs + 1 || (m.isva && m.nargs == last_m.m.nargs + 2))
if !last_m.isva && # the vararg variant is always last
isempty(last(list).kwargs) && # the kwargs variant is always last
m.file == last_m.file && m.line == last_m.line && # same location
startswith(m.slot_syms, last_m.slot_syms) && # same argument names so far
(m.nargs == last_m.nargs + 1 || (m.isva && m.nargs == last_m.nargs + 2))
# number of arguments consistent with one new optional argument (+ slurp)
unwrapped = Base.unwrap_unionall(m.sig).types
truncated = Tuple{unwrapped[1:last_m.m.nargs]...}
truncated = Tuple{unwrapped[1:last_m.nargs]...}
rewrapped = Base.rewrap_unionall(truncated, m.sig)
if rewrapped == last_m.m.sig # same argument types so far
if rewrapped == last_m.sig # same argument types so far
# At this point, we have determined that method m has a signature identical
# to that of last_m.m, except for one additional argument (+ slurp)
# to that of last_m, except for one additional argument (+ slurp)
newmethod = false
list[end] = FactoredMethod(m, last_m.mandatory, kwarg_decl(m))
push!(positions[end], i)
push!(last(list).m, m)
append!(last(list).kwargs, kwarg_decl(m)) # we ensure that only one of the methods has kwargs, if any
push!(last(positions), i)
end
end
if newmethod
Expand All @@ -259,7 +259,7 @@ function FactoredMethodList(ms::MethodList)
end

function show_method(io::IO, f::Union{Method,FactoredMethod}, html::Bool)
m = f isa FactoredMethod ? f.m : f
m = f isa FactoredMethod ? last(f.m) : f
tv, decls, file, line = arg_decl_parts(m, html)
sig = unwrap_unionall(m.sig)
if sig === Tuple
Expand All @@ -268,7 +268,7 @@ function show_method(io::IO, f::Union{Method,FactoredMethod}, html::Bool)
return
end
print(io, decls[1][2], "(")
supmandatory = 1 + (f isa FactoredMethod ? f.mandatory : m.nargs)
supmandatory = 1 + (f isa FactoredMethod ? first(f.m).nargs : m.nargs)
last_optional = m.nargs >= supmandatory ? m.nargs - m.isva : 0
for i in 2:m.nargs
i == supmandatory && print(io, '[')
Expand Down Expand Up @@ -376,7 +376,7 @@ function show_method_table(io::IO, ml::Union{MethodList,FactoredMethodList}, max
show_method_list_header(io, ms, str -> "\""*str*"\"")
end
rest = 0
local last
local last_meth

last_shown_line_infos = get(io, :last_shown_line_infos, nothing)
last_shown_line_infos === nothing || empty!(last_shown_line_infos)
Expand All @@ -390,19 +390,19 @@ function show_method_table(io::IO, ml::Union{MethodList,FactoredMethodList}, max
print(io, "[$n] ")
end
show(io, meth)
file, line = updated_methodloc(ml isa FactoredMethodList ? meth.m : meth)
file, line = updated_methodloc(ml isa FactoredMethodList ? last(meth.m) : meth)
if last_shown_line_infos !== nothing
push!(last_shown_line_infos, (string(file), line))
end
else
rest += 1
last = meth
last_meth = meth
end
end
if rest > 0
println(io)
if rest == 1
show(io, last)
show(io, last_meth)
else
print(io, "... $rest methods not shown")
if hasname
Expand Down
9 changes: 4 additions & 5 deletions stdlib/REPL/src/REPLCompletions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,8 @@ struct FieldCompletion <: Completion
end

struct MethodCompletion <: Completion
tt # may be used by an external consumer to infer return type, etc.
tt::Vector{Any} # may be used by an external consumer to infer return type, etc.
method::Base.FactoredMethod
MethodCompletion(@nospecialize(tt), method::Base.FactoredMethod) = new(tt, method)
end

struct BslashCompletion <: Completion
Expand Down Expand Up @@ -587,7 +586,7 @@ function complete_any_methods(ex_org::Expr, callee_module::Module, context_modul
filter!(out) do c
isa(c, TextCompletion) && return false
isa(c, MethodCompletion) || return true
sig = Base.unwrap_unionall(c.method.m.sig)::DataType
sig = Base.unwrap_unionall(last(c.method.m).sig)::DataType
return !all(T -> T === Any || T === Vararg{Any}, sig.parameters[2:end])
end
end
Expand Down Expand Up @@ -633,14 +632,14 @@ function complete_methods!(out::Vector{Completion}, @nospecialize(funct), args_e
mm = [m::Core.MethodMatch for m in ml]
first_m = mm[1].method
if first_m.sig === Tuple # Builtin
push!(out, MethodCompletion(t_in, Base.FactoredMethod(first_m)))
push!(out, MethodCompletion(Any[t_in], Base.FactoredMethod(first_m)))
return
end
mt = Base.get_methodtable(first_m)
fml = Base.FactoredMethodList(Base.MethodList([m.method for m in mm], mt))
for (fm, pos) in zip(fml.list, fml.positions)
# TODO: if kwargs_ex, filter out methods without kwargs?
push!(out, MethodCompletion(mm[last(pos)].spec_types, fm))
push!(out, MethodCompletion(Any[mm[p].spec_types for p in pos], fm))
end
end

Expand Down
7 changes: 7 additions & 0 deletions stdlib/REPL/test/replcompletions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,13 @@ let s = "CompletionFoo.test4(\"e\",r\" \","
@test s[r] == "CompletionFoo.test4"
end

# Test builtins method completion
let s = "typeof("
c, r = test_complete(s)
@test length(c) == 1
@test c[1] == "typeof(...) in Core"
end

# (As discussed in #19829, the Base.REPLCompletions.get_type function isn't
# powerful enough to analyze anonymous functions.)
let s = "CompletionFoo.test5(broadcast((x,y)->x==y, push!(Base.split(\"\",' '),\"\",\"\"), \"\"),"
Expand Down

0 comments on commit 872f646

Please sign in to comment.