-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor stacktrace processing and display pipeline for more clarity and less redundancy #55841
base: master
Are you sure you want to change the base?
Conversation
Could the first entry be removed? Saying that an error starts at |
This PR wouldn't be the spot for a change like that. I'm personally all for removing frames that aren't useful, though formally a stacktrace needs to show where an error was thrown from, and the error function is just a convenience to trigger an error. So it wouldn't be a default even if possible. That said, there are bigger fish to fry when it comes to stacktrace lengths, and movement on that is... slow. |
Just a small suggestion for your consideration: one positive aspect of the first of the two current styles is how it is explicit about which lines are repeated; the style proposed in this PR attempts to capture this information, but I find it a bit more ambiguous, perhaps because of the asymetry between the begin and the end markers of the blocks: julia> foo1(100)
ERROR:
Stacktrace:
[1] error()
@ Base ./error.jl:53
┌┌ [2] foo1(n::Int64)
││ @ Main ./REPL[2]:1
││ [3] foo2(n::Int64)
││ @ Main ./REPL[3]:1
│└───── repeated 9 more times
│┌ [22] foo3(n::Int64)
││ @ Main ./REPL[4]:1
││ [23] foo2(n::Int64)
││ @ Main ./REPL[3]:1
│└───── repeated 9 more times
└────── repeated 1 more time
┌ [82] foo1(n::Int64)
│ @ Main ./REPL[2]:1
│ [83] foo2(n::Int64)
│ @ Main ./REPL[3]:1
└────── repeated 9 more times
[102] foo1(n::Int64)
@ Main ./REPL[2]:1
[103] top-level scope
@ REPL[14]:1 Perhaps adding a block-ending marker in a similar fashion to the starting one could help? julia> foo1(100)
ERROR:
Stacktrace:
[1] error()
@ Base ./error.jl:53
┌┌ [2] foo1(n::Int64)
││ @ Main ./REPL[2]:1
││ [3] foo2(n::Int64)
│├ @ Main ./REPL[3]:1
│╰───── repeated 9 more times
│┌ [22] foo3(n::Int64)
││ @ Main ./REPL[4]:1
││ [23] foo2(n::Int64)
├├ @ Main ./REPL[3]:1
│╰───── repeated 9 more times
╰────── repeated 1 more time
┌ [82] foo1(n::Int64)
│ @ Main ./REPL[2]:1
│ [83] foo2(n::Int64)
├ @ Main ./REPL[3]:1
╰────── repeated 9 more times
[102] foo1(n::Int64)
@ Main ./REPL[2]:1
[103] top-level scope
@ REPL[14]:1 In case this seems too busy, perhaps the block delimiters could be distinguished from the "arrow" pointing to the "repeated x times" line by using a different emphasis, e.g.: julia> foo1(100)
ERROR:
Stacktrace:
[1] error()
@ Base ./error.jl:53
┏┏ [2] foo1(n::Int64)
┃┃ @ Main ./REPL[2]:1
┃┃ [3] foo2(n::Int64)
┃┡ @ Main ./REPL[3]:1
┃╰───── repeated 9 more times
┃┏ [22] foo3(n::Int64)
┃┃ @ Main ./REPL[4]:1
┃┃ [23] foo2(n::Int64)
┡┡ @ Main ./REPL[3]:1
│╰───── repeated 9 more times
╰────── repeated 1 more time
┏ [82] foo1(n::Int64)
┃ @ Main ./REPL[2]:1
┃ [83] foo2(n::Int64)
┡ @ Main ./REPL[3]:1
╰────── repeated 9 more times
[102] foo1(n::Int64)
@ Main ./REPL[2]:1
[103] top-level scope
@ REPL[14]:1 WDYT? |
Yeah I take your point... Could work! |
But While I sympathise, making a special case for just this seems odd to me. |
@waldyrious how do you feel about one of these? Adding the end marker inside complicates things a bit, but maybe the bold region is enough of an indicator? (bold start tick, thin start tick, no start tick) |
Using bold is certainly an improvement over the initial approach! I personally like the third option conceptually the most, because it's symetrical in how it represents the start and the end of the relevant selection, but can understand if others prefer the corner. I do worry that the distinction between bold and thin lines may not be as evident, though. Would using dashed segments for the thin ones be an option? (And maybe curved corners to add to the "softness" aspect 🙂) julia> foo1(100)
ERROR:
Stacktrace:
[1] error()
@ Base ./error.jl:53
┃┃ [2] foo1(n::Int64)
┃┃ @ Main ./REPL[2]:1
┃┃ [3] foo2(n::Int64)
┃┃ @ Main ./REPL[3]:1
┃╰╌╌╌╌╌ repeated 9 more times
┃┃ [22] foo3(n::Int64)
┃┃ @ Main ./REPL[4]:1
┃┃ [23] foo2(n::Int64)
┃┃ @ Main ./REPL[3]:1
┊╰╌╌╌╌╌ repeated 9 more times
╰╌╌╌╌╌╌ repeated 1 more time
┃ [82] foo1(n::Int64)
┃ @ Main ./REPL[2]:1
┃ [83] foo2(n::Int64)
┃ @ Main ./REPL[3]:1
╰╌╌╌╌╌╌ repeated 9 more times
[102] foo1(n::Int64)
@ Main ./REPL[2]:1
[103] top-level scope
@ REPL[14]:1 |
I suppose it's hard to tell, but they are rounded in the screenshots. I'll try some more things out. |
I'm not a fan of the bold stuff. It doesn't look clean and I don't understand the motivation: What else should the reader assume is repeated? Is it that people think the "x times repeated" is repeated too? |
Yeah... I've tried a couple iterations and nothing quite seems to be better enough to justify itself. I will try adding the closing tick though, despite the extra complexity. |
The current stacktrace display pipeline has 2 different ways to show repetition:
And each of these uses two separate printing paths, leading to other inconsistencies, like sometimes top-level scope is shown and sometimes it isn't, and sometimes the frame counter includes the hidden frames and sometimes it doesn't.
I merged the two pathways and display the cycles more nicely using line characters, and extracted some of the filtering into separate functions. I also added a comment to document the stacktrace processing pipeline.
Keeping as a draft to look at CI results and get feedback.