Skip to content

Commit be95d67

Browse files
committed
Added so JuliaLang#7714 also takes care of args... when considering a match and
removed the requirement of equal lengths of args. The match also takes into account that parametric methods args needs to have the same type for one tvar using typeintersect. There is also added test of `show_method_candidates`.
1 parent 48e980b commit be95d67

File tree

3 files changed

+92
-17
lines changed

3 files changed

+92
-17
lines changed

base/replutil.jl

+50-16
Original file line numberDiff line numberDiff line change
@@ -167,28 +167,62 @@ function showerror(io::IO, e::MethodError)
167167
print(io, "This may have arisen from a call to the constructor $(e.args[1])(...), ")
168168
print(io, "since type constructors fall back to convert methods in julia v0.4.")
169169
end
170+
171+
show_method_candidates(io, e)
172+
end
170173

171-
# Display up to three closest candidates
174+
function show_method_candidates(io::IO, e::MethodError)
175+
# Displays the closest candidates of the given function by looping over the
176+
# functions methods and counting the number of matching arguments.
172177
lines = Array((IOBuffer, Int), 0)
173178
for method in methods(e.f)
174-
n = length(e.args)
175-
if n != length(method.sig)
176-
continue
177-
end
178179
buf = IOBuffer()
179-
print(buf, " $(e.f.env.name)(")
180-
first = true
180+
print(buf, " $(e.f.env.name)")
181+
right_matches = 0
182+
tv = method.tvars
183+
if !isa(tv,Tuple)
184+
tv = (tv,)
185+
end
186+
if !isempty(tv)
187+
show_delim_array(buf, tv, '{', ',', '}', false)
188+
end
189+
print(buf, "(")
190+
t_i = Any[typeof(e.args)...]
181191
right_matches = 0
182-
for (arg, sigtype) in Zip2{Any,Any}(e.args, method.sig)
183-
if first
184-
first = false
192+
for i = 1 : min(length(t_i), length(method.sig))
193+
i != 1 && print(buf, ", ")
194+
# If isvarargtype then it checks wether the rest of the input arguements matches
195+
# the varargtype
196+
j = Base.isvarargtype(method.sig[i]) ? length(t_i) : i
197+
# checks if the type of arg 1:i of the input intersects with the current method
198+
t_in = typeintersect(method.sig[1:i], tuple(t_i[1:j]...))
199+
if t_in == None
200+
# If there is no typeintersect then the type signature from the method is
201+
# inserted in t_i this insures if the type at the next i matches the type
202+
# signature then there will be a type intersect
203+
t_i[i] = method.sig[i]
204+
Base.with_output_color(:red, buf) do buf
205+
print(buf, "::$(method.sig[i])")
206+
end
185207
else
186-
print(buf, ", ")
208+
right_matches += j==i ? 1 : 0
209+
print(buf, "::$(method.sig[i])")
187210
end
188-
if typeof(arg) <: sigtype
189-
right_matches += 1
190-
print(buf, "::$(sigtype)")
191-
else
211+
end
212+
if length(t_i) > length(method.sig) && Base.isvarargtype(method.sig[end])
213+
# It insures that methods like f(a::AbstractString...) gets the correct
214+
# number of right_matches
215+
for t in typeof(e.args)[length(method.sig):end]
216+
if t <: method.sig[end].parameters[1]
217+
right_matches += 1
218+
end
219+
end
220+
end
221+
if length(t_i) < length(method.sig)
222+
# If the methods args is longer than input then the method
223+
# arguments is printed as not a match
224+
for sigtype in method.sig[length(t_i)+1:end]
225+
print(buf, ", ")
192226
Base.with_output_color(:red, buf) do buf
193227
print(buf, "::$(sigtype)")
194228
end
@@ -199,7 +233,7 @@ function showerror(io::IO, e::MethodError)
199233
push!(lines, (buf, right_matches))
200234
end
201235
end
202-
if length(lines) != 0
236+
if length(lines) != 0 # Display up to three closest candidates
203237
Base.with_output_color(:normal, io) do io
204238
println(io, "\nClosest candidates are:")
205239
sort!(lines, by = x -> -x[2])

test/replutil.jl

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
function test_have_color(buf, color, no_color)
2+
if Base.have_color
3+
@test takebuf_string(buf) == color
4+
else
5+
@test takebuf_string(buf) == no_color
6+
end
7+
end
8+
let
9+
f(x::Int, s::AbstractString...) = pass
10+
buf = IOBuffer()
11+
Base.show_method_candidates(buf, Base.MethodError(f,(1.,1,"")))
12+
no_color = "Closest candidates are:\n f(::Int64, ::AbstractString...)"
13+
test_have_color(buf,
14+
"\e[0m\nClosest candidates are:\n f(\e[1m\e[31m::Int64\e[0m, \e[1m\e[31m::AbstractString...\e[0m)\n\e[0m",
15+
no_color)
16+
17+
Base.show_method_candidates(buf, Base.MethodError(f,(1.,"","")))
18+
test_have_color(buf,
19+
"\e[0m\nClosest candidates are:\n f(\e[1m\e[31m::Int64\e[0m, ::AbstractString...)\n\e[0m",
20+
no_color)
21+
22+
# should match
23+
Base.show_method_candidates(buf, Base.MethodError(f,(1,"","")))
24+
test_have_color(buf,
25+
"\e[0m\nClosest candidates are:\n f(::Int64, ::AbstractString...)\n\e[0m",
26+
no_color)
27+
28+
# Have no matches so should return empty
29+
Base.show_method_candidates(buf, Base.MethodError(f,(1.,1,1)))
30+
test_have_color(buf, "", "")
31+
32+
g(x::Int, args...) = pass
33+
g(x::Int, y::Float64 ,args...) = pass
34+
g(x::Int, y::Float64) = pass
35+
g{T<:Real}(x::T, y::T, z::T) = pass
36+
Base.show_method_candidates(buf, Base.MethodError(g,(1.,1.,2)))
37+
color = "\e[0m\nClosest candidates are:\n g(\e[1m\e[31m::Int64\e[0m, ::Float64, ::Any...)\n g(\e[1m\e[31m::Int64\e[0m, ::Any...)\n g{T<:Real}(::T<:Real, ::T<:Real, \e[1m\e[31m::T<:Real\e[0m)\n ...\n\e[0m"
38+
no_color = no_color = "Closest candidates are:\n g(::Int64, ::Float64, ::Any...)\n g(::Int64, ::Any...)\n g{T<:Real}(::T<:Real, ::T<:Real, ::T<:Real)\n ..."
39+
test_have_color(buf, color, no_color)
40+
41+
end

test/runtests.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ testnames = [
99
"resolve", "pollfd", "mpfr", "broadcast", "complex", "socket",
1010
"floatapprox", "readdlm", "reflection", "regex", "float16", "combinatorics",
1111
"sysinfo", "rounding", "ranges", "mod2pi", "euler", "show",
12-
"lineedit", "replcompletions", "repl", "sets", "test", "goto",
12+
"lineedit", "replcompletions", "repl", "replutil", "sets", "test", "goto",
1313
"llvmcall", "grisu", "nullable", "meta", "profile",
1414
"libgit2", "docs", "base64", "parser"
1515
]

0 commit comments

Comments
 (0)