Skip to content

Commit

Permalink
Added so JuliaLang#7714 also takes care of args... when considering a…
Browse files Browse the repository at this point in the history
… 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`.
  • Loading branch information
dhoegh committed Jan 14, 2015
1 parent 7f915c7 commit 5da9faa
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 17 deletions.
67 changes: 51 additions & 16 deletions base/replutil.jl
Original file line number Diff line number Diff line change
Expand Up @@ -165,27 +165,62 @@ function showerror(io::IO, ex::MethodError)
print(io, "since type constructors fall back to convert methods in julia v0.4.")
end

# Display up to three closest candidates
show_method_candidates(io, ex)
end

function show_method_candidates(io::IO, ex::MethodError)
# Displays the closest candidates of the given function by looping over the
# functions methods and counting the number of matching arguments.
lines = Array((IOBuffer, Int), 0)
name = isgeneric(ex.f) ? ex.f.env.name : :anonymous
for method in methods(ex.f)
n = length(ex.args)
if n != length(method.sig)
continue
end
buf = IOBuffer()
print(buf, " $(ex.f.env.name)(")
first = true
print(buf, " $name")
right_matches = 0
for (arg, sigtype) in Zip2{Any,Any}(ex.args, method.sig)
if first
first = false
tv = method.tvars
if !isa(tv,Tuple)
tv = (tv,)
end
if !isempty(tv)
show_delim_array(buf, tv, '{', ',', '}', false)
end
print(buf, "(")
t_i = Any[typeof(ex.args)...]
right_matches = 0
for i = 1 : min(length(t_i), length(method.sig))
i != 1 && print(buf, ", ")
# If isvarargtype then it checks wether the rest of the input arguements matches
# the varargtype
j = Base.isvarargtype(method.sig[i]) ? length(t_i) : i
# checks if the type of arg 1:i of the input intersects with the current method
t_in = typeintersect(method.sig[1:i], tuple(t_i[1:j]...))
if t_in == None
# If there is no typeintersect then the type signature from the method is
# inserted in t_i this insures if the type at the next i matches the type
# signature then there will be a type intersect
t_i[i] = method.sig[i]
Base.with_output_color(:red, buf) do buf
print(buf, "::$(method.sig[i])")
end
else
print(buf, ", ")
right_matches += j==i ? 1 : 0
print(buf, "::$(method.sig[i])")
end
if typeof(arg) <: sigtype
right_matches += 1
print(buf, "::$(sigtype)")
else
end
if length(t_i) > length(method.sig) && Base.isvarargtype(method.sig[end])
# It insures that methods like f(a::AbstractString...) gets the correct
# number of right_matches
for t in typeof(ex.args)[length(method.sig):end]
if t <: method.sig[end].parameters[1]
right_matches += 1
end
end
end
if length(t_i) < length(method.sig)
# If the methods args is longer than input then the method
# arguments is printed as not a match
for sigtype in method.sig[length(t_i)+1:end]
print(buf, ", ")
Base.with_output_color(:red, buf) do buf
print(buf, "::$(sigtype)")
end
Expand All @@ -196,7 +231,7 @@ function showerror(io::IO, ex::MethodError)
push!(lines, (buf, right_matches))
end
end
if length(lines) != 0
if length(lines) != 0 # Display up to three closest candidates
Base.with_output_color(:normal, io) do io
println(io, "\nClosest candidates are:")
sort!(lines, by = x -> -x[2])
Expand Down
41 changes: 41 additions & 0 deletions test/replutil.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
function test_have_color(buf, color, no_color)
if Base.have_color
@test takebuf_string(buf) == color
else
@test takebuf_string(buf) == no_color
end
end

fe(x::Float64, s::AbstractString...) = true
ge(x::Int32, args...) = true
ge(x::Int32, y::Float64 ,args...) = true
ge(x::Int32, y::Float64) = true
ge{T<:Real}(x::T, y::T, z::T) = true

buf = IOBuffer()
Base.show_method_candidates(buf, Base.MethodError(Repl_test_module.fe,(1, 1, "")))
no_color = "\nClosest candidates are:\n fe(::Float64, ::AbstractString...)\n"
test_have_color(buf,
"\e[0m\nClosest candidates are:\n fe(\e[1m\e[31m::Float64\e[0m, \e[1m\e[31m::AbstractString...\e[0m)\n\e[0m",
no_color)

Base.show_method_candidates(buf, Base.MethodError(Repl_test_module.fe,(1, "", "")))
test_have_color(buf,
"\e[0m\nClosest candidates are:\n fe(\e[1m\e[31m::Float64\e[0m, ::AbstractString...)\n\e[0m",
no_color)

# should match
Base.show_method_candidates(buf, Base.MethodError(Repl_test_module.fe,(1., "", "")))
test_have_color(buf,
"\e[0m\nClosest candidates are:\n fe(::Float64, ::AbstractString...)\n\e[0m",
no_color)

# Have no matches so should return empty
Base.show_method_candidates(buf, Base.MethodError(Repl_test_module.fe,(1, 1, 1)))
test_have_color(buf, "", "")


Base.show_method_candidates(buf, Base.MethodError(Repl_test_module.ge,(1., 1., 2)))
color = "\e[0m\nClosest candidates are:\n ge(\e[1m\e[31m::Int32\e[0m, ::Float64, ::Any...)\n ge(\e[1m\e[31m::Int32\e[0m, ::Any...)\n ge{T<:Real}(::T<:Real, ::T<:Real, \e[1m\e[31m::T<:Real\e[0m)\n ...\n\e[0m"
no_color = no_color = "\nClosest candidates are:\n ge(::Int32, ::Float64, ::Any...)\n ge(::Int32, ::Any...)\n ge{T<:Real}(::T<:Real, ::T<:Real, ::T<:Real)\n ...\n"
test_have_color(buf, color, no_color)
2 changes: 1 addition & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ testnames = [
"resolve", "pollfd", "mpfr", "broadcast", "complex", "socket",
"floatapprox", "readdlm", "reflection", "regex", "float16", "combinatorics",
"sysinfo", "rounding", "ranges", "mod2pi", "euler", "show",
"lineedit", "replcompletions", "repl", "sets", "test", "goto",
"lineedit", "replcompletions", "repl", "replutil", "sets", "test", "goto",
"llvmcall", "grisu", "nullable", "meta", "profile",
"libgit2", "docs", "base64", "parser"
]
Expand Down

0 comments on commit 5da9faa

Please sign in to comment.