Skip to content

Commit ae005e1

Browse files
committed
simplify and improve printing of qualified names
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
1 parent 76698ea commit ae005e1

File tree

10 files changed

+86
-86
lines changed

10 files changed

+86
-86
lines changed

base/Enums.jl

+1-10
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,7 @@ Base.Symbol(x::Enum) = namemap(typeof(x))[Integer(x)]::Symbol
2828
Base.print(io::IO, x::Enum) = print(io, Symbol(x))
2929

3030
function Base.show(io::IO, x::Enum)
31-
sym = Symbol(x)
32-
if !(get(io, :compact, false)::Bool)
33-
from = get(io, :module, Main)
34-
def = typeof(x).name.module
35-
if from === nothing || !Base.isvisible(sym, def, from)
36-
show(io, def)
37-
print(io, ".")
38-
end
39-
end
40-
print(io, sym)
31+
Base.print_qualified_name(io, parentmodule(typeof(x)), Symbol(x))
4132
end
4233

4334
function Base.show(io::IO, ::MIME"text/plain", x::Enum)

base/atomics.jl

+13-13
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ Atomic objects can be accessed using the `[]` notation:
6060
# Examples
6161
```jldoctest
6262
julia> x = Threads.Atomic{Int}(3)
63-
Base.Threads.Atomic{Int64}(3)
63+
Threads.Atomic{Int64}(3)
6464
6565
julia> x[] = 1
6666
1
@@ -100,17 +100,17 @@ time.
100100
# Examples
101101
```jldoctest
102102
julia> x = Threads.Atomic{Int}(3)
103-
Base.Threads.Atomic{Int64}(3)
103+
Threads.Atomic{Int64}(3)
104104
105105
julia> Threads.atomic_cas!(x, 4, 2);
106106
107107
julia> x
108-
Base.Threads.Atomic{Int64}(3)
108+
Threads.Atomic{Int64}(3)
109109
110110
julia> Threads.atomic_cas!(x, 3, 2);
111111
112112
julia> x
113-
Base.Threads.Atomic{Int64}(2)
113+
Threads.Atomic{Int64}(2)
114114
```
115115
"""
116116
function atomic_cas! end
@@ -128,7 +128,7 @@ For further details, see LLVM's `atomicrmw xchg` instruction.
128128
# Examples
129129
```jldoctest
130130
julia> x = Threads.Atomic{Int}(3)
131-
Base.Threads.Atomic{Int64}(3)
131+
Threads.Atomic{Int64}(3)
132132
133133
julia> Threads.atomic_xchg!(x, 2)
134134
3
@@ -152,7 +152,7 @@ For further details, see LLVM's `atomicrmw add` instruction.
152152
# Examples
153153
```jldoctest
154154
julia> x = Threads.Atomic{Int}(3)
155-
Base.Threads.Atomic{Int64}(3)
155+
Threads.Atomic{Int64}(3)
156156
157157
julia> Threads.atomic_add!(x, 2)
158158
3
@@ -176,7 +176,7 @@ For further details, see LLVM's `atomicrmw sub` instruction.
176176
# Examples
177177
```jldoctest
178178
julia> x = Threads.Atomic{Int}(3)
179-
Base.Threads.Atomic{Int64}(3)
179+
Threads.Atomic{Int64}(3)
180180
181181
julia> Threads.atomic_sub!(x, 2)
182182
3
@@ -199,7 +199,7 @@ For further details, see LLVM's `atomicrmw and` instruction.
199199
# Examples
200200
```jldoctest
201201
julia> x = Threads.Atomic{Int}(3)
202-
Base.Threads.Atomic{Int64}(3)
202+
Threads.Atomic{Int64}(3)
203203
204204
julia> Threads.atomic_and!(x, 2)
205205
3
@@ -222,7 +222,7 @@ For further details, see LLVM's `atomicrmw nand` instruction.
222222
# Examples
223223
```jldoctest
224224
julia> x = Threads.Atomic{Int}(3)
225-
Base.Threads.Atomic{Int64}(3)
225+
Threads.Atomic{Int64}(3)
226226
227227
julia> Threads.atomic_nand!(x, 2)
228228
3
@@ -245,7 +245,7 @@ For further details, see LLVM's `atomicrmw or` instruction.
245245
# Examples
246246
```jldoctest
247247
julia> x = Threads.Atomic{Int}(5)
248-
Base.Threads.Atomic{Int64}(5)
248+
Threads.Atomic{Int64}(5)
249249
250250
julia> Threads.atomic_or!(x, 7)
251251
5
@@ -268,7 +268,7 @@ For further details, see LLVM's `atomicrmw xor` instruction.
268268
# Examples
269269
```jldoctest
270270
julia> x = Threads.Atomic{Int}(5)
271-
Base.Threads.Atomic{Int64}(5)
271+
Threads.Atomic{Int64}(5)
272272
273273
julia> Threads.atomic_xor!(x, 7)
274274
5
@@ -291,7 +291,7 @@ For further details, see LLVM's `atomicrmw max` instruction.
291291
# Examples
292292
```jldoctest
293293
julia> x = Threads.Atomic{Int}(5)
294-
Base.Threads.Atomic{Int64}(5)
294+
Threads.Atomic{Int64}(5)
295295
296296
julia> Threads.atomic_max!(x, 7)
297297
5
@@ -314,7 +314,7 @@ For further details, see LLVM's `atomicrmw min` instruction.
314314
# Examples
315315
```jldoctest
316316
julia> x = Threads.Atomic{Int}(7)
317-
Base.Threads.Atomic{Int64}(7)
317+
Threads.Atomic{Int64}(7)
318318
319319
julia> Threads.atomic_min!(x, 5)
320320
7

