Skip to content

Commit 9a98dcb

Browse files
committed
parseable printing of all type names and TypeVars
also adjust generic function printing so that when `(::x)` is printed, `x` is more likely to be the type of the function.
1 parent b330b0e commit 9a98dcb

File tree

5 files changed

+121
-16
lines changed

5 files changed

+121
-16
lines changed

base/methodshow.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,8 @@ function show_method_table(io::IO, ms::MethodList, max::Int=-1, header::Bool=tru
144144
n = length(ms)
145145
if header
146146
m = n==1 ? "method" : "methods"
147-
ns = isself ? string(name) : string("(::", name, ")")
147+
sname = string(name)
148+
ns = (isself || '#' in sname) ? sname : string("(::", name, ")")
148149
what = startswith(ns, '@') ? "macro" : "generic function"
149150
print(io, "# $n $m for ", what, " \"", ns, "\":")
150151
end

base/replutil.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,8 @@ function show(io::IO, ::MIME"text/plain", f::Function)
109109
ft == typeof(getfield(ft.name.module, name))
110110
n = length(methods(f))
111111
m = n==1 ? "method" : "methods"
112-
ns = isself ? string(name) : string("(::", name, ")")
112+
sname = string(name)
113+
ns = (isself || '#' in sname) ? sname : string("(::", ft, ")")
113114
what = startswith(ns, '@') ? "macro" : "generic function"
114115
print(io, ns, " (", what, " with $n $m)")
115116
end

base/show.jl

Lines changed: 83 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -181,10 +181,15 @@ end
181181
function show(io::IO, f::Function)
182182
ft = typeof(f)
183183
mt = ft.name.mt
184-
if !isdefined(mt, :module) || is_exported_from_stdlib(mt.name, mt.module) || mt.module === Main
185-
print(io, mt.name)
184+
if isdefined(mt, :module) && isdefined(mt.module, mt.name) &&
185+
getfield(mt.module, mt.name) === f
186+
if is_exported_from_stdlib(mt.name, mt.module) || mt.module === Main
187+
print(io, mt.name)
188+
else
189+
print(io, mt.module, ".", mt.name)
190+
end
186191
else
187-
print(io, mt.module, ".", mt.name)
192+
show_default(io, f)
188193
end
189194
end
190195

@@ -208,17 +213,89 @@ function print_without_params(@nospecialize(x))
208213
return false
209214
end
210215

216+
has_typevar(@nospecialize(t), v::TypeVar) = ccall(:jl_has_typevar, Cint, (Any, Any), t, v)!=0
217+
218+
function io_has_tvar_name(io::IOContext, name::Symbol, @nospecialize(x))
219+
for (key, val) in io.dict
220+
if key === :unionall_env && val isa TypeVar && val.name === name && has_typevar(x, val)
221+
return true
222+
end
223+
end
224+
return false
225+
end
226+
io_has_tvar_name(io::IO, name::Symbol, @nospecialize(x)) = false
227+
211228
function show(io::IO, x::UnionAll)
212229
if print_without_params(x)
213230
return show(io, unwrap_unionall(x).name)
214231
end
232+
233+
if x.var.name == :_ || io_has_tvar_name(io, x.var.name, x)
234+
counter = 1
235+
while true
236+
newname = Symbol(x.var.name, counter)
237+
if !io_has_tvar_name(io, newname, x)
238+
newtv = TypeVar(newname, x.var.lb, x.var.ub)
239+
x = UnionAll(newtv, x{newtv})
240+
break
241+
end
242+
counter += 1
243+
end
244+
end
245+
215246
show(IOContext(io, :unionall_env => x.var), x.body)
216247
print(io, " where ")
217248
show(io, x.var)
218249
end
219250

220251
show(io::IO, x::DataType) = show_datatype(io, x)
221252

253+
function show_type_name(io::IO, tn::TypeName)
254+
globname = isdefined(tn, :mt) ? tn.mt.name : nothing
255+
globfunc = false
256+
if globname !== nothing
257+
globname_str = string(globname)
258+
if ('#' globname_str && '@' globname_str && isdefined(tn, :module) &&
259+
isbindingresolved(tn.module, globname) && isdefined(tn.module, globname) &&
260+
isa(getfield(tn.module, globname), tn.wrapper) && isleaftype(tn.wrapper))
261+
globfunc = true
262+
end
263+
end
264+
sym = globfunc ? globname : tn.name
265+
sym_str = string(sym)
266+
hidden = !globfunc && '#' sym_str
267+
quo = false
268+
if hidden
269+
print(io, "getfield(")
270+
elseif globfunc
271+
print(io, "typeof(")
272+
end
273+
if isdefined(tn, :module) && !(is_exported_from_stdlib(sym, tn.module) || (tn.module === Main && !hidden))
274+
show(io, tn.module)
275+
if !hidden
276+
print(io, ".")
277+
if globfunc && !is_id_start_char(first(sym_str))
278+
print(io, ":")
279+
if sym == :(==)
280+
print(io, "(")
281+
quo = true
282+
end
283+
end
284+
end
285+
end
286+
if hidden
287+
print(io, ", Symbol(\"", sym_str, "\"))")
288+
else
289+
print(io, sym_str)
290+
if globfunc
291+
print(io, ")")
292+
if quo
293+
print(io, ")")
294+
end
295+
end
296+
end
297+
end
298+
222299
function show_datatype(io::IO, x::DataType)
223300
istuple = x.name === Tuple.name
224301
if (!isempty(x.parameters) || istuple) && x !== Tuple
@@ -228,7 +305,7 @@ function show_datatype(io::IO, x::DataType)
228305
if istuple && n > 3 && all(i -> (x.parameters[1] === i), x.parameters)
229306
print(io, "NTuple{", n, ',', x.parameters[1], "}")
230307
else
231-
show(io, x.name)
308+
show_type_name(io, x.name)
232309
# Do not print the type parameters for the primary type if we are
233310
# printing a method signature or type parameter.
234311
# Always print the type parameter if we are printing the type directly
@@ -241,7 +318,7 @@ function show_datatype(io::IO, x::DataType)
241318
print(io, '}')
242319
end
243320
else
244-
show(io, x.name)
321+
show_type_name(io, x.name)
245322
end
246323
end
247324

@@ -272,11 +349,7 @@ macro show(exs...)
272349
end
273350

274351
function show(io::IO, tn::TypeName)
275-
if is_exported_from_stdlib(tn.name, tn.module) || tn.module === Main
276-
print(io, tn.name)
277-
else
278-
print(io, tn.module, '.', tn.name)
279-
end
352+
show_type_name(io, tn)
280353
end
281354

282355
show(io::IO, ::Void) = print(io, "nothing")

test/replutil.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ let err_str,
347347
err_str = @except_str randn(1)() MethodError
348348
@test contains(err_str, "MethodError: objects of type Array{Float64,1} are not callable")
349349
end
350-
@test stringmime("text/plain", FunctionLike()) == "(::FunctionLike) (generic function with 0 methods)"
350+
@test stringmime("text/plain", FunctionLike()) == "(::$(curmod_prefix)FunctionLike) (generic function with 0 methods)"
351351
@test ismatch(r"^@doc \(macro with \d+ method[s]?\)$", stringmime("text/plain", getfield(Base, Symbol("@doc"))))
352352

353353
method_defs_lineno = @__LINE__() + 1
@@ -385,7 +385,7 @@ let err_str,
385385
"@doc(__source__::LineNumberNode, __module__::Module, x...) in Core at boot.jl:")
386386
@test startswith(sprint(show, which(FunctionLike(), Tuple{})),
387387
"(::$(curmod_prefix)FunctionLike)() in $curmod_str at $sp:$(method_defs_lineno + 7)")
388-
@test stringmime("text/plain", FunctionLike()) == "(::FunctionLike) (generic function with 1 method)"
388+
@test stringmime("text/plain", FunctionLike()) == "(::$(curmod_prefix)FunctionLike) (generic function with 1 method)"
389389
@test stringmime("text/plain", Core.arraysize) == "arraysize (built-in function)"
390390

