Skip to content

Commit

Permalink
simplify and improve printing of qualified names
Browse files Browse the repository at this point in the history
This removes repeated code, fixes some cases where quoting was not done
correcly (e.g. `Mod.:+`), and checks identifier visibility recursively
so only a minimal module path is printed.

fixes #39834
  • Loading branch information
JeffBezanson committed Mar 4, 2021
1 parent de7d695 commit 090c4c9
Show file tree
Hide file tree
Showing 16 changed files with 117 additions and 118 deletions.
11 changes: 1 addition & 10 deletions base/Enums.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,7 @@ Base.Symbol(x::Enum) = namemap(typeof(x))[Integer(x)]::Symbol
Base.print(io::IO, x::Enum) = print(io, Symbol(x))

function Base.show(io::IO, x::Enum)
sym = Symbol(x)
if !(get(io, :compact, false)::Bool)
from = get(io, :module, Main)
def = typeof(x).name.module
if from === nothing || !Base.isvisible(sym, def, from)
show(io, def)
print(io, ".")
end
end
print(io, sym)
Base.print_qualified_name(io, parentmodule(typeof(x)), Symbol(x))
end

function Base.show(io::IO, ::MIME"text/plain", x::Enum)
Expand Down
26 changes: 13 additions & 13 deletions base/atomics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ Atomic objects can be accessed using the `[]` notation:
# Examples
```jldoctest
julia> x = Threads.Atomic{Int}(3)
Base.Threads.Atomic{Int64}(3)
Threads.Atomic{Int64}(3)
julia> x[] = 1
1
Expand Down Expand Up @@ -100,17 +100,17 @@ time.
# Examples
```jldoctest
julia> x = Threads.Atomic{Int}(3)
Base.Threads.Atomic{Int64}(3)
Threads.Atomic{Int64}(3)
julia> Threads.atomic_cas!(x, 4, 2);
julia> x
Base.Threads.Atomic{Int64}(3)
Threads.Atomic{Int64}(3)
julia> Threads.atomic_cas!(x, 3, 2);
julia> x
Base.Threads.Atomic{Int64}(2)
Threads.Atomic{Int64}(2)
```
"""
function atomic_cas! end
Expand All @@ -128,7 +128,7 @@ For further details, see LLVM's `atomicrmw xchg` instruction.
# Examples
```jldoctest
julia> x = Threads.Atomic{Int}(3)
Base.Threads.Atomic{Int64}(3)
Threads.Atomic{Int64}(3)
julia> Threads.atomic_xchg!(x, 2)
3
Expand All @@ -152,7 +152,7 @@ For further details, see LLVM's `atomicrmw add` instruction.
# Examples
```jldoctest
julia> x = Threads.Atomic{Int}(3)
Base.Threads.Atomic{Int64}(3)
Threads.Atomic{Int64}(3)
julia> Threads.atomic_add!(x, 2)
3
Expand All @@ -176,7 +176,7 @@ For further details, see LLVM's `atomicrmw sub` instruction.
# Examples
```jldoctest
julia> x = Threads.Atomic{Int}(3)
Base.Threads.Atomic{Int64}(3)
Threads.Atomic{Int64}(3)
julia> Threads.atomic_sub!(x, 2)
3
Expand All @@ -199,7 +199,7 @@ For further details, see LLVM's `atomicrmw and` instruction.
# Examples
```jldoctest
julia> x = Threads.Atomic{Int}(3)
Base.Threads.Atomic{Int64}(3)
Threads.Atomic{Int64}(3)
julia> Threads.atomic_and!(x, 2)
3
Expand All @@ -222,7 +222,7 @@ For further details, see LLVM's `atomicrmw nand` instruction.
# Examples
```jldoctest
julia> x = Threads.Atomic{Int}(3)
Base.Threads.Atomic{Int64}(3)
Threads.Atomic{Int64}(3)
julia> Threads.atomic_nand!(x, 2)
3
Expand All @@ -245,7 +245,7 @@ For further details, see LLVM's `atomicrmw or` instruction.
# Examples
```jldoctest
julia> x = Threads.Atomic{Int}(5)
Base.Threads.Atomic{Int64}(5)
Threads.Atomic{Int64}(5)
julia> Threads.atomic_or!(x, 7)
5
Expand All @@ -268,7 +268,7 @@ For further details, see LLVM's `atomicrmw xor` instruction.
# Examples
```jldoctest
julia> x = Threads.Atomic{Int}(5)
Base.Threads.Atomic{Int64}(5)
Threads.Atomic{Int64}(5)
julia> Threads.atomic_xor!(x, 7)
5
Expand All @@ -291,7 +291,7 @@ For further details, see LLVM's `atomicrmw max` instruction.
# Examples
```jldoctest
julia> x = Threads.Atomic{Int}(5)
Base.Threads.Atomic{Int64}(5)
Threads.Atomic{Int64}(5)
julia> Threads.atomic_max!(x, 7)
5
Expand All @@ -314,7 +314,7 @@ For further details, see LLVM's `atomicrmw min` instruction.
# Examples
```jldoctest
julia> x = Threads.Atomic{Int}(7)
Base.Threads.Atomic{Int64}(7)
Threads.Atomic{Int64}(7)
julia> Threads.atomic_min!(x, 5)
7
Expand Down
6 changes: 3 additions & 3 deletions base/broadcast.jl
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,7 @@ Uses [`BroadcastStyle`](@ref) to get the style for each argument, and uses
```jldoctest
julia> Broadcast.combine_styles([1], [1 2; 3 4])
Base.Broadcast.DefaultArrayStyle{2}()
Broadcast.DefaultArrayStyle{2}()
```
"""
function combine_styles end
Expand All @@ -431,10 +431,10 @@ determine a common `BroadcastStyle`.
```jldoctest
julia> Broadcast.result_style(Broadcast.DefaultArrayStyle{0}(), Broadcast.DefaultArrayStyle{3}())
Base.Broadcast.DefaultArrayStyle{3}()
Broadcast.DefaultArrayStyle{3}()
julia> Broadcast.result_style(Broadcast.Unknown(), Broadcast.DefaultArrayStyle{1}())
Base.Broadcast.DefaultArrayStyle{1}()
Broadcast.DefaultArrayStyle{1}()
```
"""
function result_style end
Expand Down
7 changes: 2 additions & 5 deletions base/docs/bindings.jl
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,8 @@ macro var(x)
end

