Skip to content

Commit

Permalink
Make dump print const before const fields (#53492)
Browse files Browse the repository at this point in the history
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 <aviatesk@gmail.com>
  • Loading branch information
jakobnissen and aviatesk authored Mar 3, 2024
1 parent e3b2462 commit 86f5b21
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 61 deletions.
11 changes: 10 additions & 1 deletion base/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -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])
Expand Down
12 changes: 6 additions & 6 deletions doc/src/devdocs/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -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}
```
Expand Down Expand Up @@ -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
...
Expand Down
108 changes: 54 additions & 54 deletions test/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)"

Expand Down

0 comments on commit 86f5b21

Please sign in to comment.