Skip to content

Commit 3c131bf

Browse files
committed
In errorshow UI, filter out frames for _include implementation
This simplifies stack traces for include() which were made much more complex by moving jl_parse_eval_all to the Julia layer.
1 parent f60aefe commit 3c131bf

File tree

4 files changed

+64
-11
lines changed

4 files changed

+64
-11
lines changed

base/errorshow.jl

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -681,6 +681,41 @@ function is_kw_sorter_name(name::Symbol)
681681
return !startswith(sn, '#') && endswith(sn, "##kw")
682682
end
683683

684+
# For improved user experience, filter out frames for include() implementation
685+
# - see #33065. See also #35371 for extended discussion of internal frames.
686+
function _simplify_include_frames(trace)
687+
i = length(trace)
688+
kept_frames = trues(i)
689+
first_ignored = nothing
690+
while i >= 1
691+
frame, _ = trace[i]
692+
mod = parentmodule(frame)
693+
if isnothing(first_ignored)
694+
if mod === Base && frame.func === :_include
695+
# Hide include() machinery by default
696+
first_ignored = i
697+
end
698+
else
699+
# Hack: allow `mod==nothing` as a workaround for inlined functions.
700+
# TODO: Fix this by improving debug info.
701+
if mod in (Base,Core,nothing) && 1+first_ignored-i <= 5
702+
if frame.func == :eval
703+
kept_frames[i:first_ignored] .= false
704+
first_ignored = nothing
705+
end
706+
else
707+
# Bail out to avoid hiding frames in unexpected circumstances
708+
first_ignored = nothing
709+
end
710+
end
711+
i -= 1
712+
end
713+
if !isnothing(first_ignored)
714+
kept_frames[i:first_ignored] .= false
715+
end
716+
return trace[kept_frames]
717+
end
718+
684719
function process_backtrace(t::Vector, limit::Int=typemax(Int); skipC = true)
685720
n = 0
686721
last_frame = StackTraces.UNKNOWN
@@ -721,7 +756,7 @@ function process_backtrace(t::Vector, limit::Int=typemax(Int); skipC = true)
721756
if n > 0
722757
push!(ret, (last_frame, n))
723758
end
724-
return ret
759+
return _simplify_include_frames(ret)
725760
end
726761

727762
function show_exception_stack(io::IO, stack::Vector)

base/stacktraces.jl

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -268,22 +268,28 @@ function show(io::IO, frame::StackFrame; full_path::Bool=false)
268268
end
269269
end
270270

271+
function Base.parentmodule(frame::StackFrame)
272+
if frame.linfo isa MethodInstance
273+
def = frame.linfo.def
274+
if def isa Module
275+
return def
276+
else
277+
return (def::Method).module
278+
end
279+
else
280+
# The module is not always available (common reasons include inlined
281+
# frames and frames arising from the interpreter)
282+
nothing
283+
end
284+
end
285+
271286
"""
272287
from(frame::StackFrame, filter_mod::Module) -> Bool
273288
274289
Returns whether the `frame` is from the provided `Module`
275290
"""
276291
function from(frame::StackFrame, m::Module)
277-
finfo = frame.linfo
278-
result = false
279-
280-
if finfo isa MethodInstance
281-
frame_m = finfo.def
282-
isa(frame_m, Method) && (frame_m = frame_m.module)
283-
result = nameof(frame_m) === nameof(m)
284-
end
285-
286-
return result
292+
return parentmodule(frame) === m
287293
end
288294

289295
end

test/errorshow.jl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,3 +704,14 @@ for (func,str) in ((TestMethodShadow.:+,":+"), (TestMethodShadow.:(==),":(==)"),
704704
end::MethodError
705705
@test occursin("You may have intended to import Base.$str", sprint(Base.showerror, ex))
706706
end
707+
708+
# Test that implementation detail of include() is hidden from the user by default
709+
let bt = try
710+
include("testhelpers/include_error.jl")
711+
catch
712+
catch_backtrace()
713+
end
714+
bt_str = sprint(Base.show_backtrace, bt)
715+
@test occursin(" include(", bt_str)
716+
@test !occursin(" _include(", bt_str)
717+
end

test/testhelpers/include_error.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
error("Expected exception while running include")

0 commit comments

Comments
 (0)