Skip to content

Commit

Permalink
Fix so method errors caused by keywords is displayed as the original …
Browse files Browse the repository at this point in the history
…method in show_method_candidates with a text stating the not matching keyword. Fix #15639
  • Loading branch information
dhoegh committed May 30, 2016
1 parent f54a935 commit a1118cb
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 15 deletions.
53 changes: 46 additions & 7 deletions base/replutil.jl
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,16 @@ function showerror(io::IO, ex::MethodError)
ft = typeof(f)
name = ft.name.mt.name
f_is_function = false
kwargs = Dict{Any,Any}()
if startswith(string(ft.name), "#kw#")
f = ex.args[2]
ft = typeof(f)
name = ft.name.mt.name
arg_types_param = arg_types_param[3:end]
temp = ex.args[1]
kwargs = [(temp[i*2-1], temp[i*2]) for i in 1:(length(temp) ÷ 2)]
ex = MethodError(f, ex.args[3:end])
end
if f == Base.convert && length(arg_types_param) == 2 && !is_arg_types
f_is_function = true
# See #13033
Expand Down Expand Up @@ -150,6 +160,13 @@ function showerror(io::IO, ex::MethodError)
print(io, "::$typ")
i == length(arg_types_param) || print(io, ", ")
end
if 0 < length(kwargs)
print(io, "; ")
for (i ,(k, v)) in enumerate(kwargs)
print(io, k, "=", v)
i == length(kwargs) || print(io, ", ")
end
end
print(io, ")")
end
if ft <: AbstractArray
Expand Down Expand Up @@ -189,7 +206,7 @@ function showerror(io::IO, ex::MethodError)
"\nsince type constructors fall back to convert methods.")
end
try
show_method_candidates(io, ex)
show_method_candidates(io, ex, kwargs)
catch
warn(io, "Error showing method candidates, aborted")
end
Expand Down Expand Up @@ -222,7 +239,7 @@ function showerror_nostdio(err, msg::AbstractString)
ccall(:jl_printf, Cint, (Ptr{Void},Cstring), stderr_stream, "\n")
end

function show_method_candidates(io::IO, ex::MethodError)
function show_method_candidates(io::IO, ex::MethodError, kwargs=Tuple{Symbol, Any}[])
is_arg_types = isa(ex.args, DataType)
arg_types = is_arg_types ? ex.args : typesof(ex.args...)
arg_types_param = Any[arg_types.parameters...]
Expand All @@ -233,7 +250,7 @@ function show_method_candidates(io::IO, ex::MethodError)
else
f = ex.f
end

ft = typeof(f)
lines = []
# These functions are special cased to only show if first argument is matched.
special = f in [convert, getindex, setindex!]
Expand Down Expand Up @@ -262,7 +279,6 @@ function show_method_candidates(io::IO, ex::MethodError)
use_constructor_syntax = isa(func, Type)
print(buf, use_constructor_syntax ? func : typeof(func).name.mt.name)
end
right_matches = 0
tv = method.tvars
if !isa(tv,SimpleVector)
tv = Any[tv]
Expand Down Expand Up @@ -318,17 +334,19 @@ function show_method_candidates(io::IO, ex::MethodError)
end
end

if right_matches > 0
if right_matches > 0 || length(ex.args) < 2
if length(t_i) < length(sig)
# If the methods args is longer than input then the method
# arguments is printed as not a match
for sigtype in sig[length(t_i)+1:end]
for (k, sigtype) in enumerate(sig[length(t_i)+1:end])
if Base.isvarargtype(sigtype)
sigstr = string(sigtype.parameters[1], "...")
else
sigstr = string(sigtype)
end
print(buf, ", ")
if !((min(length(t_i), length(sig)) == 0) && k==1)
print(buf, ", ")
end
if Base.have_color
Base.with_output_color(:red, buf) do buf
print(buf, "::$sigstr")
Expand All @@ -338,7 +356,28 @@ function show_method_candidates(io::IO, ex::MethodError)
end
end
end
kwords = Symbol[]
if isdefined(ft.name.mt, :kwsorter)
kwsorter_t = typeof(ft.name.mt.kwsorter)
kwords = kwarg_decl(method.sig, kwsorter_t)
length(kwords) > 0 && print(buf, "; ", join(kwords, ", "))
end
print(buf, ")")
if 0 < length(kwargs)
unexpected = Symbol[]
if isempty(kwords) || !(any(endswith(string(kword), "...") for kword in kwords))
for (k, v) in kwargs
if !(k in kwords)
push!(unexpected, k)
end
end
end
if 0 < length(unexpected)
Base.with_output_color(:red, buf) do buf
print(buf, " got an unrecognized keyword argument \"", join(unexpected, "\", \""), "\"")
end
end
end
push!(lines, (buf, right_matches))
end
end
Expand Down
50 changes: 42 additions & 8 deletions test/replutil.jl
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,19 @@ no_color = no_color = "\nClosest candidates are:\n method_c3(::Float64, !Matche
test_have_color(buf, color, no_color)

