Skip to content

Commit

Permalink
Merge pull request JuliaLang#39395 from JuliaLang/jn/feature/print-un…
Browse files Browse the repository at this point in the history
…ionall

make printing of typealias env shorter using `{<:T}` syntax, when preferable
  • Loading branch information
vtjnash committed Apr 3, 2021
2 parents 31b66d5 + e593839 commit c0d2e1a
Show file tree
Hide file tree
Showing 7 changed files with 184 additions and 58 deletions.
127 changes: 93 additions & 34 deletions base/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,69 @@ function make_typealias(@nospecialize(x::Type))
end
end

isgensym(s::Symbol) = '#' in string(s)

function show_can_elide(p::TypeVar, wheres::Vector, elide::Int, env::SimpleVector, skip::Int)
elide == 0 && return false
wheres[elide] === p || return false
for i = (elide + 1):length(wheres)
v = wheres[i]::TypeVar
has_typevar(v.lb, p) && return false
has_typevar(v.ub, p) && return false
end
for i = 1:length(env)
i == skip && continue
has_typevar(env[i], p) && return false
end
return true
end

function show_typeparams(io::IO, env::SimpleVector, orig::SimpleVector, wheres::Vector)
n = length(env)
elide = length(wheres)
function egal_var(p::TypeVar, @nospecialize o)
return o isa TypeVar &&
ccall(:jl_types_egal, Cint, (Any, Any), p.ub, o.ub) != 0 &&
ccall(:jl_types_egal, Cint, (Any, Any), p.lb, o.lb) != 0
end
for i = n:-1:1
p = env[i]
if p isa TypeVar
if i == n && egal_var(p, orig[i]) && show_can_elide(p, wheres, elide, env, i)
n -= 1
elide -= 1
elseif p.lb === Union{} && isgensym(p.name) && show_can_elide(p, wheres, elide, env, i)
elide -= 1
elseif p.ub === Any && isgensym(p.name) && show_can_elide(p, wheres, elide, env, i)
elide -= 1
end
end
end
if n > 0
print(io, "{")
for i = 1:n
p = env[i]
if p isa TypeVar
if p.lb === Union{} && something(findfirst(@nospecialize(w) -> w === p, wheres), 0) > elide
print(io, "<:")
show(io, p.ub)
elseif p.ub === Any && something(findfirst(@nospecialize(w) -> w === p, wheres), 0) > elide
print(io, ">:")
show(io, p.lb)
else
show(io, p)
end
else
show(io, p)
end
i < n && print(io, ", ")
end
print(io, "}")
end
resize!(wheres, elide)
nothing
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
Expand All @@ -596,21 +659,19 @@ function show_typealias(io::IO, name::GlobalRef, x::Type, env::SimpleVector, whe
end
end
print(io, name.name)
n = length(env)
n == 0 && return

print(io, "{")
param_io = IOContext(io)
for i = 1:length(wheres)
p = wheres[i]::TypeVar
param_io = IOContext(param_io, :unionall_env => p)
isempty(env) && return
io = IOContext(io)
for p in wheres
io = IOContext(io, :unionall_env => p)
end
for i = 1:n
p = env[i]
show(param_io, p)
i < n && print(io, ", ")
orig = getfield(name.mod, name.name)
vars = TypeVar[]
while orig isa UnionAll
push!(vars, orig.var)
orig = orig.body
end
print(io, "}")
show_typeparams(io, env, Core.svec(vars...), wheres)
nothing
end

function make_wheres(io::IO, env::SimpleVector, @nospecialize(x::Type))
Expand Down Expand Up @@ -643,12 +704,12 @@ function make_wheres(io::IO, env::SimpleVector, @nospecialize(x::Type))
return wheres
end

function show_wheres(io::IO, env::Vector)
isempty(env) && return
function show_wheres(io::IO, wheres::Vector)
isempty(wheres) && return
io = IOContext(io)
n = length(env)
n = length(wheres)
for i = 1:n
p = env[i]::TypeVar
p = wheres[i]::TypeVar
print(io, n == 1 ? " where " : i == 1 ? " where {" : ", ")
show(io, p)
io = IOContext(io, :unionall_env => p)
Expand Down Expand Up @@ -858,7 +919,11 @@ function _show_type(io::IO, @nospecialize(x::Type))
push!(wheres, var)
io = IOContext(io, :unionall_env => var)
end
show(io, x)
if x isa DataType
show_datatype(io, x, wheres)
else
show(io, x)
end
end
show_wheres(io, wheres)
end
Expand Down Expand Up @@ -920,29 +985,23 @@ function show_type_name(io::IO, tn::Core.TypeName)
nothing
end

function show_datatype(io::IO, @nospecialize(x::DataType))
function show_datatype(io::IO, @nospecialize(x::DataType), wheres::Vector=TypeVar[])
parameters = x.parameters::SimpleVector
istuple = x.name === Tuple.name
n = length(parameters)

# Print homogeneous tuples with more than 3 elements compactly as NTuple{N, T}
if istuple && n > 3 && all(i -> (parameters[1] === i), parameters)
print(io, "NTuple{", n, ", ", parameters[1], "}")
if istuple
if n > 3 && all(@nospecialize(i) -> (parameters[1] === i), parameters)
print(io, "NTuple{", n, ", ", parameters[1], "}")
else
print(io, "Tuple{")
join(io, parameters, ", ")
print(io, "}")
end
else
show_type_name(io, x.name)
if (n > 0 || istuple) && x !== Tuple
# Do not print the type parameters for the primary type if we are
# printing a method signature or type parameter.
# Always print the type parameter if we are printing the type directly
# since this information is still useful.
print(io, '{')
for i = 1:n
p = parameters[i]
show(io, p)
i < n && print(io, ", ")
end
print(io, '}')
end
show_typeparams(io, parameters, unwrap_unionall(x.name.wrapper).parameters, wheres)
end
end

Expand Down
4 changes: 2 additions & 2 deletions doc/src/manual/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -1033,8 +1033,8 @@ The `where` keyword itself can be nested inside a more complex declaration. For
consider the two types created by the following declarations:

```jldoctest
julia> const T1 = Array{Array{T,1} where T, 1}
Vector{Vector{T} where T} (alias for Array{Array{T, 1} where T, 1})
julia> const T1 = Array{Array{T, 1} where T, 1}
Vector{Vector} (alias for Array{Array{T, 1} where T, 1})
julia> const T2 = Array{Array{T, 1}, 1} where T
Array{Vector{T}, 1} where T
Expand Down
2 changes: 1 addition & 1 deletion stdlib/InteractiveUtils/test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ end
Base.getindex(A::Stable, i) = A.A[i]
Base.getindex(A::Unstable, i) = A.A[i]

tag = "ARRAY{FLOAT64, N}"
tag = "ARRAY"
@test warntype_hastag(getindex, Tuple{Unstable{Float64},Int}, tag)
@test !warntype_hastag(getindex, Tuple{Stable{Float64,2},Int}, tag)
@test warntype_hastag(getindex, Tuple{Stable{Float64},Int}, tag)
Expand Down
2 changes: 1 addition & 1 deletion stdlib/REPL/src/docview.jl
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ function summarize(io::IO, TT::Type, binding::Binding)
println(io, "# Subtypes")
println(io, "```")
for t in subt
println(io, t)
println(io, Base.unwrap_unionall(t))
end
println(io, "```")
end
Expand Down
22 changes: 11 additions & 11 deletions test/docs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -965,10 +965,10 @@ abstract type $(curmod_prefix)Undocumented.at0{T<:Number, N}
# Subtypes
```
$(curmod_prefix)Undocumented.at1{T, N} where {Integer<:T<:Number, N}
$(curmod_prefix)Undocumented.pt2
$(curmod_prefix)Undocumented.st3
$(curmod_prefix)Undocumented.st4{T, N} where {T<:Number, N}
$(curmod_prefix)Undocumented.at1{Integer<:T<:Number, N}
$(curmod_prefix)Undocumented.pt2{T<:Number, N, A>:Integer}
$(curmod_prefix)Undocumented.st3{T<:Integer, N}
$(curmod_prefix)Undocumented.st4{T<:Number, N}
```
""")
@test docstrings_equal(@doc(Undocumented.at0), doc"$doc_str")
Expand All @@ -985,7 +985,7 @@ abstract type $(curmod_prefix)Undocumented.at1{T>:Integer, N}
# Subtypes
```
$(curmod_prefix)Undocumented.mt6{Integer, N} where N
$(curmod_prefix)Undocumented.mt6{Integer, N}
```
# Supertype Hierarchy
Expand All @@ -1007,9 +1007,9 @@ abstract type $(curmod_prefix)Undocumented.at0{Int64, N}
# Subtypes
```
$(curmod_prefix)Undocumented.pt2{Int64, N, A} where {N, A>:Integer}
$(curmod_prefix)Undocumented.st3{Int64, N} where N
$(curmod_prefix)Undocumented.st4{Int64, N} where N
$(curmod_prefix)Undocumented.pt2{Int64, N, A>:Integer}
$(curmod_prefix)Undocumented.st3{Int64, N}
$(curmod_prefix)Undocumented.st4{Int64, N}
```
""")
@test docstrings_equal(@doc(Undocumented.at_), doc"$doc_str")
Expand Down Expand Up @@ -1157,9 +1157,9 @@ No documentation found.
# Union Composed of Types
- `$(curmod_prefix)Undocumented.at1{T, N} where {T, N}`
- `$(curmod_prefix)Undocumented.pt2{T, N, A} where {T, N, A>:Integer}`
- `$(curmod_prefix)Undocumented.st3{T, N} where {T, N}`
- `$(curmod_prefix)Undocumented.at1{T} where T`
- `$(curmod_prefix)Undocumented.pt2{T} where T`
- `$(curmod_prefix)Undocumented.st3{T} where T`
- `$(curmod_prefix)Undocumented.st4`
""")
@test docstrings_equal(@doc(Undocumented.ut9), doc"$doc_str")
Expand Down
2 changes: 1 addition & 1 deletion 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{T} where T)")
"foo13825(::Array{T, N}, ::Array, ::Vector) where {T, N} in")

mutable struct TLayout
x::Int8
Expand Down
83 changes: 75 additions & 8 deletions test/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1569,12 +1569,77 @@ end
end

let x = TypeVar(:_), y = TypeVar(:_)
@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"
@test repr(UnionAll(x, UnionAll(y, Pair{x,y}))) == "Pair"
@test repr(UnionAll(y, UnionAll(x, Pair{x,y}))) == "Pair{_2, _1} where {_1, _2}"
@test repr(UnionAll(x, UnionAll(y, Pair{UnionAll(x,Ref{x}),y}))) == "Pair{Ref}"
@test repr(UnionAll(y, UnionAll(x, Pair{UnionAll(y,Ref{x}),y}))) == "Pair{Ref{_2}, _1} where {_1, _2}"
end

let x, y, x
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 {a, a1, a2}"
@test repr(UnionAll(z, UnionAll(x, UnionAll(y, Tuple{z,y,x})))) == "Tuple{a, a2, a1} where {a, a1, a2}"
end

let x = TypeVar(:_, Number), y = TypeVar(:_, Number)
@test repr(UnionAll(x, UnionAll(y, Pair{x,y}))) == "Pair{_1, _2} where {_1<:Number, _2<:Number}"
@test repr(UnionAll(y, UnionAll(x, Pair{x,y}))) == "Pair{_2, _1} where {_1<:Number, _2<:Number}"
@test repr(UnionAll(x, UnionAll(y, Pair{UnionAll(x,Ref{x}),y}))) == "Pair{Ref{_1} where _1<:Number, _1} where _1<:Number"
@test repr(UnionAll(y, UnionAll(x, Pair{UnionAll(y,Ref{x}),y}))) == "Pair{Ref{_2}, _1} where {_1<:Number, _2<:Number}"
end


is_juliarepr(x) = eval(Meta.parse(repr(x))) == x
@testset "unionall types" begin
X = TypeVar(gensym())
Y = TypeVar(gensym(), Ref, Ref)
x, y, z = TypeVar(:a), TypeVar(:a), TypeVar(:a)
struct TestTVUpper{A<:Integer} end

# named typevars
@test is_juliarepr(Ref{A} where A)
@test is_juliarepr(Ref{A} where A>:Ref)
@test is_juliarepr(Ref{A} where A<:Ref)
@test is_juliarepr(Ref{A} where Ref<:A<:Ref)
@test is_juliarepr(TestTVUpper{<:Real})
@test is_juliarepr(TestTVUpper{<:Integer})
@test is_juliarepr(TestTVUpper{<:Signed})

# typearg order
@test is_juliarepr(UnionAll(X, Pair{X,<:Any}))
@test is_juliarepr(UnionAll(X, Pair{<:Any,X}))

# duplicates
@test is_juliarepr(UnionAll(X, Pair{X,X}))

# nesting
@test is_juliarepr(UnionAll(X, Ref{Ref{X}}))
@test is_juliarepr(Union{T, Int} where T)
@test is_juliarepr(Pair{A, <:A} where A)

# renumbered typevars with same names
@test is_juliarepr(UnionAll(z, UnionAll(x, UnionAll(y, Tuple{x,y,z}))))

# shortened typevar printing
@test repr(Ref{<:Any}) == "Ref"
@test repr(Pair{1, <:Any}) == "Pair{1}"
@test repr(Ref{<:Number}) == "Ref{<:Number}"
@test repr(Pair{1, <:Number}) == "Pair{1, <:Number}"
@test repr(Ref{<:Ref}) == "Ref{<:Ref}"
@test repr(Ref{>:Ref}) == "Ref{>:Ref}"
@test repr(Pair{<:Any, 1}) == "Pair{<:Any, 1}"
yname = sprint(Base.show_unquoted, Y.name)
@test repr(UnionAll(Y, Ref{Y})) == "Ref{$yname} where Ref<:$yname<:Ref"
@test endswith(repr(TestTVUpper{<:Real}), "TestTVUpper{<:Real}")
@test endswith(repr(TestTVUpper), "TestTVUpper")
@test endswith(repr(TestTVUpper{<:Signed}), "TestTVUpper{<:Signed}")

# exception for tuples
@test is_juliarepr(Tuple)
@test is_juliarepr(Tuple{})
@test is_juliarepr(Tuple{<:Any})
end

@testset "showarg" begin
Expand Down Expand Up @@ -1659,7 +1724,7 @@ end
@test showstr([Float16(1)]) == "Float16[1.0]"
@test showstr([[Float16(1)]]) == "Vector{Float16}[[1.0]]"
@test replstr(Real[Float16(1)]) == "1-element Vector{Real}:\n Float16(1.0)"
@test replstr(Array{Real}[Real[1]]) == "1-element Vector{Array{Real, N} where N}:\n [1]"
@test replstr(Array{Real}[Real[1]]) == "1-element Vector{Array{Real}}:\n [1]"
# printing tuples (Issue #25042)
@test replstr(fill((Int64(1), zeros(Float16, 3)), 1)) ==
"1-element Vector{Tuple{Int64, Vector{Float16}}}:\n (1, [0.0, 0.0, 0.0])"
Expand Down Expand Up @@ -1708,7 +1773,7 @@ end
# issue #28159
@test replstr([(a=1, b=2), (a=3,c=4)]) == "2-element Vector{NamedTuple{names, Tuple{$Int, $Int}} where names}:\n (a = 1, b = 2)\n (a = 3, c = 4)"

@test replstr(Vector[Any[1]]) == "1-element Vector{Vector{T} where T}:\n Any[1]"
@test replstr(Vector[Any[1]]) == "1-element Vector{Vector}:\n Any[1]"
@test replstr(AbstractDict{Integer,Integer}[Dict{Integer,Integer}(1=>2)]) ==
"1-element Vector{AbstractDict{Integer, Integer}}:\n Dict(1 => 2)"

Expand Down Expand Up @@ -1935,7 +2000,7 @@ end

@testset """printing "Any" is not skipped with nested arrays""" begin
@test replstr(Union{X28004,Vector}[X28004(Any[X28004(1)])], :compact => true) ==
"1-element Vector{Union{X28004, Vector{T} where T}}:\n X(Any[X(1)])"
"1-element Vector{Union{X28004, Vector}}:\n X(Any[X(1)])"
end

# Issue 25589 - Underlines in cmd printing
Expand Down Expand Up @@ -2102,15 +2167,17 @@ 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(Union{Nothing, Number, Vector}) == "Union{Nothing, Number, Vector}"
@test string(Union{Nothing, Number, Vector{<:Integer}}) == "Union{Nothing, Number, Vector{<:Integer}}"
@test string(Union{Nothing, AbstractVecOrMat}) == "Union{Nothing, AbstractVecOrMat}"
@test string(Union{Nothing, AbstractVecOrMat{<:Integer}}) == "Union{Nothing, AbstractVecOrMat{<:Integer}}"
@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 string(Union{M37012.SimpleU, Nothing}) == "Union{Nothing, $(curmod_prefix)M37012.SimpleU}"
@test string(Union{M37012.SimpleU, Nothing, T} where T) == "Union{Nothing, $(curmod_prefix)M37012.SimpleU, T} where T"
@test string(Union{AbstractVector{T}, T} where T) == "Union{AbstractVector{T}, T} where T"
@test string(Union{AbstractVector, T} where T) == "Union{AbstractVector{T} where T, T} where T"
@test string(Union{AbstractVector, T} where T) == "Union{AbstractVector, T} where T"

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

0 comments on commit c0d2e1a

Please sign in to comment.