Skip to content

Commit ab18138

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 7f915c7 commit ab18138

File tree

3 files changed

+91
-17
lines changed

3 files changed

+91
-17
lines changed

base/replutil.jl

+50-16
Original file line numberDiff line numberDiff line change
@@ -165,27 +165,61 @@ function showerror(io::IO, ex::MethodError)
165165
print(io, "since type constructors fall back to convert methods in julia v0.4.")
166166
end
167167

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

test/replutil.jl

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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+
fe(x::Int, s::AbstractString...) = pass
10+
buf = IOBuffer()
11+
Base.show_method_candidates(buf, Base.MethodError(fe,(1.,1,"")))
12+
no_color = "\nClosest candidates are:\n fe(::Int64, ::AbstractString...)\n"
13+
test_have_color(buf,
14+
"\e[0m\nClosest candidates are:\n fe(\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(fe,(1.,"","")))
18+
test_have_color(buf,
19+
"\e[0m\nClosest candidates are:\n fe(\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(fe,(1,"","")))
24+
test_have_color(buf,
25+
"\e[0m\nClosest candidates are:\n fe(::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(fe,(1.,1,1)))
30+
test_have_color(buf, "", "")
31+
32+
ge(x::Int, args...) = pass
33+
ge(x::Int, y::Float64 ,args...) = pass
34+
ge(x::Int, y::Float64) = pass
35+
ge{T<:Real}(x::T, y::T, z::T) = pass
36+
Base.show_method_candidates(buf, Base.MethodError(ge,(1.,1.,2)))
37+
color = "\e[0m\nClosest candidates are:\n ge(\e[1m\e[31m::Int64\e[0m, ::Float64, ::Any...)\n ge(\e[1m\e[31m::Int64\e[0m, ::Any...)\n ge{T<:Real}(::T<:Real, ::T<:Real, \e[1m\e[31m::T<:Real\e[0m)\n ...\n\e[0m"
38+
no_color = no_color = "\nClosest candidates are:\n ge(::Int64, ::Float64, ::Any...)\n ge(::Int64, ::Any...)\n ge{T<:Real}(::T<:Real, ::T<:Real, ::T<:Real)\n ...\n"
39+
test_have_color(buf, color, no_color)
40+
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)