Skip to content
Merged
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
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "Compat"
uuid = "34da2185-b29b-5c13-b0c7-acf172513d20"
version = "3.33.0"
version = "3.34.0"

[deps]
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ changes in `julia`.

## Supported features

* The function `current_exceptions()` has been added to get the current
exception stack. Julia-1.0 lacks runtime support for full execption stacks,
so we return only the most recent exception in that case. ([#29901]) (since
Compat 3.34)

* The methods `Base.include(::Function, ::Module, path)` and
`Base.include_string(::Function, ::Module, code[, filename])` have been added. ([#34595]) (since Compat 3.33)

Expand Down
53 changes: 53 additions & 0 deletions src/Compat.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1049,6 +1049,59 @@ if VERSION < v"1.5.0-DEV.263"
end
end

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

if VERSION >= v"1.1"
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
else
# There's no exception stack in 1.0, but we can fall back to returning
# the (single) current exception and backtrace instead.
@eval function current_exceptions(task=current_task(); backtrace=true)
bt = catch_backtrace()
# `exc = Expr(:the_exception)` is the lowering for `catch exc`
exc = isempty(bt) ? nothing : $(Expr(:the_exception))
ExceptionStack(isempty(bt) ? Any[] : Any[(exception=exc, backtrace=bt)])
end
@eval function the_stack()
$(Expr(:the_exception)), catch_backtrace()
end
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
35 changes: 35 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1109,3 +1109,38 @@ end
@test m.y === 3
@test !isdefined(m, :x)
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

if VERSION >= v"1.1"
@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))
else
# Due to runtime limitations, julia-1.0 only retains the last exception
@test typeof.(first.(excs)) == [DivideError]
@test occursin(r"""
1-element ExceptionStack:
DivideError: integer division error
Stacktrace:.*
""", sprint(show, excs))
end
end