base/broadcast.jl

+3-3
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ Uses [`BroadcastStyle`](@ref) to get the style for each argument, and uses
411411
412412
```jldoctest
413413
julia> Broadcast.combine_styles([1], [1 2; 3 4])
414-
Base.Broadcast.DefaultArrayStyle{2}()
414+
Broadcast.DefaultArrayStyle{2}()
415415
```
416416
"""
417417
function combine_styles end
@@ -431,10 +431,10 @@ determine a common `BroadcastStyle`.
431431
432432
```jldoctest
433433
julia> Broadcast.result_style(Broadcast.DefaultArrayStyle{0}(), Broadcast.DefaultArrayStyle{3}())
434-
Base.Broadcast.DefaultArrayStyle{3}()
434+
Broadcast.DefaultArrayStyle{3}()
435435
436436
julia> Broadcast.result_style(Broadcast.Unknown(), Broadcast.DefaultArrayStyle{1}())
437-
Base.Broadcast.DefaultArrayStyle{1}()
437+
Broadcast.DefaultArrayStyle{1}()
438438
```
439439
"""
440440
function result_style end

base/iterators.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ See [`Base.filter`](@ref) for an eager implementation of filtering for arrays.
435435
# Examples
436436
```jldoctest
437437
julia> f = Iterators.filter(isodd, [1, 2, 3, 4, 5])
438-
Base.Iterators.Filter{typeof(isodd), Vector{Int64}}(isodd, [1, 2, 3, 4, 5])
438+
Iterators.Filter{typeof(isodd), Vector{Int64}}(isodd, [1, 2, 3, 4, 5])
439439
440440
julia> foreach(println, f)
441441
1

base/meta.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ julia> Meta.parse("x = ")
246246
:($(Expr(:incomplete, "incomplete: premature end of input")))
247247
248248
julia> Meta.parse("1.0.2")
249-
ERROR: Base.Meta.ParseError("invalid numeric constant \\\"1.0.\\\"")
249+
ERROR: Meta.ParseError("invalid numeric constant \\\"1.0.\\\"")
250250
Stacktrace:
251251
[...]
252252

base/show.jl

+47-52
Original file line numberDiff line numberDiff line change
@@ -429,20 +429,6 @@ function _show_default(io::IO, @nospecialize(x))
429429
print(io,')')
430430
end
431431

432-
# Check if a particular symbol is exported from a standard library module
433-
function is_exported_from_stdlib(name::Symbol, mod::Module)
434-
!isdefined(mod, name) && return false
435-
orig = getfield(mod, name)
436-
while !(mod === Base || mod === Core)
437-
parent = parentmodule(mod)
438-
if mod === Main || mod === parent || parent === Main
439-
return false
440-
end
441-
mod = parent
442-
end
443-
return isexported(mod, name) && isdefined(mod, name) && !isdeprecated(mod, name) && getfield(mod, name) === orig
444-
end
445-
446432
function show_function(io::IO, f::Function, compact::Bool)
447433
ft = typeof(f)
448434
mt = ft.name.mt
@@ -453,12 +439,7 @@ function show_function(io::IO, f::Function, compact::Bool)
453439
print(io, mt.name)
454440
elseif isdefined(mt, :module) && isdefined(mt.module, mt.name) &&
455441
getfield(mt.module, mt.name) === f
456-
if is_exported_from_stdlib(mt.name, mt.module) || mt.module === Main
457-
show_sym(io, mt.name)
458-
else
459-
print(io, mt.module, ".")
460-
show_sym(io, mt.name)
461-
end
442+
print_qualified_name(io, mt.module, mt.name)
462443
else
463444
show_default(io, f)
464445
end
@@ -584,17 +565,8 @@ function make_typealias(@nospecialize(x::Type))
584565
end
585566

586567
function show_typealias(io::IO, name::GlobalRef, x::Type, env::SimpleVector, wheres::Vector)
587-
if !(get(io, :compact, false)::Bool)
588-
# Print module prefix unless alias is visible from module passed to
589-
# IOContext. If :module is not set, default to Main. nothing can be used
590-
# to force printing prefix.
591-
from = get(io, :module, Main)
592-
if (from === nothing || !isvisible(name.name, name.mod, from))
593-
show(io, name.mod)
594-
print(io, ".")
595-
end
596-
end
597-
print(io, name.name)
568+
print_qualified_name(io, name.mod, name.name)
569+
598570
n = length(env)
599571
n == 0 && return
600572

@@ -866,13 +838,49 @@ end
866838
# If an object with this name exists in 'from', we need to check that it's the same binding
867839
# and that it's not deprecated.
868840
function isvisible(sym::Symbol, parent::Module, from::Module)
841+
if sym === nameof(from) && parent === parentmodule(from)
842+
# the name of a module is visible within itself, even though it's
843+
# a separate binding
844+
return true
845+
end
869846
owner = ccall(:jl_binding_owner, Any, (Any, Any), parent, sym)
870847
from_owner = ccall(:jl_binding_owner, Any, (Any, Any), from, sym)
871848
return owner !== nothing && from_owner === owner &&
872849
!isdeprecated(parent, sym) &&
873850
isdefined(from, sym) # if we're going to return true, force binding resolution
874851
end
875852

853+
function should_print_qualified(io::IO, m::Module, name::Symbol, from::Union{Module,Nothing} = get(io,:module,Main))
854+
return !isvisible(name, m, from)
855+
end
856+
857+
# Print `name` from module `m` in qualified form based on IO settings and identifier
858+
# visibility.
859+
# If :module is not set, default to Main. `nothing` can be used to force printing prefix.
860+
# The optional `from` argument exists so that the Main default can be set in
861+
# a central place and possibly phased out eventually.
862+
function print_qualified_name(io::IO, m::Module, name::Symbol, from::Union{Module,Nothing} = get(io,:module,Main))
863+
quo = false
864+
if !(get(io, :compact, false)::Bool)
865+
if from === nothing || !isvisible(name, m, from)
866+
show(IOContext(io, :module=>from), m)
867+
print(io, ".")
868+
if is_valid_identifier(name) && !is_id_start_char(first(string(name)))
869+
print(io, ':')
870+
if name in quoted_syms
871+
print(io, '(')
872+
quo = true
873+
end
874+
end
875+
end
876+
show_sym(io, name)
877+
quo && print(io, ')')
878+
else
879+
print(io, name)
880+
end
881+
nothing
882+
end
883+
876884
function is_global_function(tn::Core.TypeName, globname::Union{Symbol,Nothing})
877885
if globname !== nothing
878886
globname_str = string(globname::Symbol)
@@ -895,26 +903,11 @@ function show_type_name(io::IO, tn::Core.TypeName)
895903
globfunc = is_global_function(tn, globname)
896904
sym = (globfunc ? globname : tn.name)::Symbol
897905
globfunc && print(io, "typeof(")
898-
quo = false
899-
if !(get(io, :compact, false)::Bool)
900-
# Print module prefix unless type is visible from module passed to
901-
# IOContext If :module is not set, default to Main. nothing can be used
902-
# to force printing prefix
903-
from = get(io, :module, Main)
904-
if isdefined(tn, :module) && (from === nothing || !isvisible(sym, tn.module, from))
905-
show(io, tn.module)
906-
print(io, ".")
907-
if globfunc && !is_id_start_char(first(string(sym)))
908-
print(io, ':')
909-
if sym in quoted_syms
910-
print(io, '(')
911-
quo = true
912-
end
913-
end
914-
end
906+
if isdefined(tn, :module)
907+
print_qualified_name(io, tn.module, sym)
908+
else
909+
show_sym(io, sym)
915910
end
916-
show_sym(io, sym)
917-
quo && print(io, ")")
918911
globfunc && print(io, ")")
919912
nothing
920913
end
@@ -1023,10 +1016,12 @@ function show(io::IO, m::Module)
10231016
if is_root_module(m)
10241017
print(io, nameof(m))
10251018
else
1026-
print(io, join(fullname(m),"."))
1019+
print_qualified_name(io, parentmodule(m), nameof(m))
10271020
end
10281021
end
10291022

1023+
print(io::IO, m::Module) = print(io, nameof(m))
1024+
10301025
function sourceinfo_slotnames(src::CodeInfo)
10311026
slotnames = src.slotnames
10321027
names = Dict{String,Int}()
@@ -2216,7 +2211,7 @@ function show_signature_function(io::IO, @nospecialize(ft), demangle=false, farg
22162211
if ft <: Function && isa(uw, DataType) && isempty(uw.parameters) &&
22172212
isdefined(uw.name.module, uw.name.mt.name) &&
22182213
ft == typeof(getfield(uw.name.module, uw.name.mt.name))
2219-
if qualified && !is_exported_from_stdlib(uw.name.mt.name, uw.name.module) && uw.name.module !== Main
2214+
if qualified && should_print_qualified(io, uw.name.module, uw.name.mt.name)
22202215
print_within_stacktrace(io, uw.name.module, '.', bold=true)
22212216
end
22222217
s = sprint(show_sym, (demangle ? demangle_function_name : identity)(uw.name.mt.name), context=io)

doc/src/devdocs/inference.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,9 @@ map(f, t::Tuple{Any}) in Base at tuple.jl:179
106106
1 │ %2 = Base.sitofp(Float64, %1)::Float64
107107
2 │ %3 = Base.lt_float(%2, 0.0)::Bool
108108
0 └── goto #3 if not %3
109-
0 2 ─ invoke Base.Math.throw_complex_domainerror(:sqrt::Symbol, %2::Float64)::Union{}
109+
0 2 ─ invoke Math.throw_complex_domainerror(:sqrt::Symbol, %2::Float64)::Union{}
110110
0 └── unreachable
111-
20 3 ─ %7 = Base.Math.sqrt_llvm(%2)::Float64
111+
20 3 ─ %7 = Math.sqrt_llvm(%2)::Float64
112112
0 └── goto #4
113113
0 4 ─ goto #5
114114
0 5 ─ %10 = Core.tuple(%7)::Tuple{Float64}

stdlib/Distributed/src/pmap.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ and `tail`: an iterator over the remaining elements.
241241
242242
```jldoctest
243243
julia> b, c = Distributed.head_and_tail(1:10, 3)
244-
([1, 2, 3], Base.Iterators.Rest{UnitRange{Int64}, Int64}(1:10, 3))
244+
([1, 2, 3], Iterators.Rest{UnitRange{Int64}, Int64}(1:10, 3))
245245
246246
julia> collect(c)
247247
7-element Vector{Int64}:

