Skip to content

Commit fb59c19

Browse files
authored
Merge pull request #39366 from JuliaLang/jn/compacttypealias
bugfixes for showing type aliases
2 parents f31ef76 + ee816ef commit fb59c19

File tree

2 files changed

+96
-41
lines changed

2 files changed

+96
-41
lines changed

base/show.jl

Lines changed: 87 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -532,8 +532,9 @@ function makeproper(io::IO, x::Type)
532532
push!(y, typ)
533533
end
534534
end
535-
normal || (x = Union{y...})
536-
properx = rewrap_unionall(x, properx)
535+
if !normal
536+
properx = rewrap_unionall(Union{y...}, properx)
537+
end
537538
end
538539
has_free_typevars(properx) && return Any
539540
return properx
@@ -554,7 +555,7 @@ function make_typealias(@nospecialize(x::Type))
554555
for name in names(mod)
555556
if isdefined(mod, name) && !isdeprecated(mod, name) && isconst(mod, name)
556557
alias = getfield(mod, name)
557-
if alias isa Type && !has_free_typevars(alias) && !isvarargtype(alias) && !print_without_params(alias) && x <: alias
558+
if alias isa Type && !has_free_typevars(alias) && !print_without_params(alias) && x <: alias
558559
if alias isa UnionAll
559560
(ti, env) = ccall(:jl_type_intersection_with_env, Any, (Any, Any), x, alias)::SimpleVector
560561
# ti === Union{} && continue # impossible, since we already checked that x <: alias
@@ -580,8 +581,8 @@ function make_typealias(@nospecialize(x::Type))
580581
applied = rewrap_unionall(applied, p)
581582
end
582583
has_free_typevars(applied) && continue
583-
applied == x || continue # it couldn't figure out the parameter matching
584-
elseif alias <: x
584+
applied === x || continue # it couldn't figure out the parameter matching
585+
elseif alias === x
585586
env = Core.svec()
586587
else
587588
continue # not a complete match
@@ -596,7 +597,7 @@ function make_typealias(@nospecialize(x::Type))
596597
end
597598
end
598599

599-
function show_typealias(io::IO, name::GlobalRef, x::Type, env::SimpleVector)
600+
function show_typealias(io::IO, name::GlobalRef, x::Type, env::SimpleVector, wheres::Vector)
600601
if !(get(io, :compact, false)::Bool)
601602
# Print module prefix unless alias is visible from module passed to
602603
# IOContext. If :module is not set, default to Main. nothing can be used
@@ -612,34 +613,70 @@ function show_typealias(io::IO, name::GlobalRef, x::Type, env::SimpleVector)
612613
n == 0 && return
613614

614615
print(io, "{")
615-
let io = IOContext(io)
616-
for i = n:-1:1
617-
p = env[i]
618-
if p isa TypeVar
619-
io = IOContext(io, :unionall_env => p)
616+
param_io = IOContext(io)
617+
for i = 1:length(wheres)
618+
p = wheres[i]::TypeVar
619+
param_io = IOContext(param_io, :unionall_env => p)
620+
end
621+
for i = 1:n
622+
p = env[i]
623+
show(param_io, p)
624+
i < n && print(io, ", ")
625+
end
626+
print(io, "}")
627+
end
628+
629+
function make_wheres(io::IO, env::SimpleVector, @nospecialize(x::Type))
630+
seen = IdSet()
631+
wheres = TypeVar[]
632+
# record things printed by the context
633+
if io isa IOContext
634+
for (key, val) in io.dict
635+
if key === :unionall_env && val isa TypeVar && has_typevar(x, val)
636+
push!(seen, val)
620637
end
621638
end
622-
for i = 1:n
623-
p = env[i]
624-
show(io, p)
625-
i < n && print(io, ", ")
639+
end
640+
# record things in x to print outermost
641+
while x isa UnionAll
642+
if !(x.var in seen)
643+
push!(seen, x.var)
644+
push!(wheres, x.var)
626645
end
646+
x = x.body
627647
end
628-
print(io, "}")
629-
for i = n:-1:1
648+
# record remaining things in env to print innermost
649+
for i = length(env):-1:1
630650
p = env[i]
631-
if p isa TypeVar && !io_has_tvar_name(io, p.name, x)
632-
print(io, " where ")
633-
show(io, p)
651+
if p isa TypeVar && !(p in seen)
652+
push!(seen, p)
653+
pushfirst!(wheres, p)
634654
end
635655
end
656+
return wheres
657+
end
658+
659+
function show_wheres(io::IO, env::Vector)
660+
isempty(env) && return
661+
io = IOContext(io)
662+
n = length(env)
663+
for i = 1:n
664+
p = env[i]::TypeVar
665+
print(io, n == 1 ? " where " : i == 1 ? " where {" : ", ")
666+
show(io, p)
667+
io = IOContext(io, :unionall_env => p)
668+
end
669+
n > 1 && print(io, "}")
670+
nothing
636671
end
637672

