Make verify trim printing more readable (also fix the colours)#60350
Make verify trim printing more readable (also fix the colours)#60350DilumAluthge merged 14 commits intomasterfrom
Conversation
topolarity
left a comment
There was a problem hiding this comment.
Looks like a solid improvement to me. Thanks @gbaraldi !
Compiler/src/verifytrim.jl
Outdated
| if newstmt.head ∈ (:quote, :inert) | ||
| return newstmt | ||
| # Check if a union is small with concrete types (same logic as code_warntype's is_expected_union) | ||
| function is_expected_union(@nospecialize(u::Union)) |
There was a problem hiding this comment.
Maybe instead of duplicating, we should move these into the Compiler printing utilities and have InteractiveUtils pull them in from there?
Compiler/src/verifytrim.jl
Outdated
| end | ||
|
|
||
| # Print with light_black if stable, normal otherwise | ||
| function print_styled(io::IO, @nospecialize(x), stable::Bool) |
There was a problem hiding this comment.
| function print_styled(io::IO, @nospecialize(x), stable::Bool) | |
| function print_nontype(io::IO, @nospecialize(x), stable::Bool) |
Not a great name, but better than print_styled and printstyled floating around in the same function
| # Convert Core.Argument to slot name symbol if available | ||
| function argument_name(codeinfo::CodeInfo, arg::Core.Argument) | ||
| slotnames = codeinfo.slotnames | ||
| if slotnames !== nothing && arg.n <= length(slotnames) |
There was a problem hiding this comment.
The IR verifier seems to suggest that codeinfo.slotnames is always populated and the right length - Is that not true?
There was a problem hiding this comment.
Where do you see that?
There was a problem hiding this comment.
Most uses I see do check it.
Compiler/src/verifytrim.jl
Outdated
| if codeinfo.slotnames !== nothing | ||
| io = IOContext(io, :SOURCE_SLOTNAMES => sourceinfo_slotnames(codeinfo)) | ||
| # Colors for matching parentheses at different nesting levels | ||
| const PAREN_COLORS = (:blue, :yellow, :magenta, :cyan, :green) |
There was a problem hiding this comment.
I'm really not a fan of multi-colored parentheses personally
They really overload the maximum number of visual items I can track at a time. Do you think they're very helpful?
Compiler/src/verifytrim.jl
Outdated
| if warn | ||
| printstyled(io, "Verifier warning #", no, ": "; color=Base.warn_color(), bold=true) | ||
| else | ||
| printstyled(io, "Verifier error #", no, ": "; color=Base.error_color(), bold=true) | ||
| end |
There was a problem hiding this comment.
| if warn | |
| printstyled(io, "Verifier warning #", no, ": "; color=Base.warn_color(), bold=true) | |
| else | |
| printstyled(io, "Verifier error #", no, ": "; color=Base.error_color(), bold=true) | |
| end | |
| printstyled(io, "Problem #", no, ": "; color=Base.warn_color(), bold=true) |
The index is shared but these are counted separately, so changing between "error" / "warning" seems a bit confusing to me
There was a problem hiding this comment.
I went with just error here. I don't think the user deciding to ignore errors means we should print them as warnings
9c34e95 to
eca85d5
Compare
There was a problem hiding this comment.
Looks like you're missing a repr when printing constant values:
Error #1: unresolved call from statement Base.print(
Base.stdout::IO,
x::String,
::String # this is "\n"::String
)::Nothingran into this with:
function @main(ARGS)
println("hello!")
endThis can also end up with some pretty complex output at times:
Main.SimpleLib.unsafe_wrap(
Main.SimpleLib.Array::Type{Array},
Base.getproperty(
Base.getproperty(
Main.SimpleLib.tree::Any,
…::Symbol
)::Any,
:data::Symbol
)::Any,
Base.getproperty(
Base.getproperty(
Main.SimpleLib.tree::Any,
…::Symbol
)::Any,
:length::Symbol
)::Any
)::Array{T, N} where {N, T}I'm not sure unwrapping that many calls is needed? It seems that beyond 1 or 2 you are likely to want to dive into the IR instead.
Oh and the usage of "…" reminds me of Varargs, but that's not what it means. It would be good to make that clearer somehow.
Compiler/src/verifytrim.jl
Outdated
| function argument_name(codeinfo::CodeInfo, arg::Core.Argument) | ||
| slotnames = codeinfo.slotnames | ||
| if slotnames !== nothing && arg.n <= length(slotnames) | ||
| return slotnames[arg.n] |
topolarity
left a comment
There was a problem hiding this comment.
This is looking pretty good now!
My only remaining wishlist is to translate intrinsics back to user-familiar syntax, such as:
- getproperty(x::T, :field)::FieldT -> (x::T).field::FieldT
- Base.memoryrefget((…)::MemoryRef{T}, (…)::Symbol, (…)::Bool) -> (...)[]::T
- etc.
I'm sure there will be plenty of details to work out w.r.t. when we can do that faithfully without mis-leading the user and exactly how we want to translate it all, so probably best left to a separate PR anyway.
Very minor, but I also think it'd be nice to have an extra newline before the stacktrace, like:
Error #1: unresolved call from statement Main.SimpleLib.println(
Main.SimpleLib.stderr::IO,
"bad time"::String,
Base.memoryrefget((…)::MemoryRef{Main.SimpleLib.CTree{Float64}}, (…)::Symbol, (…)::Bool)::Main.SimpleLib.CTree{Float64}
)::Any
Stacktrace:
[1] size(tree::Main.SimpleLib.CTree{Float64})
@ Main.SimpleLib ~/repos/julia/test/trimming/libsimple.jl:9
[2] size(tree::Main.SimpleLib.CTree{Float64})
@ Main.SimpleLib ~/repos/julia/test/trimming/libsimple.jl:11Other than that, this looks ready to go to me. Thanks again @gbaraldi !
Compiler/src/verifytrim.jl
Outdated
| # Use repr for strings/chars to show quotes | ||
| function print_nontype(io::IO, @nospecialize(x), stable::Bool) | ||
| stable ? printstyled(io, x; color=:light_black) : print(io, x) | ||
| txt = x isa Union{AbstractString, AbstractChar} ? Base.repr(x) : x |
There was a problem hiding this comment.
Any reason not to always use repr?
|
Actually hold on.. This seems to still have pretty aggressive nesting somehow: Base.prod(
Base.getfield(
Main.SimpleLib.unsafe_wrap(
(…)::Type{Array},
Base.getproperty(
Base.getproperty(
Main.SimpleLib.tree::Any,
(…)::Symbol
)::Any,
(…)::Symbol
)::Any,
Base.getproperty(
Base.getproperty(
Main.SimpleLib.tree::Any,
(…)::Symbol
)::Any,
(…)::Symbol
)::Any
)::Array{T, N} where {N, T},
(…)::Symbol
)::NTuple{N, Int64} where N
)::Int64Is the limit not being applied? This would almost be readable if we translated the intrinsics back to syntax, but as-is it's pretty overwhelming |
|
Also the Can we avoid abbreviating "small" constant values in that position? |
|
We may want to port this to 1.13. and maybe even 1.12 (it's technically a bug fix of #60412 |
pr:

master:

Inspired by @jakobnissen's blog https://viralinstruction.com/posts/aoc2025/
Written with AI help