Skip to content

Commit

Permalink
methodshow: single-line printing for Method by default (JuliaLang#4…
Browse files Browse the repository at this point in the history
…6241)

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
)
```
  • Loading branch information
aviatesk committed Aug 6, 2022
1 parent fa986d9 commit 42c5f6c
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 32 deletions.
22 changes: 12 additions & 10 deletions base/errorshow.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -685,15 +685,15 @@ 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)
get!(() -> popfirst!(modulecolorcycler), modulecolordict, 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
Expand All @@ -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))
Expand All @@ -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)
Expand All @@ -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
Expand Down
19 changes: 14 additions & 5 deletions base/methodshow.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
3 changes: 1 addition & 2 deletions doc/src/devdocs/inference.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion stdlib/InteractiveUtils/test/highlighting.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
3 changes: 1 addition & 2 deletions stdlib/Test/src/Test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
18 changes: 9 additions & 9 deletions test/errorshow.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)"
Expand Down
6 changes: 3 additions & 3 deletions test/reflection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
12 changes: 12 additions & 0 deletions test/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 42c5f6c

Please sign in to comment.