638673
function show_typealias(io::IO, x::Type)
639674
properx = makeproper(io, x)
640675
alias = make_typealias(properx)
641676
alias === nothing && return false
642-
show_typealias(io, alias[1], x, alias[2])
677+
wheres = make_wheres(io, alias[2], x)
678+
show_typealias(io, alias[1], x, alias[2], wheres)
679+
show_wheres(io, wheres)
643680
return true
644681
end
645682

@@ -661,7 +698,7 @@ function make_typealiases(@nospecialize(x::Type))
661698
for name in names(mod)
662699
if isdefined(mod, name) && !isdeprecated(mod, name) && isconst(mod, name)
663700
alias = getfield(mod, name)
664-
if alias isa Type && !has_free_typevars(alias) && !isvarargtype(alias) && !print_without_params(alias) && !(alias <: Tuple)
701+
if alias isa Type && !has_free_typevars(alias) && !print_without_params(alias) && !(alias <: Tuple)
665702
(ti, env) = ccall(:jl_type_intersection_with_env, Any, (Any, Any), x, alias)::SimpleVector
666703
ti === Union{} && continue
667704
mod in modulesof!(Set{Module}(), alias) || continue # make sure this alias wasn't from an unrelated part of the Union
@@ -735,13 +772,17 @@ function show_unionaliases(io::IO, x::Union)
735772
end
736773
if first && length(aliases) == 1
737774
alias = aliases[1]
738-
show_typealias(io, alias[1], x, alias[2])
775+
wheres = make_wheres(io, alias[2], x)
776+
show_typealias(io, alias[1], x, alias[2], wheres)
777+
show_wheres(io, wheres)
739778
else
740779
for alias in aliases
741780
print(io, first ? "Union{" : ", ")
742781
first = false
743782
env = alias[2]
744-
show_typealias(io, alias[1], x, alias[2])
783+
wheres = make_wheres(io, alias[2], x)
784+
show_typealias(io, alias[1], x, alias[2], wheres)
785+
show_wheres(io, wheres)
745786
end
746787
print(io, "}")
747788
end
@@ -751,7 +792,7 @@ function show(io::IO, ::MIME"text/plain", @nospecialize(x::Type))
751792
show(io, x)
752793
if !print_without_params(x) && get(io, :compact, true)
753794
properx = makeproper(io, x)
754-
if make_typealias(properx) !== nothing || x <: make_typealiases(properx)[2]
795+
if make_typealias(properx) !== nothing || (unwrap_unionall(x) isa Union && x <: make_typealiases(properx)[2])
755796
print(io, " (alias for ")
756797
show(IOContext(io, :compact => false), x)
757798
print(io, ")")
@@ -786,22 +827,30 @@ function show(io::IO, @nospecialize(x::Type))
786827
end
787828

