Skip to content

Commit cb2e8c8

Browse files
authored
fix #34824, improve various cases of showing method signatures (#35862)
1 parent 759e78c commit cb2e8c8

File tree

4 files changed

+53
-65
lines changed

4 files changed

+53
-65
lines changed

base/errorshow.jl

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -260,12 +260,9 @@ function showerror(io::IO, ex::MethodError)
260260
isdefined(ft.name.module, name) &&
261261
ft == typeof(getfield(ft.name.module, name))
262262
f_is_function = true
263-
print(io, "no method matching ", name)
264-
elseif isa(f, Type)
265-
print(io, "no method matching ", f)
266-
else
267-
print(io, "no method matching (::", ft, ")")
268263
end
264+
print(io, "no method matching ")
265+
show_signature_function(io, isa(f, Type) ? Type{f} : typeof(f))
269266
print(io, "(")
270267
for (i, typ) in enumerate(arg_types_param)
271268
print(io, "::", typ)
@@ -339,7 +336,9 @@ striptype(::Type{T}) where {T} = T
339336
striptype(::Any) = nothing
340337

341338
function showerror_ambiguous(io::IO, meth, f, args)
342-
print(io, "MethodError: ", f, "(")
339+
print(io, "MethodError: ")
340+
show_signature_function(io, isa(f, Type) ? Type{f} : typeof(f))
341+
print(io, "(")
343342
p = args.parameters
344343
for (i,a) in enumerate(p)
345344
print(io, "::", a)
@@ -415,9 +414,7 @@ function show_method_candidates(io::IO, ex::MethodError, @nospecialize kwargs=()
415414
# function itself doesn't match
416415
continue
417416
else
418-
# TODO: use the methodshow logic here
419-
use_constructor_syntax = isa(func, Type)
420-
print(iob, use_constructor_syntax ? func : typeof(func).name.mt.name)
417+
show_signature_function(iob, s1)
421418
end
422419
print(iob, "(")
423420
t_i = copy(arg_types_param)

base/methodshow.jl

Lines changed: 6 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ function method_argnames(m::Method)
4848
return argnames[1:m.nargs]
4949
end
5050

51-
function arg_decl_parts(m::Method)
51+
function arg_decl_parts(m::Method, html=false)
5252
tv = Any[]
5353
sig = m.sig
5454
while isa(sig, UnionAll)
@@ -65,6 +65,8 @@ function arg_decl_parts(m::Method)
6565
end
6666
decls = Tuple{String,String}[argtype_decl(show_env, argnames[i], sig, i, m.nargs, m.isva)
6767
for i = 1:m.nargs]
68+
decls[1] = ("", sprint(show_signature_function, sig.parameters[1], false, decls[1][1], html,
69+
context = show_env))
6870
else
6971
decls = Tuple{String,String}[("", "") for i = 1:length(sig.parameters::SimpleVector)]
7072
end
@@ -180,30 +182,12 @@ end
180182
function show(io::IO, m::Method)
181183
tv, decls, file, line = arg_decl_parts(m)
182184
sig = unwrap_unionall(m.sig)
183-
ft0 = sig.parameters[1]
184-
ft = unwrap_unionall(ft0)
185-
d1 = decls[1]
186185
if sig === Tuple
187186
# Builtin
188187
print(io, m.name, "(...) in ", m.module)
189188
return
190189
end
191-
if ft <: Function && isa(ft, DataType) &&
192-
isdefined(ft.name.module, ft.name.mt.name) &&
193-
# TODO: more accurate test? (tn.name === "#" name)
194-
ft0 === typeof(getfield(ft.name.module, ft.name.mt.name))
195-
print(io, ft.name.mt.name)
196-
elseif isa(ft, DataType) && ft.name === Type.body.name
197-
f = ft.parameters[1]
198-
if isa(f, DataType) && isempty(f.parameters)
199-
print(io, f)
200-
else
201-
print(io, "(", d1[1], "::", d1[2], ")")
202-
end
203-
else
204-
print(io, "(", d1[1], "::", d1[2], ")")
205-
end
206-
print(io, "(")
190+
print(io, decls[1][2], "(")
207191
join(io, String[isempty(d[2]) ? d[1] : d[1]*"::"*d[2] for d in decls[2:end]],
208192
", ", ", ")
209193
kwargs = kwarg_decl(m)
@@ -338,31 +322,14 @@ function url(m::Method)
338322
end
339323

340324
function show(io::IO, ::MIME"text/html", m::Method)
341-
tv, decls, file, line = arg_decl_parts(m)
325+
tv, decls, file, line = arg_decl_parts(m, true)
342326
sig = unwrap_unionall(m.sig)
343-
ft0 = sig.parameters[1]
344-
ft = unwrap_unionall(ft0)
345-
d1 = decls[1]
346327
if sig === Tuple
347328
# Builtin
348329
print(io, m.name, "(...) in ", m.module)
349330
return
350331
end
351-
if ft <: Function && isa(ft, DataType) &&
352-
isdefined(ft.name.module, ft.name.mt.name) &&
353-
ft0 === typeof(getfield(ft.name.module, ft.name.mt.name))
354-
print(io, ft.name.mt.name)
355-
elseif isa(ft, DataType) && ft.name === Type.body.name
356-
f = ft.parameters[1]
357-
if isa(f, DataType) && isempty(f.parameters)
358-
print(io, f)
359-
else
360-
print(io, "(", d1[1], "::<b>", d1[2], "</b>)")
361-
end
362-
else
363-
print(io, "(", d1[1], "::<b>", d1[2], "</b>)")
364-
end
365-
print(io, "(")
332+
print(io, decls[1][2], "(")
366333
join(io, String[isempty(d[2]) ? d[1] : d[1]*"::<b>"*d[2]*"</b>"
367334
for d in decls[2:end]], ", ", ", ")
368335
kwargs = kwarg_decl(m)

base/show.jl

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1742,6 +1742,31 @@ function demangle_function_name(name::AbstractString)
17421742
return name
17431743
end
17441744

1745+
# show the called object in a signature, given its type `ft`
1746+
# `io` should contain the UnionAll env of the signature
1747+
function show_signature_function(io::IO, @nospecialize(ft), demangle=false, fargname="", html=false)
1748+
uw = unwrap_unionall(ft)
1749+
if ft <: Function && isa(uw, DataType) && isempty(uw.parameters) &&
1750+
isdefined(uw.name.module, uw.name.mt.name) &&
1751+
ft == typeof(getfield(uw.name.module, uw.name.mt.name))
1752+
print(io, (demangle ? demangle_function_name : identity)(uw.name.mt.name))
1753+
elseif isa(ft, DataType) && ft.name === Type.body.name &&
1754+
(f = ft.parameters[1]; !isa(f, TypeVar))
1755+
uwf = unwrap_unionall(f)
1756+
parens = isa(f, UnionAll) && !(isa(uwf, DataType) && f === uwf.name.wrapper)
1757+
parens && print(io, "(")
1758+
show(io, f)
1759+
parens && print(io, ")")
1760+
else
1761+
if html
1762+
print(io, "($fargname::<b>", ft, "</b>)")
1763+
else
1764+
print(io, "($fargname::", ft, ")")
1765+
end
1766+
end
1767+
nothing
1768+
end
1769+
17451770
function show_tuple_as_call(io::IO, name::Symbol, sig::Type, demangle=false, kwargs=nothing)
17461771
# print a method signature tuple for a lambda definition
17471772
color = get(io, :color, false) && get(io, :backtrace, false) ? stackframe_function_color() : :nothing
@@ -1758,18 +1783,7 @@ function show_tuple_as_call(io::IO, name::Symbol, sig::Type, demangle=false, kwa
17581783
end
17591784
sig = sig.parameters
17601785
with_output_color(color, env_io) do io
1761-
ft = sig[1]
1762-
uw = unwrap_unionall(ft)
1763-
if ft <: Function && isa(uw,DataType) && isempty(uw.parameters) &&
1764-
isdefined(uw.name.module, uw.name.mt.name) &&
1765-
ft == typeof(getfield(uw.name.module, uw.name.mt.name))
1766-
print(io, (demangle ? demangle_function_name : identity)(uw.name.mt.name))
1767-
elseif isa(ft, DataType) && ft.name === Type.body.name && !Core.Compiler.has_free_typevars(ft)
1768-
f = ft.parameters[1]
1769-
print(io, f)
1770-
else
1771-
print(io, "(::", ft, ")")
1772-
end
1786+
show_signature_function(io, sig[1], demangle)
17731787
end
17741788
first = true
17751789
print_style = get(io, :color, false) && get(io, :backtrace, false) ? :bold : :nothing

test/errorshow.jl

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ Base.show_method_candidates(buf, Base.MethodError(method_c1,(1, 1, 1)))
7474
# matches the implicit constructor -> convert method
7575
Base.show_method_candidates(buf, Base.MethodError(Tuple{}, (1, 1, 1)))
7676
let mc = String(take!(buf))
77-
@test occursin("\nClosest candidates are:\n Tuple{}", mc)
77+
@test occursin("\nClosest candidates are:\n (::Type{T})", mc)
7878
@test !occursin(cfile, mc)
7979
end
8080

@@ -124,10 +124,13 @@ PR16155line2 = @__LINE__() + 1
124124
(::Type{T})(arg::Any) where {T<:PR16155} = "replace call-to-convert method from sysimg"
125125

126126
Base.show_method_candidates(buf, MethodError(PR16155,(1.0, 2.0, Int64(3))))
127-
@test String(take!(buf)) == "\nClosest candidates are:\n $(curmod_prefix)PR16155(::Any, ::Any)$cfile$PR16155line\n $(curmod_prefix)PR16155(!Matched::Int64, ::Any)$cfile$PR16155line\n $(curmod_prefix)PR16155(::Any) where T<:$(curmod_prefix)PR16155$cfile$PR16155line2"
127+
@test String(take!(buf)) == "\nClosest candidates are:\n $(curmod_prefix)PR16155(::Any, ::Any)$cfile$PR16155line\n $(curmod_prefix)PR16155(!Matched::Int64, ::Any)$cfile$PR16155line\n (::Type{T})(::Any) where T<:$(curmod_prefix)PR16155$cfile$PR16155line2"
128128

129129
Base.show_method_candidates(buf, MethodError(PR16155,(Int64(3), 2.0, Int64(3))))
130-
@test String(take!(buf)) == "\nClosest candidates are:\n $(curmod_prefix)PR16155(::Int64, ::Any)$cfile$PR16155line\n $(curmod_prefix)PR16155(::Any, ::Any)$cfile$PR16155line\n $(curmod_prefix)PR16155(::Any) where T<:$(curmod_prefix)PR16155$cfile$PR16155line2"
130+
@test String(take!(buf)) == "\nClosest candidates are:\n $(curmod_prefix)PR16155(::Int64, ::Any)$cfile$PR16155line\n $(curmod_prefix)PR16155(::Any, ::Any)$cfile$PR16155line\n (::Type{T})(::Any) where T<:$(curmod_prefix)PR16155$cfile$PR16155line2"
131+
132+
Base.show_method_candidates(buf, MethodError(Complex{T} where T<:Integer, (1.2,)))
133+
@test startswith(String(take!(buf)), "\nClosest candidates are:\n (::Type{T})(::T) where T<:Number")
131134

132135
c6line = @__LINE__
133136
method_c6(; x=1) = x
@@ -396,6 +399,9 @@ EightBitTypeT{T}() where {T} = throw(ErrorException("6"))
396399
(::EightBitTypeT)() = throw(ErrorException("7"))
397400
(::FunctionLike)() = throw(ErrorException("8"))
398401

402+
struct StructWithUnionAllMethodDefs{T}
403+
end
404+
(::Type{StructWithUnionAllMethodDefs{T} where T<:Integer})(x) = x
399405

400406
let err_str,
401407
i = reinterpret(EightBitType, 0x54),
@@ -412,15 +418,19 @@ let err_str,
412418
@test sprint(show, which(reinterpret(EightBitType, 0x54), Tuple{})) ==
413419
"(::$(curmod_prefix)EightBitType)() in $curmod_str at $sp:$(method_defs_lineno + 3)"
414420
@test sprint(show, which(EightBitTypeT, Tuple{})) ==
415-
"(::Type{$(curmod_prefix)EightBitTypeT})() in $curmod_str at $sp:$(method_defs_lineno + 4)"
421+
"$(curmod_prefix)EightBitTypeT() in $curmod_str at $sp:$(method_defs_lineno + 4)"
416422
@test sprint(show, which(EightBitTypeT{Int32}, Tuple{})) ==
417-
"(::Type{$(curmod_prefix)EightBitTypeT{T}})() where T in $curmod_str at $sp:$(method_defs_lineno + 5)"
423+
"$(curmod_prefix)EightBitTypeT{T}() where T in $curmod_str at $sp:$(method_defs_lineno + 5)"
418424
@test sprint(show, which(reinterpret(EightBitTypeT{Int32}, 0x54), Tuple{})) ==
419425
"(::$(curmod_prefix)EightBitTypeT)() in $curmod_str at $sp:$(method_defs_lineno + 6)"
426+
@test startswith(sprint(show, which(Complex{Int}, Tuple{Int})),
427+
"Complex{T}(")
420428
@test startswith(sprint(show, which(getfield(Base, Symbol("@doc")), Tuple{LineNumberNode, Module, Vararg{Any}})),
421429
"@doc(__source__::LineNumberNode, __module__::Module, x...) in Core at boot.jl:")
422430
@test startswith(sprint(show, which(FunctionLike(), Tuple{})),
423431
"(::$(curmod_prefix)FunctionLike)() in $curmod_str at $sp:$(method_defs_lineno + 7)")
432+
@test startswith(sprint(show, which(StructWithUnionAllMethodDefs{<:Integer}, (Any,))),
433+
"($(curmod_prefix)StructWithUnionAllMethodDefs{T} where T<:Integer)(x)")
424434
@test repr("text/plain", FunctionLike()) == "(::$(curmod_prefix)FunctionLike) (generic function with 1 method)"
425435
@test repr("text/plain", Core.arraysize) == "arraysize (built-in function)"
426436

0 commit comments

Comments
 (0)