test/show.jl

+13-1
Original file line numberDiff line numberDiff line change
@@ -1628,7 +1628,7 @@ end
16281628

16291629
b = IOBuffer()
16301630
show(IOContext(b, :module => @__MODULE__), TestShowType.TypeA)
1631-
@test String(take!(b)) == "$(@__MODULE__).TestShowType.TypeA"
1631+
@test String(take!(b)) == "TestShowType.TypeA"
16321632

16331633
b = IOBuffer()
16341634
show(IOContext(b, :module => TestShowType), TestShowType.TypeA)
@@ -2162,3 +2162,15 @@ end
21622162
s = sprint(show, MIME("text/plain"), Function)
21632163
@test s == "Function"
21642164
end
2165+
2166+
# issue #39834, minimal qualifying of module paths in printing
2167+
module M39834
2168+
export A39834
2169+
module A39834
2170+
struct Foo end
2171+
end
2172+
struct (+) end
2173+
end
2174+
using .M39834
2175+
@test sprint(show, M39834.A39834.Foo, context = :module => @__MODULE__) == "A39834.Foo"
2176+
@test sprint(show, M39834.:+, context = :module => @__MODULE__) == "M39834.:+"

test/testenv.jl

+4-2
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,10 @@ if !@isdefined(testenv_defined)
4141
end
4242

4343
const curmod = @__MODULE__
44-
const curmod_name = fullname(curmod)
45-
const curmod_str = curmod === Main ? "Main" : join(curmod_name, ".")
44+
const curmod_name = let fn = fullname(curmod)
45+
fn[1] === :Main ? fn[2:end] : fn
46+
end
47+
const curmod_str = join(curmod_name, ".")
4648
const curmod_prefix = "$(["$m." for m in curmod_name]...)"
4749

4850
# platforms that support cfunction with closures

0 commit comments

Comments
 (0)