Skip to content

Commit

Permalink
Port Base.current_exceptions() to older Julia versions
Browse files Browse the repository at this point in the history
See JuliaLang/julia#29901

This is limited to julia-1.1 and above because earlier versions don'
have the necessary runtime library support (Base.catch_stack() etc).
  • Loading branch information
c42f committed Jun 26, 2021
1 parent 78bba10 commit 502e994
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 0 deletions.
39 changes: 39 additions & 0 deletions src/Compat.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1032,6 +1032,45 @@ if VERSION < v"1.7.0-DEV.1230"
get(f::Callable, x::Number, ind::Tuple) = all(isone, ind) ? x : f()
end

# https://github.com/JuliaLang/julia/pull/29901
if VERSION >= v"1.1" && VERSION < v"1.7.0-DEV.1106"
struct ExceptionStack <: AbstractArray{Any,1}
stack
end

function current_exceptions(task=current_task(); backtrace=true)
stack = Base.catch_stack(task, include_bt=backtrace)
ExceptionStack(Any[(exception=x[1],backtrace=x[2]) for x in stack])
end

Base.size(s::ExceptionStack) = size(s.stack)
Base.getindex(s::ExceptionStack, i::Int) = s.stack[i]

function show_exception_stack(io::IO, stack)
# Display exception stack with the top of the stack first. This ordering
# means that the user doesn't have to scroll up in the REPL to discover the
# root cause.
nexc = length(stack)
for i = nexc:-1:1
if nexc != i
printstyled(io, "\ncaused by: ", color=Base.error_color())
end
exc, bt = stack[i]
showerror(io, exc, bt, backtrace = bt!==nothing)
i == 1 || println(io)
end
end

function Base.show(io::IO, ::MIME"text/plain", stack::ExceptionStack)
nexc = length(stack)
printstyled(io, nexc, "-element ExceptionStack", nexc == 0 ? "" : ":\n")
show_exception_stack(io, stack)
end
Base.show(io::IO, stack::ExceptionStack) = show(io, MIME("text/plain"), stack)

export current_exceptions
end

include("iterators.jl")
include("deprecated.jl")

Expand Down
25 changes: 25 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1067,3 +1067,28 @@ end
@test get(() -> c[]+=1, x, (3,2,1)) == 3
end
end

# https://github.com/JuliaLang/julia/pull/29901
@testset "current_exceptions" begin
# Display of errors which cause more than one entry on the exception stack
excs = try
try
__not_a_binding__
catch
1 ÷ 0 # Generate error while handling error
end
catch
current_exceptions()
end

@test typeof.(first.(excs)) == [UndefVarError, DivideError]

@test occursin(r"""
2-element ExceptionStack:
DivideError: integer division error
Stacktrace:.*
caused by: UndefVarError: __not_a_binding__ not defined
Stacktrace:.*
"""s, sprint(show, excs))
end

0 comments on commit 502e994

Please sign in to comment.