From 86f5b218ca8c99e9eea6b23208e6bd5569f8b504 Mon Sep 17 00:00:00 2001 From: Jakob Nybo Nissen Date: Sun, 3 Mar 2024 02:16:23 +0100 Subject: [PATCH] Make dump print `const` before const fields (#53492) This provides more information to the user when dumping types, and also makes the output of dump slightly more similar to the type definition syntax. EDIT: This has been changed to print: * The kind of type before the type name `abstract type`, `mutable struct`, etc. * `const` only for `const` fields of `mutable struct` New behaviour ``` julia> dump(Float32) primitive type Float32 <: AbstractFloat julia> dump(Signed) abstract type Signed <: Integer julia> dump(Pair{Int, String}) struct Pair{Int64, String} <: Any first::Int64 second::String julia> dump(BitSet) mutable struct BitSet <: AbstractSet{Int64} const bits::Vector{UInt64} offset::Int64 julia> dump(Set) UnionAll var: TypeVar name: Symbol T lb: Union{} ub: abstract type Any body: struct Set{T} <: AbstractSet{T} dict::Dict{T, Nothing} ``` --------- Co-authored-by: Shuhei Kadowaki --- base/show.jl | 11 +++- doc/src/devdocs/types.md | 12 ++--- test/show.jl | 108 +++++++++++++++++++-------------------- 3 files changed, 70 insertions(+), 61 deletions(-) diff --git a/base/show.jl b/base/show.jl index 217b22ab39ef8..df429830b16fd 100644 --- a/base/show.jl +++ b/base/show.jl @@ -2986,6 +2986,13 @@ end # Types function dump(io::IOContext, x::DataType, n::Int, indent) + # For some reason, tuples are structs + is_struct = isstructtype(x) && !(x <: Tuple) + is_mut = is_struct && ismutabletype(x) + is_mut && print(io, "mutable ") + is_struct && print(io, "struct ") + isprimitivetype(x) && print(io, "primitive type ") + isabstracttype(x) && print(io, "abstract type ") print(io, x) if x !== Any print(io, " <: ", supertype(x)) @@ -3007,7 +3014,9 @@ function dump(io::IOContext, x::DataType, n::Int, indent) fieldtypes = datatype_fieldtypes(x) for idx in 1:length(fields) println(io) - print(io, indent, " ", fields[idx]) + print(io, indent, " ") + is_mut && isconst(x, idx) && print(io, "const ") + print(io, fields[idx]) if isassigned(fieldtypes, idx) print(io, "::") print(tvar_io, fieldtypes[idx]) diff --git a/doc/src/devdocs/types.md b/doc/src/devdocs/types.md index 120c948c6cadc..7a5ede63b1989 100644 --- a/doc/src/devdocs/types.md +++ b/doc/src/devdocs/types.md @@ -93,13 +93,13 @@ UnionAll var: TypeVar name: Symbol T lb: Union{} - ub: Any + ub: abstract type Any body: UnionAll var: TypeVar name: Symbol N lb: Union{} - ub: Any - body: Array{T, N} <: DenseArray{T, N} + ub: abstract type Any + body: mutable struct Array{T, N} <: DenseArray{T, N} ref::MemoryRef{T} size::NTuple{N, Int64} ``` @@ -181,13 +181,13 @@ TypeName var: TypeVar name: Symbol T lb: Union{} - ub: Any + ub: abstract type Any body: UnionAll var: TypeVar name: Symbol N lb: Union{} - ub: Any - body: Array{T, N} <: DenseArray{T, N} + ub: abstract type Any + body: mutable struct Array{T, N} <: DenseArray{T, N} cache: SimpleVector ... diff --git a/test/show.jl b/test/show.jl index 064ae76b6fe1f..8d6b32a3fd663 100644 --- a/test/show.jl +++ b/test/show.jl @@ -703,7 +703,7 @@ let oldout = stdout, olderr = stderr redirect_stderr(olderr) close(wrout) close(wrerr) - @test fetch(out) == "Int64 <: Signed\nTESTA\nTESTB\nΑ1Β2\"A\"\nA\n123\"C\"\n" + @test fetch(out) == "primitive type Int64 <: Signed\nTESTA\nTESTB\nΑ1Β2\"A\"\nA\n123\"C\"\n" @test fetch(err) == "TESTA\nTESTB\nΑ1Β2\"A\"\n" finally redirect_stdout(oldout) @@ -1259,64 +1259,64 @@ end close(s2) end -let repr = sprint(dump, :(x = 1)) - @test repr == "Expr\n head: Symbol =\n args: Array{Any}((2,))\n 1: Symbol x\n 2: $Int 1\n" -end -let repr = sprint(dump, Pair{String,Int64}) - @test repr == "Pair{String, Int64} <: Any\n first::String\n second::Int64\n" -end -let repr = sprint(dump, Tuple) - @test repr == "Tuple <: Any\n" -end -let repr = sprint(dump, Int64) - @test repr == "Int64 <: Signed\n" -end -let repr = sprint(dump, Any) - @test length(repr) == 4 - @test occursin(r"^Any\n", repr) - @test endswith(repr, '\n') -end -let repr = sprint(dump, Integer) - @test occursin("Integer <: Real", repr) - @test !occursin("Any", repr) -end -let repr = sprint(dump, Union{Integer, Float32}) - @test repr == "Union{Integer, Float32}\n" || repr == "Union{Float32, Integer}\n" -end module M30442 struct T end end -let repr = sprint(show, Union{String, M30442.T}) - @test repr == "Union{$(curmod_prefix)M30442.T, String}" || - repr == "Union{String, $(curmod_prefix)M30442.T}" -end -let repr = sprint(dump, Ptr{UInt8}(UInt(1))) - @test repr == "Ptr{UInt8} @$(Base.repr(UInt(1)))\n" -end -let repr = sprint(dump, Core.svec()) - @test repr == "empty SimpleVector\n" -end -let repr = sprint(dump, sin) - @test repr == "sin (function of type typeof(sin))\n" -end -let repr = sprint(dump, Test) - @test repr == "Module Test\n" -end -let repr = sprint(dump, nothing) - @test repr == "Nothing nothing\n" -end -let a = Vector{Any}(undef, 10000) - a[2] = "elemA" - a[4] = "elemB" - a[11] = "elemC" - repr = sprint(dump, a; context=(:limit => true), sizehint=0) - @test repr == "Array{Any}((10000,))\n 1: #undef\n 2: String \"elemA\"\n 3: #undef\n 4: String \"elemB\"\n 5: #undef\n ...\n 9996: #undef\n 9997: #undef\n 9998: #undef\n 9999: #undef\n 10000: #undef\n" -end -@test occursin("NamedTuple", sprint(dump, NamedTuple)) +@testset "Dump types" begin + let repr = sprint(dump, :(x = 1)) + @test repr == "Expr\n head: Symbol =\n args: Array{Any}((2,))\n 1: Symbol x\n 2: $Int 1\n" + end + let repr = sprint(dump, Pair{String,Int64}) + @test repr == "struct Pair{String, Int64} <: Any\n first::String\n second::Int64\n" + end + let repr = sprint(dump, Tuple) + @test repr == "Tuple <: Any\n" + end + let repr = sprint(dump, Int64) + @test repr == "primitive type Int64 <: Signed\n" + end + let repr = sprint(dump, Any) + @test repr == "abstract type Any\n" + end + let repr = sprint(dump, Integer) + @test occursin("abstract type Integer <: Real", repr) + @test !occursin("Any", repr) + end + let repr = sprint(dump, Union{Integer, Float32}) + @test repr == "Union{Integer, Float32}\n" || repr == "Union{Float32, Integer}\n" + end -# issue 36495, dumping a partial NamedTupled shouldn't error -@test occursin("NamedTuple", sprint(dump, NamedTuple{(:foo,:bar)})) + let repr = sprint(show, Union{String, M30442.T}) + @test repr == "Union{$(curmod_prefix)M30442.T, String}" || + repr == "Union{String, $(curmod_prefix)M30442.T}" + end + let repr = sprint(dump, Ptr{UInt8}(UInt(1))) + @test repr == "Ptr{UInt8} @$(Base.repr(UInt(1)))\n" + end + let repr = sprint(dump, Core.svec()) + @test repr == "empty SimpleVector\n" + end + let repr = sprint(dump, sin) + @test repr == "sin (function of type typeof(sin))\n" + end + let repr = sprint(dump, Test) + @test repr == "Module Test\n" + end + let repr = sprint(dump, nothing) + @test repr == "Nothing nothing\n" + end + let a = Vector{Any}(undef, 10000) + a[2] = "elemA" + a[4] = "elemB" + a[11] = "elemC" + repr = sprint(dump, a; context=(:limit => true), sizehint=0) + @test repr == "Array{Any}((10000,))\n 1: #undef\n 2: String \"elemA\"\n 3: #undef\n 4: String \"elemB\"\n 5: #undef\n ...\n 9996: #undef\n 9997: #undef\n 9998: #undef\n 9999: #undef\n 10000: #undef\n" + end + @test occursin("NamedTuple", sprint(dump, NamedTuple)) + # issue 36495, dumping a partial NamedTupled shouldn't error + @test occursin("NamedTuple", sprint(dump, NamedTuple{(:foo,:bar)})) +end # issue #17338 @test repr(Core.svec(1, 2)) == "svec(1, 2)"