Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bugfixes for showing type aliases #39366

Merged
merged 4 commits into from
Jan 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 87 additions & 38 deletions base/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -532,8 +532,9 @@ function makeproper(io::IO, x::Type)
push!(y, typ)
end
end
normal || (x = Union{y...})
properx = rewrap_unionall(x, properx)
if !normal
properx = rewrap_unionall(Union{y...}, properx)
end
end
has_free_typevars(properx) && return Any
return properx
Expand All @@ -554,7 +555,7 @@ function make_typealias(@nospecialize(x::Type))
for name in names(mod)
if isdefined(mod, name) && !isdeprecated(mod, name) && isconst(mod, name)
alias = getfield(mod, name)
if alias isa Type && !has_free_typevars(alias) && !isvarargtype(alias) && !print_without_params(alias) && x <: alias
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this change be removed for the backport to 1.6?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this commit can be ignored for the backport

if alias isa Type && !has_free_typevars(alias) && !print_without_params(alias) && x <: alias
if alias isa UnionAll
(ti, env) = ccall(:jl_type_intersection_with_env, Any, (Any, Any), x, alias)::SimpleVector
# ti === Union{} && continue # impossible, since we already checked that x <: alias
Expand All @@ -580,8 +581,8 @@ function make_typealias(@nospecialize(x::Type))
applied = rewrap_unionall(applied, p)
end
has_free_typevars(applied) && continue
applied == x || continue # it couldn't figure out the parameter matching
elseif alias <: x
applied === x || continue # it couldn't figure out the parameter matching
elseif alias === x
env = Core.svec()
else
continue # not a complete match
Expand All @@ -596,7 +597,7 @@ function make_typealias(@nospecialize(x::Type))
end
end

function show_typealias(io::IO, name::GlobalRef, x::Type, env::SimpleVector)
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
Expand All @@ -612,34 +613,70 @@ function show_typealias(io::IO, name::GlobalRef, x::Type, env::SimpleVector)
n == 0 && return

print(io, "{")
let io = IOContext(io)
for i = n:-1:1
p = env[i]
if p isa TypeVar
io = IOContext(io, :unionall_env => p)
param_io = IOContext(io)
for i = 1:length(wheres)
p = wheres[i]::TypeVar
param_io = IOContext(param_io, :unionall_env => p)
end
for i = 1:n
p = env[i]
show(param_io, p)
i < n && print(io, ", ")
end
print(io, "}")
end

function make_wheres(io::IO, env::SimpleVector, @nospecialize(x::Type))
seen = IdSet()
wheres = TypeVar[]
# record things printed by the context
if io isa IOContext
for (key, val) in io.dict
if key === :unionall_env && val isa TypeVar && has_typevar(x, val)
push!(seen, val)
end
end
for i = 1:n
p = env[i]
show(io, p)
i < n && print(io, ", ")
end
# record things in x to print outermost
while x isa UnionAll
if !(x.var in seen)
push!(seen, x.var)
push!(wheres, x.var)
end
x = x.body
end
print(io, "}")
for i = n:-1:1
# record remaining things in env to print innermost
for i = length(env):-1:1
p = env[i]
if p isa TypeVar && !io_has_tvar_name(io, p.name, x)
print(io, " where ")
show(io, p)
if p isa TypeVar && !(p in seen)
push!(seen, p)
pushfirst!(wheres, p)
end
end
return wheres
end

function show_wheres(io::IO, env::Vector)
isempty(env) && return
io = IOContext(io)
n = length(env)
for i = 1:n
p = env[i]::TypeVar
print(io, n == 1 ? " where " : i == 1 ? " where {" : ", ")
show(io, p)
io = IOContext(io, :unionall_env => p)
end
n > 1 && print(io, "}")
nothing
end

function show_typealias(io::IO, x::Type)
properx = makeproper(io, x)
alias = make_typealias(properx)
alias === nothing && return false
show_typealias(io, alias[1], x, alias[2])
wheres = make_wheres(io, alias[2], x)
show_typealias(io, alias[1], x, alias[2], wheres)
show_wheres(io, wheres)
return true
end

Expand All @@ -661,7 +698,7 @@ function make_typealiases(@nospecialize(x::Type))
for name in names(mod)
if isdefined(mod, name) && !isdeprecated(mod, name) && isconst(mod, name)
alias = getfield(mod, name)
if alias isa Type && !has_free_typevars(alias) && !isvarargtype(alias) && !print_without_params(alias) && !(alias <: Tuple)
if alias isa Type && !has_free_typevars(alias) && !print_without_params(alias) && !(alias <: Tuple)
(ti, env) = ccall(:jl_type_intersection_with_env, Any, (Any, Any), x, alias)::SimpleVector
ti === Union{} && continue
mod in modulesof!(Set{Module}(), alias) || continue # make sure this alias wasn't from an unrelated part of the Union
Expand Down Expand Up @@ -735,13 +772,17 @@ function show_unionaliases(io::IO, x::Union)
end
if first && length(aliases) == 1
alias = aliases[1]
show_typealias(io, alias[1], x, alias[2])
wheres = make_wheres(io, alias[2], x)
show_typealias(io, alias[1], x, alias[2], wheres)
show_wheres(io, wheres)
else
for alias in aliases
print(io, first ? "Union{" : ", ")
first = false
env = alias[2]
show_typealias(io, alias[1], x, alias[2])
wheres = make_wheres(io, alias[2], x)
show_typealias(io, alias[1], x, alias[2], wheres)
show_wheres(io, wheres)
end
print(io, "}")
end
Expand All @@ -751,7 +792,7 @@ function show(io::IO, ::MIME"text/plain", @nospecialize(x::Type))
show(io, x)
if !print_without_params(x) && get(io, :compact, true)
properx = makeproper(io, x)
if make_typealias(properx) !== nothing || x <: make_typealiases(properx)[2]
if make_typealias(properx) !== nothing || (unwrap_unionall(x) isa Union && x <: make_typealiases(properx)[2])
print(io, " (alias for ")
show(IOContext(io, :compact => false), x)
print(io, ")")
Expand Down Expand Up @@ -786,22 +827,30 @@ function show(io::IO, @nospecialize(x::Type))
end

