From 42c5f6cf644de393c24525989ca74c3664786c88 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Sat, 6 Aug 2022 12:17:01 +0900 Subject: [PATCH] methodshow: single-line printing for `Method` by default (#46241) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently `show(::IO, ::Method)` prints the method object in multiple-line as like: ```julia julia> only(methods(sin, (Float64,))) sin(x::T) where T<:Union{Float32, Float64} @ Base.Math special/trig.jl:29 ``` and this could be confusing when used within a container e.g.: ```julia julia> Any[only(methods(sin, (Float64,)))] 1-element Vector{Any}: sin(x::T) where T<:Union{Float32, Float64} @ Base.Math special/trig.jl:29 julia> code_lowered() do; Base.Experimental.@opaque a::Int -> sin(a); end 1-element Vector{Core.CodeInfo}: CodeInfo( 1 ─ %1 = Core.apply_type(Core.Tuple, Main.Int) │ %2 = Core.apply_type(Core.Union) │ %3 = $(Expr(:new_opaque_closure, :(%1), :(%2), :(Core.Any), opaque closure(...) @ Main none:0)) └── return %3 ) ``` This commit refactors the `show` method for `Method` object so that `show(::IO, ::Method)` prints it within a single line by default and `show(::IO, ::MIME"text/plain", ::Method)` prints within 2-lines, that I believe is more aligned with printing implementations for the other types: ```julia julia> Any[only(methods(sin, (Float64,)))] 1-element Vector{Any}: sin(x::T) where T<:Union{Float32, Float64} @ Base.Math special/trig.jl:29 julia> code_lowered() do; Base.Experimental.@opaque a::Int -> sin(a); end 1-element Vector{Core.CodeInfo}: CodeInfo( 1 ─ %1 = Core.apply_type(Core.Tuple, Main.Int) │ %2 = Core.apply_type(Core.Union) │ %3 = $(Expr(:new_opaque_closure, :(%1), :(%2), :(Core.Any), opaque closure(...) @ Main none:0)) └── return %3 ) ``` --- base/errorshow.jl | 22 +++++++++++--------- base/methodshow.jl | 19 ++++++++++++----- doc/src/devdocs/inference.md | 3 +-- stdlib/InteractiveUtils/test/highlighting.jl | 1 - stdlib/Test/src/Test.jl | 3 +-- test/errorshow.jl | 18 ++++++++-------- test/reflection.jl | 6 +++--- test/show.jl | 12 +++++++++++ 8 files changed, 52 insertions(+), 32 deletions(-) diff --git a/base/errorshow.jl b/base/errorshow.jl index aaf040cd71b8d..1b00419cd8510 100644 --- a/base/errorshow.jl +++ b/base/errorshow.jl @@ -346,7 +346,7 @@ function showerror_ambiguous(io::IO, meths, f, args) sigfix = Any for m in meths print(io, " ") - show(io, m; digit_align_width=-2) + show_method(io, m; digit_align_width=0) println(io) sigfix = typeintersect(m.sig, sigfix) end @@ -543,8 +543,8 @@ function show_method_candidates(io::IO, ex::MethodError, @nospecialize kwargs=() println(iob) m = parentmodule_before_main(method.module) - color = get!(() -> popfirst!(STACKTRACE_MODULECOLORS), STACKTRACE_FIXEDCOLORS, m) - print_module_path_file(iob, m, string(file), line, color, 1) + modulecolor = get!(() -> popfirst!(STACKTRACE_MODULECOLORS), STACKTRACE_FIXEDCOLORS, m) + print_module_path_file(iob, m, string(file), line; modulecolor, digit_align_width = 3) # TODO: indicate if it's in the wrong world push!(lines, (buf, right_matches)) @@ -685,7 +685,7 @@ end # Print a stack frame where the module color is determined by looking up the parent module in # `modulecolordict`. If the module does not have a color, yet, a new one can be drawn # from `modulecolorcycler`. -function print_stackframe(io, i, frame::StackFrame, n::Int, digit_align_width, modulecolordict, modulecolorcycler) +function print_stackframe(io, i, frame::StackFrame, n::Int, ndigits_max, modulecolordict, modulecolorcycler) m = Base.parentmodule(frame) modulecolor = if m !== nothing m = parentmodule_before_main(m) @@ -693,7 +693,7 @@ function print_stackframe(io, i, frame::StackFrame, n::Int, digit_align_width, m else :default end - print_stackframe(io, i, frame, n, digit_align_width, modulecolor) + print_stackframe(io, i, frame, n, ndigits_max, modulecolor) end # Gets the topmost parent module that isn't Main @@ -707,7 +707,7 @@ function parentmodule_before_main(m) end # Print a stack frame where the module color is set manually with `modulecolor`. -function print_stackframe(io, i, frame::StackFrame, n::Int, digit_align_width, modulecolor) +function print_stackframe(io, i, frame::StackFrame, n::Int, ndigits_max, modulecolor) file, line = string(frame.file), frame.line file = fixup_stdlib_path(file) stacktrace_expand_basepaths() && (file = something(find_source_file(file), file)) @@ -722,8 +722,10 @@ function print_stackframe(io, i, frame::StackFrame, n::Int, digit_align_width, m inlined = getfield(frame, :inlined) modul = parentmodule(frame) + digit_align_width = ndigits_max + 2 + # frame number - print(io, " ", lpad("[" * string(i) * "]", digit_align_width + 2)) + print(io, " ", lpad("[" * string(i) * "]", digit_align_width)) print(io, " ") StackTraces.show_spec_linfo(IOContext(io, :backtrace=>true), frame) @@ -733,14 +735,14 @@ function print_stackframe(io, i, frame::StackFrame, n::Int, digit_align_width, m println(io) # @ Module path / file : line - print_module_path_file(io, modul, file, line, modulecolor, digit_align_width) + print_module_path_file(io, modul, file, line; modulecolor, digit_align_width) # inlined printstyled(io, inlined ? " [inlined]" : "", color = :light_black) end -function print_module_path_file(io, modul, file, line, modulecolor = :light_black, digit_align_width = 0) - printstyled(io, " " ^ (digit_align_width + 2) * "@", color = :light_black) +function print_module_path_file(io, modul, file, line; modulecolor = :light_black, digit_align_width = 0) + printstyled(io, " " ^ digit_align_width * "@", color = :light_black) # module if modul !== nothing && modulecolor !== nothing diff --git a/base/methodshow.jl b/base/methodshow.jl index dc723f5c23e8a..9e815765dc382 100644 --- a/base/methodshow.jl +++ b/base/methodshow.jl @@ -205,7 +205,12 @@ function sym_to_string(sym) end end -function show(io::IO, m::Method; modulecolor = :light_black, digit_align_width = -1) +# default compact view +show(io::IO, m::Method; kwargs...) = show_method(IOContext(io, :compact=>true), m; kwargs...) + +show(io::IO, ::MIME"text/plain", m::Method; kwargs...) = show_method(io, m; kwargs...) + +function show_method(io::IO, m::Method; modulecolor = :light_black, digit_align_width = 1) tv, decls, file, line = arg_decl_parts(m) sig = unwrap_unionall(m.sig) if sig === Tuple @@ -242,8 +247,12 @@ function show(io::IO, m::Method; modulecolor = :light_black, digit_align_width = end # module & file, re-using function from errorshow.jl - println(io) - print_module_path_file(io, m.module, string(file), line, modulecolor, digit_align_width+4) + if get(io, :compact, false) # single-line mode + print_module_path_file(io, m.module, string(file), line; modulecolor, digit_align_width) + else + println(io) + print_module_path_file(io, m.module, string(file), line; modulecolor, digit_align_width=digit_align_width+4) + end end function show_method_list_header(io::IO, ms::MethodList, namefmt::Function) @@ -313,7 +322,7 @@ function show_method_table(io::IO, ms::MethodList, max::Int=-1, header::Bool=tru m = parentmodule_before_main(meth.module) get!(() -> popfirst!(STACKTRACE_MODULECOLORS), STACKTRACE_FIXEDCOLORS, m) end - show(io, meth; modulecolor) + show_method(io, meth; modulecolor) file, line = updated_methodloc(meth) if last_shown_line_infos !== nothing @@ -327,7 +336,7 @@ function show_method_table(io::IO, ms::MethodList, max::Int=-1, header::Bool=tru if rest > 0 println(io) if rest == 1 - show(io, last) + show_method(io, last) else print(io, "... $rest methods not shown") if hasname diff --git a/doc/src/devdocs/inference.md b/doc/src/devdocs/inference.md index cce272f336a86..253dcf3e63c01 100644 --- a/doc/src/devdocs/inference.md +++ b/doc/src/devdocs/inference.md @@ -96,8 +96,7 @@ Each statement gets analyzed for its total cost in a function called as follows: ```jldoctest; filter=r"tuple.jl:\d+" julia> Base.print_statement_costs(stdout, map, (typeof(sqrt), Tuple{Int},)) # map(sqrt, (2,)) -map(f, t::Tuple{Any}) - @ Base tuple.jl:273 +map(f, t::Tuple{Any}) @ Base tuple.jl:273 0 1 ─ %1 = Base.getfield(_3, 1, true)::Int64 1 │ %2 = Base.sitofp(Float64, %1)::Float64 2 │ %3 = Base.lt_float(%2, 0.0)::Bool diff --git a/stdlib/InteractiveUtils/test/highlighting.jl b/stdlib/InteractiveUtils/test/highlighting.jl index 0026c0b855730..bac52e2945b5e 100644 --- a/stdlib/InteractiveUtils/test/highlighting.jl +++ b/stdlib/InteractiveUtils/test/highlighting.jl @@ -10,7 +10,6 @@ myzeros(::Type{T}, ::Type{S}, ::Type{R}, dims::Tuple{Vararg{Integer, N}}, dims2: seekstart(io) @test startswith(readline(io), "MethodInstance for ") @test occursin(r"^ from myzeros\(::.*Type.*{T}, ::", readline(io)) - readline(io) # skip location information from method printing - already tested in base @test occursin(r"^Static Parameters$", readline(io)) @test occursin(r"^ T <: .*Integer", readline(io)) @test occursin(r"^ .*Signed.* <: R <: .*Real", readline(io)) diff --git a/stdlib/Test/src/Test.jl b/stdlib/Test/src/Test.jl index fb8d3e4364a27..69714de01de50 100644 --- a/stdlib/Test/src/Test.jl +++ b/stdlib/Test/src/Test.jl @@ -1718,8 +1718,7 @@ Int64 julia> @code_warntype f(2) MethodInstance for f(::Int64) - from f(a) - @ Main none:1 + from f(a) @ Main none:1 Arguments #self#::Core.Const(f) a::Int64 diff --git a/test/errorshow.jl b/test/errorshow.jl index 442b5478cda24..6cd8dbba14637 100644 --- a/test/errorshow.jl +++ b/test/errorshow.jl @@ -431,25 +431,25 @@ let err_str, Base.stacktrace_contract_userdir() && (sp = Base.contractuser(sp)) @test sprint(show, which(String, Tuple{})) == - "String()\n @ $curmod_str $sp:$(method_defs_lineno + 0)" + "String() @ $curmod_str $sp:$(method_defs_lineno + 0)" @test sprint(show, which("a", Tuple{})) == - "(::String)()\n @ $curmod_str $sp:$(method_defs_lineno + 1)" + "(::String)() @ $curmod_str $sp:$(method_defs_lineno + 1)" @test sprint(show, which(EightBitType, Tuple{})) == - "$(curmod_prefix)EightBitType()\n @ $curmod_str $sp:$(method_defs_lineno + 2)" + "$(curmod_prefix)EightBitType() @ $curmod_str $sp:$(method_defs_lineno + 2)" @test sprint(show, which(reinterpret(EightBitType, 0x54), Tuple{})) == - "(::$(curmod_prefix)EightBitType)()\n @ $curmod_str $sp:$(method_defs_lineno + 3)" + "(::$(curmod_prefix)EightBitType)() @ $curmod_str $sp:$(method_defs_lineno + 3)" @test sprint(show, which(EightBitTypeT, Tuple{})) == - "$(curmod_prefix)EightBitTypeT()\n @ $curmod_str $sp:$(method_defs_lineno + 4)" + "$(curmod_prefix)EightBitTypeT() @ $curmod_str $sp:$(method_defs_lineno + 4)" @test sprint(show, which(EightBitTypeT{Int32}, Tuple{})) == - "$(curmod_prefix)EightBitTypeT{T}() where T\n @ $curmod_str $sp:$(method_defs_lineno + 5)" + "$(curmod_prefix)EightBitTypeT{T}() where T @ $curmod_str $sp:$(method_defs_lineno + 5)" @test sprint(show, which(reinterpret(EightBitTypeT{Int32}, 0x54), Tuple{})) == - "(::$(curmod_prefix)EightBitTypeT)()\n @ $curmod_str $sp:$(method_defs_lineno + 6)" + "(::$(curmod_prefix)EightBitTypeT)() @ $curmod_str $sp:$(method_defs_lineno + 6)" @test startswith(sprint(show, which(Complex{Int}, Tuple{Int})), "Complex{T}(") @test startswith(sprint(show, which(getfield(Base, Symbol("@doc")), Tuple{LineNumberNode, Module, Vararg{Any}})), - "var\"@doc\"(__source__::LineNumberNode, __module__::Module, x...)\n @ Core boot.jl:") + "var\"@doc\"(__source__::LineNumberNode, __module__::Module, x...) @ Core boot.jl:") @test startswith(sprint(show, which(FunctionLike(), Tuple{})), - "(::$(curmod_prefix)FunctionLike)()\n @ $curmod_str $sp:$(method_defs_lineno + 7)") + "(::$(curmod_prefix)FunctionLike)() @ $curmod_str $sp:$(method_defs_lineno + 7)") @test startswith(sprint(show, which(StructWithUnionAllMethodDefs{<:Integer}, (Any,))), "($(curmod_prefix)StructWithUnionAllMethodDefs{T} where T<:Integer)(x)") @test repr("text/plain", FunctionLike()) == "(::$(curmod_prefix)FunctionLike) (generic function with 1 method)" diff --git a/test/reflection.jl b/test/reflection.jl index 3f3f394ed71b5..5cb20256538e0 100644 --- a/test/reflection.jl +++ b/test/reflection.jl @@ -224,7 +224,7 @@ let ex = :(a + b) end foo13825(::Array{T, N}, ::Array, ::Vector) where {T, N} = nothing @test startswith(string(first(methods(foo13825))), - "foo13825(::Array{T, N}, ::Array, ::Vector) where {T, N}\n") + "foo13825(::Array{T, N}, ::Array, ::Vector) where {T, N}") mutable struct TLayout x::Int8 @@ -425,10 +425,10 @@ let li = typeof(fieldtype).name.mt.cache.func::Core.MethodInstance, mmime = repr("text/plain", li.def) @test lrepr == lmime == "MethodInstance for fieldtype(...)" - @test mrepr == mmime == "fieldtype(...)\n @ Core none:0" + @test mrepr == "fieldtype(...) @ Core none:0" # simple print + @test mmime == "fieldtype(...)\n @ Core none:0" # verbose print end - # Linfo Tracing test function tracefoo end # Method Tracing test diff --git a/test/show.jl b/test/show.jl index a0352540e2d9d..4c7ef8290634a 100644 --- a/test/show.jl +++ b/test/show.jl @@ -2380,3 +2380,15 @@ Base.show(io::IO, ces::⛵) = Base.print(io, '⛵') @test Base.alignment(stdout, ⛵()) == (0, 2) @test Base.alignment(IOContext(IOBuffer(), :color=>true), ColoredLetter()) == (0, 1) @test Base.alignment(IOContext(IOBuffer(), :color=>false), ColoredLetter()) == (0, 1) + +# `show` implementations for `Method` +let buf = IOBuffer() + + # single line printing by default + show(buf, only(methods(sin, (Float64,)))) + @test !occursin('\n', String(take!(buf))) + + # two-line printing for rich display + show(buf, MIME("text/plain"), only(methods(sin, (Float64,)))) + @test occursin('\n', String(take!(buf))) +end