diff --git a/base/show.jl b/base/show.jl index 134d0e159f182..3340d007ac5d5 100644 --- a/base/show.jl +++ b/base/show.jl @@ -148,21 +148,29 @@ end show(io::IO, x::TypeConstructor) = show(io, x.body) -function show_type_parameter(io::IO, p::ANY) - if p === String - print(io, "String") - else +function show_type_parameter(io::IO, p::ANY, has_tvar_env::Bool) + if has_tvar_env show(io, p) + else + show(IOContext(io, :tvar_env, true), p) end end function show(io::IO, x::DataType) show(io, x.name) - if (!isempty(x.parameters) || x.name === Tuple.name) && x !== Tuple + # tvar_env is a `::Vector{Any}` when we are printing a method signature + # and `true` if we are printing type parameters outside a method signature. + has_tvar_env = get(io, :tvar_env, false) !== false + if ((!isempty(x.parameters) || x.name === Tuple.name) && x !== Tuple && + !(has_tvar_env && x.name.primary === x)) + # 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, '{') n = length(x.parameters) for (i, p) in enumerate(x.parameters) - show_type_parameter(io, p) + show_type_parameter(io, p, has_tvar_env) i < n && print(io, ',') end print(io, '}') @@ -922,13 +930,22 @@ function ismodulecall(ex::Expr) end function show(io::IO, tv::TypeVar) + # If `tvar_env` exist and we are in it, the type constraint are + # already printed and we don't need to print it again. + # Otherwise, the lower bound should be printed if it is not `Bottom` + # and the upper bound should be printed if it is not `Any`. + # The upper bound `Any` should also be printed if we are not in the + # existing `tvar_env` in order to resolve the ambiguity when printing a + # method signature. + # i.e. `foo{T,N}(::Array{T,N}, ::Vector)` should be printed as + # `foo{T,N}(::Array{T,N}, ::Array{T<:Any,1})` tvar_env = isa(io, IOContext) && get(io, :tvar_env, false) if isa(tvar_env, Vector{Any}) have_env = true in_env = (tv in tvar_env::Vector{Any}) else have_env = false - in_env = true + in_env = false end if !in_env && !is(tv.lb, Bottom) show(io, tv.lb) diff --git a/test/reflection.jl b/test/reflection.jl index 967d81cc6cf06..df23c930f7b6f 100644 --- a/test/reflection.jl +++ b/test/reflection.jl @@ -225,11 +225,15 @@ let t13464 = "hey there sailor" end end +# PR 13825 let ex = :(a + b) @test string(ex) == "a + b" ex.typ = Integer @test string(ex) == "(a + b)::Integer" end +foo13825{T,N}(::Array{T,N}, ::Array, ::Vector) = nothing +@test startswith(string(first(methods(foo13825))), + "foo13825{T,N}(::Array{T,N}, ::Array, ::Array{T<:Any,1})") type TLayout x::Int8 diff --git a/test/replutil.jl b/test/replutil.jl index 652081723e89e..ba529e088e5dc 100644 --- a/test/replutil.jl +++ b/test/replutil.jl @@ -273,9 +273,9 @@ let err_str, @test sprint(show, which(:a, Tuple{})) == "(::Symbol)() at $sp:$(method_defs_lineno + 1)" @test sprint(show, which(EightBitType, Tuple{})) == "EightBitType() at $sp:$(method_defs_lineno + 2)" @test sprint(show, which(reinterpret(EightBitType, 0x54), Tuple{})) == "(::EightBitType)() at $sp:$(method_defs_lineno + 3)" - @test sprint(show, which(EightBitTypeT, Tuple{})) == "(::Type{EightBitTypeT{T<:Any}})() at $sp:$(method_defs_lineno + 4)" + @test sprint(show, which(EightBitTypeT, Tuple{})) == "(::Type{EightBitTypeT})() at $sp:$(method_defs_lineno + 4)" @test sprint(show, which(EightBitTypeT{Int32}, Tuple{})) == "(::Type{EightBitTypeT{T}}){T}() at $sp:$(method_defs_lineno + 5)" - @test sprint(show, which(reinterpret(EightBitTypeT{Int32}, 0x54), Tuple{})) == "(::EightBitTypeT{T<:Any})() at $sp:$(method_defs_lineno + 6)" + @test sprint(show, which(reinterpret(EightBitTypeT{Int32}, 0x54), Tuple{})) == "(::EightBitTypeT)() at $sp:$(method_defs_lineno + 6)" @test startswith(sprint(show, which(Base.(Symbol("@doc")), Tuple{Vararg{Any}})), "@doc(x...) at boot.jl:") @test startswith(sprint(show, which(FunctionLike(), Tuple{})), "(::FunctionLike)() at $sp:$(method_defs_lineno + 7)") @test stringmime("text/plain", FunctionLike()) == "(::FunctionLike) (generic function with 1 method)" diff --git a/test/show.jl b/test/show.jl index 237406a6126a6..0bdc7652db3b3 100644 --- a/test/show.jl +++ b/test/show.jl @@ -436,3 +436,11 @@ let x = [], y = [] push!(y, x) @test replstr(x) == "1-element Array{Any,1}:\n Any[Any[Any[#= circular reference @-2 =#]]]" end + +# PR 16221 +# Printing of upper and lower bound of a TypeVar +@test string(TypeVar(:V, Signed, Real, false)) == "Signed<:V<:Real" +# Printing of primary type in type parameter place should not show the type +# parameter names. +@test string(Array) == "Array{T,N}" +@test string(Tuple{Array}) == "Tuple{Array}"