# Test for the method error in issue #8651
Base.show_method_candidates(buf, MethodError(readline,("",)))
test_have_color(buf, "\e[0m\nClosest candidates are:\n readline(::AbstractString)\e[0m", "\nClosest candidates are:\n readline(::AbstractString)")
method_c4() = true
method_c4(x::AbstractString) = false
Base.show_method_candidates(buf, MethodError(method_c4,("",)))
test_have_color(buf, "\e[0m\nClosest candidates are:\n method_c4(::AbstractString)\n method_c4()\e[0m", "\nClosest candidates are:\n method_c4(::AbstractString)\n method_c4()")

method_c4(::Type{Float64}) = true
Base.show_method_candidates(buf, MethodError(method_c4,(Float64,)))
test_have_color(buf, "\e[0m\nClosest candidates are:\n method_c4(::Type{Float64})\e[0m",
"\nClosest candidates are:\n method_c4(::Type{Float64})")
method_c5(::Type{Float64}) = true
Base.show_method_candidates(buf, MethodError(method_c5,(Float64,)))
test_have_color(buf, "\e[0m\nClosest candidates are:\n method_c5(::Type{Float64})\e[0m",
"\nClosest candidates are:\n method_c5(::Type{Float64})")

Base.show_method_candidates(buf, MethodError(method_c4,(Int32,)))
test_have_color(buf, "", "")
Base.show_method_candidates(buf, MethodError(method_c5,(Int32,)))
test_have_color(buf, "\e[0m\nClosest candidates are:\n method_c5(\e[1m\e[31m::Type{Float64}\e[0m)\e[0m",
"\nClosest candidates are:\n method_c5(!Matched::Type{Float64})")

type Test_type end
test_type = Test_type()
Expand All @@ -83,6 +86,37 @@ Base.show_method_candidates(buf, MethodError(PR16155,(Int64(3), 2.0, Int64(3))))
test_have_color(buf, "\e[0m\nClosest candidates are:\n PR16155(::Int64, ::Any)\n PR16155(::Any, ::Any)\n PR16155{T}(::Any)\e[0m",
"\nClosest candidates are:\n PR16155(::Int64, ::Any)\n PR16155(::Any, ::Any)\n PR16155{T}(::Any)")

method_c6(; x=1) = x
method_c6(a; y=1) = y
m_error = try method_c6(y=1) catch e; e; end
showerror(buf, m_error)
error_out = takebuf_string(buf)
m_error = try method_c6(1, x=1) catch e; e; end
showerror(buf, m_error)
error_out1 = takebuf_string(buf)

if Base.have_color
@test contains(error_out, "method_c6(; x)\e[1m\e[31m got an unrecognized keyword argument \"y\"\e[0m")
@test contains(error_out, "method_c6(\e[1m\e[31m::Any\e[0m; y)")
@test contains(error_out1, "method_c6(::Any; y)\e[1m\e[31m got an unrecognized keyword argument \"x\"\e[0m")
else
@test contains(error_out, "method_c6(; x) got an unrecognized keyword argument \"y\"")
@test contains(error_out, "method_c6(!Matched::Any; y)")
@test contains(error_out1, "method_c6(::Any; y) got an unrecognized keyword argument \"x\"")
end

method_c7(a, b; kargs...) = a
Base.show_method_candidates(buf, MethodError(method_c7, (1, 1)), [(:x, 1), (:y, 2)])
test_have_color(buf, "\e[0m\nClosest candidates are:\n method_c7(::Any, ::Any; kargs...)\e[0m",
"\nClosest candidates are:\n method_c7(::Any, ::Any; kargs...)")

addConstraint_15639(c::Int32) = c
addConstraint_15639(c::Int64; uncset=nothing) = addConstraint_15639(Int32(c), uncset=uncset)

Base.show_method_candidates(buf, MethodError(addConstraint_15639, (Int32(1),)), [(:uncset, nothing)])
test_have_color(buf, "\e[0m\nClosest candidates are:\n addConstraint_15639(::Int32)\e[1m\e[31m got an unrecognized keyword argument \"uncset\"\e[0m\n addConstraint_15639(\e[1m\e[31m::Int64\e[0m; uncset)\e[0m",
"\nClosest candidates are:\n addConstraint_15639(::Int32) got an unrecognized keyword argument \"uncset\"\n addConstraint_15639(!Matched::Int64; uncset)")

macro except_str(expr, err_type)
return quote
let err = nothing
Expand Down

0 comments on commit a1118cb

Please sign in to comment.