function Base.show(io::IO, b::Binding)
if b.mod === Main
print(io, b.var)
else
print(io, b.mod, '.', Base.isoperator(b.var) ? ":" : "", b.var)
end
from = Base.moduleroot(b.mod) === Main ? Main : nothing
Base.print_qualified_name(io, b.mod, b.var, from, allow_macroname=true)
end

aliasof(b::Binding) = defined(b) ? (a = aliasof(resolve(b), b); defined(a) ? a : b) : b
Expand Down
2 changes: 1 addition & 1 deletion base/iterators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ See [`Base.filter`](@ref) for an eager implementation of filtering for arrays.
# Examples
```jldoctest
julia> f = Iterators.filter(isodd, [1, 2, 3, 4, 5])
Base.Iterators.Filter{typeof(isodd), Vector{Int64}}(isodd, [1, 2, 3, 4, 5])
Iterators.Filter{typeof(isodd), Vector{Int64}}(isodd, [1, 2, 3, 4, 5])
julia> foreach(println, f)
1
Expand Down
2 changes: 1 addition & 1 deletion base/meta.jl
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ julia> Meta.parse("x = ")
:($(Expr(:incomplete, "incomplete: premature end of input")))
julia> Meta.parse("1.0.2")
ERROR: Base.Meta.ParseError("invalid numeric constant \\\"1.0.\\\"")
ERROR: Meta.ParseError("invalid numeric constant \\\"1.0.\\\"")
Stacktrace:
[...]
Expand Down
12 changes: 8 additions & 4 deletions base/methodshow.jl
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,8 @@ function show(io::IO, m::Method)
sig = unwrap_unionall(m.sig)
if sig === Tuple
# Builtin
print(io, m.name, "(...) in ", m.module)
print(io, m.name, "(...) in ")
show(io, m.module)
return
end
print(io, decls[1][2], "(")
Expand All @@ -219,7 +220,8 @@ function show(io::IO, m::Method)
end
print(io, ")")
show_method_params(io, tv)
print(io, " in ", m.module)
print(io, " in ")
show(io, m.module)
if line > 0
file, line = updated_methodloc(m)
print(io, " at ", file, ":", line)
Expand Down Expand Up @@ -352,7 +354,8 @@ function show(io::IO, ::MIME"text/html", m::Method)
sig = unwrap_unionall(m.sig)
if sig === Tuple
# Builtin
print(io, m.name, "(...) in ", m.module)
print(io, m.name, "(...) in ")
show(io, m.module)
return
end
print(io, decls[1][2], "(")
Expand All @@ -376,7 +379,8 @@ function show(io::IO, ::MIME"text/html", m::Method)
show_method_params(io, tv)
print(io,"</i>")
end
print(io, " in ", m.module)
print(io, " in ")
show(io, m.module)
if line > 0
file, line = updated_methodloc(m)
u = url(m)
Expand Down
108 changes: 51 additions & 57 deletions base/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -429,20 +429,6 @@ function _show_default(io::IO, @nospecialize(x))
print(io,')')
end

# Check if a particular symbol is exported from a standard library module
function is_exported_from_stdlib(name::Symbol, mod::Module)
!isdefined(mod, name) && return false
orig = getfield(mod, name)
while !(mod === Base || mod === Core)
parent = parentmodule(mod)
if mod === Main || mod === parent || parent === Main
return false
end
mod = parent
end
return isexported(mod, name) && isdefined(mod, name) && !isdeprecated(mod, name) && getfield(mod, name) === orig
end

function show_function(io::IO, f::Function, compact::Bool)
ft = typeof(f)
mt = ft.name.mt
Expand All @@ -453,12 +439,7 @@ function show_function(io::IO, f::Function, compact::Bool)
print(io, mt.name)
elseif isdefined(mt, :module) && isdefined(mt.module, mt.name) &&
getfield(mt.module, mt.name) === f
if is_exported_from_stdlib(mt.name, mt.module) || mt.module === Main
show_sym(io, mt.name)
else
print(io, mt.module, ".")
show_sym(io, mt.name)
end
print_qualified_name(io, mt.module, mt.name)
else
show_default(io, f)
end
Expand Down Expand Up @@ -584,17 +565,8 @@ function make_typealias(@nospecialize(x::Type))
end

function show_typealias(io::IO, name::GlobalRef, x::Type, env::SimpleVector, wheres::Vector)
if !(get(io, :compact, false)::Bool)
# Print module prefix unless alias is visible from module passed to
# IOContext. If :module is not set, default to Main. nothing can be used
# to force printing prefix.
from = get(io, :module, Main)
if (from === nothing || !isvisible(name.name, name.mod, from))
show(io, name.mod)
print(io, ".")
end
end
print(io, name.name)
print_qualified_name(io, name.mod, name.name)

n = length(env)
n == 0 && return

Expand Down Expand Up @@ -866,11 +838,46 @@ end
# If an object with this name exists in 'from', we need to check that it's the same binding
# and that it's not deprecated.
function isvisible(sym::Symbol, parent::Module, from::Module)
if parent === from
return true
end
owner = ccall(:jl_binding_owner, Any, (Any, Any), parent, sym)
from_owner = ccall(:jl_binding_owner, Any, (Any, Any), from, sym)
return owner !== nothing && from_owner === owner &&
!isdeprecated(parent, sym) &&
isdefined(from, sym) # if we're going to return true, force binding resolution
return (owner !== nothing && from_owner === owner && !isdeprecated(parent, sym)) ||
# name of a module is visible within itself
(from_owner isa Module && nameof(from_owner) === sym)
end

function should_print_qualified(io::IO, m::Module, name::Symbol, from::Union{Module,Nothing} = get(io,:module,Main))
return !isvisible(name, m, from)
end

# Print `name` from module `m` in qualified form based on IO settings and identifier
# visibility.
# If :module is not set, default to Main. `nothing` can be used to force printing prefix.
# The optional `from` argument exists so that the Main default can be set in
# a central place and possibly phased out eventually.
function print_qualified_name(io::IO, m::Module, name::Symbol, from::Union{Module,Nothing} = get(io,:module,Main);
allow_macroname = false)
quo = false
if !(get(io, :compact, false)::Bool)
if from === nothing || !isvisible(name, m, from)
show(IOContext(io, :module=>from), m)
print(io, ".")
if is_valid_identifier(name) && !is_id_start_char(first(string(name)))
print(io, ':')
if name in quoted_syms
print(io, '(')
quo = true
end
end
end
show_sym(io, name; allow_macroname)
quo && print(io, ')')
else
print(io, name)
end
nothing
end

function is_global_function(tn::Core.TypeName, globname::Union{Symbol,Nothing})
Expand All @@ -895,26 +902,11 @@ function show_type_name(io::IO, tn::Core.TypeName)
globfunc = is_global_function(tn, globname)
sym = (globfunc ? globname : tn.name)::Symbol
globfunc && print(io, "typeof(")
quo = false
if !(get(io, :compact, false)::Bool)
# Print module prefix unless type is visible from module passed to
# IOContext If :module is not set, default to Main. nothing can be used
# to force printing prefix
from = get(io, :module, Main)
if isdefined(tn, :module) && (from === nothing || !isvisible(sym, tn.module, from))
show(io, tn.module)
print(io, ".")
if globfunc && !is_id_start_char(first(string(sym)))
print(io, ':')
if sym in quoted_syms
print(io, '(')
quo = true
end
end
end
if isdefined(tn, :module)
print_qualified_name(io, tn.module, sym)
else
show_sym(io, sym)
end
show_sym(io, sym)
quo && print(io, ")")
globfunc && print(io, ")")
nothing
end
Expand Down Expand Up @@ -1023,10 +1015,12 @@ function show(io::IO, m::Module)
if is_root_module(m)
print(io, nameof(m))
else
print(io, join(fullname(m),"."))
print_qualified_name(io, parentmodule(m), nameof(m))
end
end

print(io::IO, m::Module) = join(io, fullname(m), ".")

function sourceinfo_slotnames(src::CodeInfo)
slotnames = src.slotnames
names = Dict{String,Int}()
Expand Down Expand Up @@ -1531,7 +1525,7 @@ show_unquoted(io::IO, ex::GotoNode, ::Int, ::Int) = print(io, "goto %", ex
show_unquoted(io::IO, ex::GlobalRef, ::Int, ::Int) = show_globalref(io, ex)

function show_globalref(io::IO, ex::GlobalRef; allow_macroname=false)
print(io, ex.mod)
show(io, ex.mod)
print(io, '.')
quoted = !isidentifier(ex.name) && !startswith(string(ex.name), "@")
parens = quoted && (!isoperator(ex.name) || (ex.name in quoted_syms))
Expand Down Expand Up @@ -2216,8 +2210,8 @@ function show_signature_function(io::IO, @nospecialize(ft), demangle=false, farg
if ft <: Function && isa(uw, DataType) && isempty(uw.parameters) &&
isdefined(uw.name.module, uw.name.mt.name) &&
ft == typeof(getfield(uw.name.module, uw.name.mt.name))
if qualified && !is_exported_from_stdlib(uw.name.mt.name, uw.name.module) && uw.name.module !== Main
print_within_stacktrace(io, uw.name.module, '.', bold=true)
if qualified && should_print_qualified(io, uw.name.module, uw.name.mt.name)
print_within_stacktrace(io, sprint(show, uw.name.module, context=io), '.', bold=true)
end
s = sprint(show_sym, (demangle ? demangle_function_name : identity)(uw.name.mt.name), context=io)
print_within_stacktrace(io, s, bold=true)
Expand Down
Loading

0 comments on commit 090c4c9

Please sign in to comment.