x = x::UnionAll
if x.var.name === :_ || io_has_tvar_name(io, x.var.name, x)
counter = 1
while true
newname = Symbol(x.var.name, counter)
if !io_has_tvar_name(io, newname, x)
newtv = TypeVar(newname, x.var.lb, x.var.ub)
x = UnionAll(newtv, x{newtv})
break
wheres = TypeVar[]
let io = IOContext(io)
while x isa UnionAll
var = x.var
if var.name === :_ || io_has_tvar_name(io, var.name, x)
counter = 1
while true
newname = Symbol(var.name, counter)
if !io_has_tvar_name(io, newname, x)
var = TypeVar(newname, var.lb, var.ub)
x = x{var}
break
end
counter += 1
end
else
x = x.body
end
counter += 1
push!(wheres, var)
io = IOContext(io, :unionall_env => var)
end
show(io, x)
end

show(IOContext(io, :unionall_env => x.var), x.body)
print(io, " where ")
show(io, x.var)
show_wheres(io, wheres)
end

# Check whether 'sym' (defined in module 'parent') is visible from module 'from'
Expand Down
12 changes: 9 additions & 3 deletions test/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,7 @@ end
# `where` syntax
@test_repr "A where T<:B"
@test_repr "A where T<:(Array{T} where T<:Real)"
@test_repr "Array{T} where T<:Array{S} where S<:Real"
@test_repr "Array{T} where {S<:Real, T<:Array{S}}"
@test_repr "x::Array{T} where T"
@test_repr "(a::b) where T"
@test_repr "a::b where T"
Expand Down Expand Up @@ -1568,12 +1568,12 @@ end
end

let x = TypeVar(:_), y = TypeVar(:_)
@test repr(UnionAll(x, UnionAll(y, Pair{x,y}))) == "Pair{_1, _2} where _2 where _1"
@test repr(UnionAll(x, UnionAll(y, Pair{x,y}))) == "Pair{_1, _2} where {_1, _2}"
@test repr(UnionAll(x, UnionAll(y, Pair{UnionAll(x,Ref{x}),y}))) == "Pair{Ref{_1} where _1, _1} where _1"
x = TypeVar(:a)
y = TypeVar(:a)
z = TypeVar(:a)
@test repr(UnionAll(z, UnionAll(x, UnionAll(y, Tuple{x,y,z})))) == "Tuple{a1, a2, a} where a2 where a1 where a"
@test repr(UnionAll(z, UnionAll(x, UnionAll(y, Tuple{x,y,z})))) == "Tuple{a1, a2, a} where {a, a1, a2}"
end

@testset "showarg" begin
Expand Down Expand Up @@ -2070,15 +2070,21 @@ end
end

module M37012
export AValue, B2
struct AnInteger{S<:Integer} end
struct AStruct{N} end
const AValue{S} = Union{AStruct{S}, AnInteger{S}}
struct BStruct{T,S} end
const B2{S,T} = BStruct{T,S}
end
@test Base.make_typealias(M37012.AStruct{1}) === nothing
@test isempty(Base.make_typealiases(M37012.AStruct{1})[1])
@test string(M37012.AStruct{1}) == "$(curmod_prefix)M37012.AStruct{1}"
@test string(Union{Nothing, Number, Vector}) == "Union{Nothing, Number, Vector{T} where T}"
@test string(Union{Nothing, AbstractVecOrMat}) == "Union{Nothing, AbstractVecOrMat{T} where T}"
@test string(M37012.BStruct{T, T} where T) == "$(curmod_prefix)M37012.B2{T, T} where T"
@test string(M37012.BStruct{T, S} where {T<:Unsigned, S<:Signed}) == "$(curmod_prefix)M37012.B2{S, T} where {T<:Unsigned, S<:Signed}"
@test string(M37012.BStruct{T, S} where {T<:Signed, S<:T}) == "$(curmod_prefix)M37012.B2{S, T} where {T<:Signed, S<:T}"

@test sprint(show, :(./)) == ":((./))"
@test sprint(show, :((.|).(.&, b))) == ":((.|).((.&), b))"
Expand Down