Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 24 additions & 17 deletions src/exception_summary.jl
Original file line number Diff line number Diff line change
Expand Up @@ -156,29 +156,36 @@ function _summarize_exception(io::IO, exc, stack, show_fn; prefix = nothing)

println(io)

# Print the source line number of the where the exception occurred.
# In order to save performance, only process the backtrace up until the first printable
# frame. (Julia skips frames from the C runtime when printing backtraces.)
# A report was received about an error where bt was not defined. Band-aid by
# initializing it as an empty vector. It's not understood why there was no backtrace.
bt = []
for i in eachindex(stack)
bt = Base.process_backtrace(stack[i:i])
if !isempty(bt)
# Find the first Julia (non-C) frame lazily, one frame at a time, for performance.
# Calling stacktrace() on the full backtrace symbolizes every frame at once, which
# can be very expensive for large stacktraces. Instead, we use StackTraces.lookup()
# on each element individually — it accepts both Ptr{Nothing} and
# Base.InterpreterIP (the element types used across Julia versions including nightly).
frame = nothing
for ptr in stack
looked_up = Base.StackTraces.lookup(ptr)
if !isempty(looked_up) && !looked_up[1].from_c
frame = looked_up[1]
break
end
end
# Now print just the very first frame we've collected:
if isempty(bt)
if frame === nothing
# A report was received about bt being a 0-element Vector. It's not clear why the
# stacktrace is missing, but this should tide us over in the meantime.
_indent_println(io, "no stacktrace available")
else
(frame, n) = bt[1]
# borrowed from julia/base/errorshow.jl
modulecolordict = copy(Base.STACKTRACE_FIXEDCOLORS)
modulecolorcycler = Iterators.Stateful(Iterators.cycle(Base.STACKTRACE_MODULECOLORS))
Base.print_stackframe(io, 1, frame, n, indent+1, modulecolordict, modulecolorcycler)
println(io)
# sprint(show, frame) gives "func(args) at file:line" -- extract just the signature.
# We avoid calling Base.print_stackframe directly since its signature is unstable
# across Julia versions.
func_sig = first(split(sprint(show, frame), " at "; limit=2))
mod_name = try
linfo = frame.linfo
linfo isa Core.MethodInstance ?
string(linfo.def isa Method ? linfo.def.module : linfo.def) : "Main"
catch
"Main"
end
_indent_println(io, " [1] " * func_sig)
_indent_println(io, " @ " * mod_name * " " * string(frame.file) * ":" * string(frame.line))
end
end
8 changes: 7 additions & 1 deletion src/test_throws_wrapped.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,20 @@ Test Passed
"""
macro test_throws_wrapped(extype, ex)
orig_ex = Expr(:inert, ex)
# current_exceptions() was added in Julia 1.7; Threw requires it on nightly.
threw_call = if VERSION >= v"1.7.0-"
:(Threw(_e, current_exceptions(), $(QuoteNode(__source__))))
else
:(Threw(_e, nothing, $(QuoteNode(__source__))))
end
result = quote
try
Returned($(esc(ex)), nothing, $(QuoteNode(__source__)))
catch _e
if $(esc(extype)) != InterruptException && _e isa InterruptException
rethrow()
end
Threw(_e, nothing, $(QuoteNode(__source__)))
$threw_call
end
end
Base.remove_linenums!(result)
Expand Down
Loading