391391
err_str = @except_stackframe Symbol() ErrorException

test/show.jl

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,7 @@ function f13127()
507507
show(buf, f)
508508
String(take!(buf))
509509
end
510-
@test f13127() == "$(curmod_prefix)f"
510+
@test startswith(f13127(), "getfield($(@__MODULE__), Symbol(\"")
511511

512512
#test methodshow.jl functions
513513
@test Base.inbase(Base)
@@ -736,7 +736,7 @@ let sv = Core.svec(:a, :b, :c)
736736
@test repr == "SimpleVector\n 1: Symbol a\n 2: Symbol b\n 3: #undef\n"
737737
end
738738
let repr = sprint(dump, sin)
739-
@test repr == "sin (function of type Base.#sin)\n"
739+
@test repr == "sin (function of type typeof(sin))\n"
740740
end
741741
let repr = sprint(dump, Base.Test)
742742
@test repr == "Module Base.Test\n"
@@ -947,3 +947,33 @@ end
947947
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 … 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
948948
" ⋮ ⋮ ⋱ ⋮ ")
949949
end
950+
951+
module UnexportedOperators
952+
function + end
953+
function == end
954+
end
955+
956+
@testset "Parseable printing of types" begin
957+
@test repr(typeof(print)) == "typeof(print)"
958+
@test repr(typeof(Base.show_default)) == "typeof(Base.show_default)"
959+
@test repr(typeof(UnexportedOperators.:+)) == "typeof($(curmod_prefix)UnexportedOperators.:+)"
960+
@test repr(typeof(UnexportedOperators.:(==))) == "typeof($(curmod_prefix)UnexportedOperators.:(==))"
961+
anonfn = x->2x
962+
modname = string(@__MODULE__)
963+
anonfn_type_repr = "getfield($modname, Symbol(\"$(typeof(anonfn).name.name)\"))"
964+
@test repr(typeof(anonfn)) == anonfn_type_repr
965+
@test repr(anonfn) == anonfn_type_repr * "()"
966+
@test stringmime("text/plain", anonfn) == "$(typeof(anonfn).name.mt.name) (generic function with 1 method)"
967+
mkclosure = x->y->x+y
968+
clo = mkclosure(10)
969+
@test stringmime("text/plain", clo) == "$(typeof(clo).name.mt.name) (generic function with 1 method)"
970+
end
971+
972+
let x = TypeVar(:_), y = TypeVar(:_)
973+
@test repr(UnionAll(x, UnionAll(y, Pair{x,y}))) == "Pair{_1,_2} where _2 where _1"
974+
@test repr(UnionAll(x, UnionAll(y, Pair{UnionAll(x,Ref{x}),y}))) == "Pair{Ref{_1} where _1,_1} where _1"
975+
x = TypeVar(:a)
976+
y = TypeVar(:a)
977+
z = TypeVar(:a)
978+
@test repr(UnionAll(z, UnionAll(x, UnionAll(y, Tuple{x,y,z})))) == "Tuple{a1,a2,a} where a2 where a1 where a"
979+
end

0 commit comments

Comments
 (0)