Skip to content

Commit b30c886

Browse files
committed
RFC: errorshow: simplify printing of keyword argument types using a new macro format
In Julia, keyword arguments are represented as `Base.Pairs` objects. However, the object type often appears unnecessarily complex, especially when printed in a stack trace. This commit aims to simplify the printing of stack traces that involve keyword method calls, while still allowing us to reconstruct the actual method signature types from the printed signature types. The approach is similar to #49117: this commit introduces a new macro called `Base.@Kwargs`. It follows the same syntax as `@NamedTuple` and returns a `Base.Pairs` type that is used for keyword method calls. We use this syntax when printing keyword argument types. Here's an example of a stack trace: ```diff diff --git a/b.jl b/a.jl index 91dd6f0464..b804ae4be5 100644 --- a/b.jl +++ b/a.jl @@ -22,12 +22,11 @@ Stacktrace: @ Base ./reduce.jl:44 [inlined] [6] mapfoldl(f::typeof(identity), op::typeof(Base.add_sum), itr::String; init::Int64) @ Base ./reduce.jl:175 [inlined] - [7] mapreduce(f::typeof(identity), op::typeof(Base.add_sum), itr::String; kw::Base.Pairs{…}) + [7] mapreduce(f::typeof(identity), op::typeof(Base.add_sum), itr::String; kw::Base.@kwargs{init::Int64}) @ Base ./reduce.jl:307 [inlined] - [8] sum(f::typeof(identity), a::String; kw::Base.Pairs{Symbol, Int64, Tuple{Symbol}, @NamedTuple{init::Int64}}) + [8] sum(f::typeof(identity), a::String; kw::Base.@kwargs{init::Int64}) @ Base ./reduce.jl:535 [inlined] - [9] sum(a::String; kw::Base.Pairs{Symbol, Int64, Tuple{Symbol}, @NamedTuple{init::Int64}}) + [9] sum(a::String; kw::Base.@kwargs{init::Int64}) @ Base ./reduce.jl:564 [inlined] [10] top-level scope ``` Feel free to share any comments or suggestions. If this idea seems acceptable, I will add test cases and also address any broken test cases.
1 parent 91cd521 commit b30c886

File tree

2 files changed

+46
-13
lines changed

2 files changed

+46
-13
lines changed

base/namedtuple.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,13 @@ macro NamedTuple(ex)
495495
return :(NamedTuple{($(vars...),), Tuple{$(types...)}})
496496
end
497497

498+
macro Kwargs(ex)
499+
return :(let
500+
NT = @NamedTuple $ex
501+
Base.Pairs{keytype(NT),eltype(NT),typeof(NT.parameters[1]),NT}
502+
end)
503+
end
504+
498505
@constprop :aggressive function split_rest(t::NamedTuple{names}, n::Int, st...) where {names}
499506
_check_length_split_rest(length(t), n)
500507
names_front, names_last_n = split_rest(names, n, st...)

base/show.jl

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,10 +1057,27 @@ function show_type_name(io::IO, tn::Core.TypeName)
10571057
nothing
10581058
end
10591059

1060+
function maybe_kws_nt(x::DataType)
1061+
x.name === typename(Pairs) || return nothing
1062+
length(x.parameters) == 4 || return nothing
1063+
x.parameters[1] === Symbol || return nothing
1064+
p4 = x.parameters[4]
1065+
if (isa(p4, DataType) && p4.name === typename(NamedTuple) && length(p4.parameters) == 2)
1066+
syms, types = p4.parameters
1067+
types isa DataType || return nothing
1068+
x.parameters[2] === eltype(p4) || return nothing
1069+
isa(syms, Tuple) || return nothing
1070+
x.parameters[3] === typeof(syms) || return nothing
1071+
return p4
1072+
end
1073+
return nothing
1074+
end
1075+
10601076
function show_datatype(io::IO, x::DataType, wheres::Vector{TypeVar}=TypeVar[])
10611077
parameters = x.parameters::SimpleVector
10621078
istuple = x.name === Tuple.name
10631079
isnamedtuple = x.name === typename(NamedTuple)
1080+
kwsnt = maybe_kws_nt(x)
10641081
n = length(parameters)
10651082

10661083
# Print tuple types with homogeneous tails longer than max_n compactly using `NTuple` or `Vararg`
@@ -1094,30 +1111,39 @@ function show_datatype(io::IO, x::DataType, wheres::Vector{TypeVar}=TypeVar[])
10941111
return
10951112
elseif isnamedtuple
10961113
syms, types = parameters
1097-
first = true
10981114
if syms isa Tuple && types isa DataType
10991115
print(io, "@NamedTuple{")
1100-
for i in 1:length(syms)
1101-
if !first
1102-
print(io, ", ")
1103-
end
1104-
print(io, syms[i])
1105-
typ = types.parameters[i]
1106-
if typ !== Any
1107-
print(io, "::")
1108-
show(io, typ)
1109-
end
1110-
first = false
1111-
end
1116+
show_at_namedtuple(io, syms, types)
11121117
print(io, "}")
11131118
return
11141119
end
1120+
elseif kwsnt !== nothing
1121+
print(io, "Base.@Kwargs{")
1122+
show_at_namedtuple(io, kwsnt.parameters...)
1123+
print(io, "}")
1124+
return
11151125
end
11161126

11171127
show_type_name(io, x.name)
11181128
show_typeparams(io, parameters, (unwrap_unionall(x.name.wrapper)::DataType).parameters, wheres)
11191129
end
11201130

1131+
function show_at_namedtuple(io::IO, syms::Tuple, types::DataType)
1132+
first = true
1133+
for i in 1:length(syms)
1134+
if !first
1135+
print(io, ", ")
1136+
end
1137+
print(io, syms[i])
1138+
typ = types.parameters[i]
1139+
if typ !== Any
1140+
print(io, "::")
1141+
show(io, typ)
1142+
end
1143+
first = false
1144+
end
1145+
end
1146+
11211147
function show_supertypes(io::IO, typ::DataType)
11221148
print(io, typ)
11231149
while typ != Any

0 commit comments

Comments
 (0)