788829
x = x::UnionAll
789-
if x.var.name === :_ || io_has_tvar_name(io, x.var.name, x)
790-
counter = 1
791-
while true
792-
newname = Symbol(x.var.name, counter)
793-
if !io_has_tvar_name(io, newname, x)
794-
newtv = TypeVar(newname, x.var.lb, x.var.ub)
795-
x = UnionAll(newtv, x{newtv})
796-
break
830+
wheres = TypeVar[]
831+
let io = IOContext(io)
832+
while x isa UnionAll
833+
var = x.var
834+
if var.name === :_ || io_has_tvar_name(io, var.name, x)
835+
counter = 1
836+
while true
837+
newname = Symbol(var.name, counter)
838+
if !io_has_tvar_name(io, newname, x)
839+
var = TypeVar(newname, var.lb, var.ub)
840+
x = x{var}
841+
break
842+
end
843+
counter += 1
844+
end
845+
else
846+
x = x.body
797847
end
798-
counter += 1
848+
push!(wheres, var)
849+
io = IOContext(io, :unionall_env => var)
799850
end
851+
show(io, x)
800852
end
801-
802-
show(IOContext(io, :unionall_env => x.var), x.body)
803-
print(io, " where ")
804-
show(io, x.var)
853+
show_wheres(io, wheres)
805854
end
806855

807856
# Check whether 'sym' (defined in module 'parent') is visible from module 'from'

test/show.jl

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,7 @@ end
634634
# `where` syntax
635635
@test_repr "A where T<:B"
636636
@test_repr "A where T<:(Array{T} where T<:Real)"
637-
@test_repr "Array{T} where T<:Array{S} where S<:Real"
637+
@test_repr "Array{T} where {S<:Real, T<:Array{S}}"
638638
@test_repr "x::Array{T} where T"
639639
@test_repr "(a::b) where T"
640640
@test_repr "a::b where T"
@@ -1568,12 +1568,12 @@ end
15681568
end
15691569

15701570
let x = TypeVar(:_), y = TypeVar(:_)
1571-
@test repr(UnionAll(x, UnionAll(y, Pair{x,y}))) == "Pair{_1, _2} where _2 where _1"
1571+
@test repr(UnionAll(x, UnionAll(y, Pair{x,y}))) == "Pair{_1, _2} where {_1, _2}"
15721572
@test repr(UnionAll(x, UnionAll(y, Pair{UnionAll(x,Ref{x}),y}))) == "Pair{Ref{_1} where _1, _1} where _1"
15731573
x = TypeVar(:a)
15741574
y = TypeVar(:a)
15751575
z = TypeVar(:a)
1576-
@test repr(UnionAll(z, UnionAll(x, UnionAll(y, Tuple{x,y,z})))) == "Tuple{a1, a2, a} where a2 where a1 where a"
1576+
@test repr(UnionAll(z, UnionAll(x, UnionAll(y, Tuple{x,y,z})))) == "Tuple{a1, a2, a} where {a, a1, a2}"
15771577
end
15781578

15791579
@testset "showarg" begin
@@ -2070,15 +2070,21 @@ end
20702070
end
20712071

20722072
module M37012
2073+
export AValue, B2
20732074
struct AnInteger{S<:Integer} end
20742075
struct AStruct{N} end
20752076
const AValue{S} = Union{AStruct{S}, AnInteger{S}}
2077+
struct BStruct{T,S} end
2078+
const B2{S,T} = BStruct{T,S}
20762079
end
20772080
@test Base.make_typealias(M37012.AStruct{1}) === nothing
20782081
@test isempty(Base.make_typealiases(M37012.AStruct{1})[1])
20792082
@test string(M37012.AStruct{1}) == "$(curmod_prefix)M37012.AStruct{1}"
20802083
@test string(Union{Nothing, Number, Vector}) == "Union{Nothing, Number, Vector{T} where T}"
20812084
@test string(Union{Nothing, AbstractVecOrMat}) == "Union{Nothing, AbstractVecOrMat{T} where T}"
2085+
@test string(M37012.BStruct{T, T} where T) == "$(curmod_prefix)M37012.B2{T, T} where T"
2086+
@test string(M37012.BStruct{T, S} where {T<:Unsigned, S<:Signed}) == "$(curmod_prefix)M37012.B2{S, T} where {T<:Unsigned, S<:Signed}"
2087+
@test string(M37012.BStruct{T, S} where {T<:Signed, S<:T}) == "$(curmod_prefix)M37012.B2{S, T} where {T<:Signed, S<:T}"
20822088

20832089
@test sprint(show, :(./)) == ":((./))"
20842090
@test sprint(show, :((.|).(.&, b))) == ":((.|).((.&), b))"

0 commit comments

Comments
 (0)