Skip to content
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

Try make REPL error easier to visually parse #19569

Merged
merged 7 commits into from
Dec 29, 2016
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
14 changes: 7 additions & 7 deletions base/REPL.jl
Original file line number Diff line number Diff line change
Expand Up @@ -112,14 +112,12 @@ end

function display_error(io::IO, er, bt)
print_with_color(Base.error_color(), io, "ERROR: "; bold = true)
Base.with_output_color(Base.error_color(), io) do io
# remove REPL-related frames from interactive printing
eval_ind = findlast(addr->ip_matches_func(addr, :eval), bt)
if eval_ind != 0
bt = bt[1:eval_ind-1]
end
Base.showerror(IOContext(io, :limit => true), er, bt)
# remove REPL-related frames from interactive printing
eval_ind = findlast(addr->Base.REPL.ip_matches_func(addr, :eval), bt)
if eval_ind != 0
bt = bt[1:eval_ind-1]
end
showerror(IOContext(io, :limit => true), er, bt)
end

immutable REPLDisplay{R<:AbstractREPL} <: Display
Expand Down Expand Up @@ -167,6 +165,8 @@ function print_response(errio::IO, val::ANY, bt, show_value::Bool, have_color::B
catch err
if bt !== nothing
println(errio, "SYSTEM: show(lasterr) caused an error")
println(errio, err)
Base.show_backtrace(errio, bt)
break
end
val = err
Expand Down
3 changes: 2 additions & 1 deletion base/array.jl
Original file line number Diff line number Diff line change
Expand Up @@ -737,7 +737,8 @@ julia> deleteat!([6, 5, 4, 3, 2, 1], 1:2:5)

julia> deleteat!([6, 5, 4, 3, 2, 1], (2, 2))
ERROR: ArgumentError: indices must be unique and sorted
in deleteat!(::Array{Int64,1}, ::Tuple{Int64,Int64}) at ./array.jl:753
Stacktrace:
[1] deleteat!(::Array{Int64,1}, ::Tuple{Int64,Int64}) at ./array.jl:748
```
"""
function deleteat!(a::Vector, inds)
Expand Down
13 changes: 9 additions & 4 deletions base/client.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,19 @@ const text_colors = AnyDict(
:normal => "\033[0m",
:default => "\033[39m",
:bold => "\033[1m",
:nothing => "",
)

for i in 0:255
text_colors[i] = "\033[38;5;$(i)m"
end

const disable_text_style = AnyDict(
:bold => "\033[22m",
:normal => "",
:default => "",
)

for i in 0:255
text_colors[i] = "\033[38;5;$(i)m"
end

# Create a docstring with an automatically generated list
# of colors.
available_text_colors = collect(Iterators.filter(x -> !isa(x, Integer), keys(text_colors)))
Expand All @@ -52,6 +53,7 @@ Available colors are: $available_text_colors_docstring as well as the integers 0

The color `:default` will print text in the default color while the color `:normal`
will print text with all text properties (like boldness) reset.
Printing with the color `:nothing` will print the string without modifications.
"""
text_colors

Expand Down Expand Up @@ -83,6 +85,9 @@ info_color() = repl_color("JULIA_INFO_COLOR" , default_color_info)
input_color() = text_colors[:bold] * text_colors[repl_color("JULIA_INPUT_COLOR", default_color_input)]
answer_color() = text_colors[:bold] * text_colors[repl_color("JULIA_ANSWER_COLOR", default_color_answer)]

stackframe_lineinfo_color() = repl_color("JULIA_STACKFRAME_LINEINFO_COLOR", :bold)
stackframe_function_color() = repl_color("JULIA_STACKFRAME_FUNCTION_COLOR", :bold)

function repl_cmd(cmd, out)
shell = shell_split(get(ENV,"JULIA_SHELL",get(ENV,"SHELL","/bin/sh")))
# Note that we can't support the fish shell due to its lack of subshells
Expand Down
6 changes: 4 additions & 2 deletions base/docs/helpdb/Base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,8 @@ If `T` is not a bitstype, an error is thrown.
```jldoctest
julia> sizeof(Base.LinAlg.LU)
ERROR: argument is an abstract type; size is indeterminate
in sizeof(::Type{T}) at ./essentials.jl:99
Stacktrace:
[1] sizeof(::Type{T}) at ./essentials.jl:99
```
"""
sizeof(::Type)
Expand Down Expand Up @@ -2531,7 +2532,8 @@ julia> convert(Int, 3.0)

julia> convert(Int, 3.5)
ERROR: InexactError()
in convert(::Type{Int64}, ::Float64) at ./float.jl:656
Stacktrace:
[1] convert(::Type{Int64}, ::Float64) at ./float.jl:656
```

If `T` is a `AbstractFloat` or `Rational` type,
Expand Down
10 changes: 6 additions & 4 deletions base/linalg/eigen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,9 @@ julia> A = [0 im; -1 0]

julia> eigmax(A)
ERROR: DomainError:
in #eigmax#36(::Bool, ::Bool, ::Function, ::Array{Complex{Int64},2}) at ./linalg/eigen.jl:218
in eigmax(::Array{Complex{Int64},2}) at ./linalg/eigen.jl:216
Stacktrace:
[1] #eigmax#30(::Bool, ::Bool, ::Function, ::Array{Complex{Int64},2}) at ./linalg/eigen.jl:219
[2] eigmax(::Array{Complex{Int64},2}) at ./linalg/eigen.jl:217
```
"""
function eigmax(A::Union{Number, StridedMatrix}; permute::Bool=true, scale::Bool=true)
Expand Down Expand Up @@ -249,8 +250,9 @@ julia> A = [0 im; -1 0]

julia> eigmin(A)
ERROR: DomainError:
in #eigmin#37(::Bool, ::Bool, ::Function, ::Array{Complex{Int64},2}) at ./linalg/eigen.jl:259
in eigmin(::Array{Complex{Int64},2}) at ./linalg/eigen.jl:257
Stacktrace:
[1] #eigmin#31(::Bool, ::Bool, ::Function, ::Array{Complex{Int64},2}) at ./linalg/eigen.jl:261
[2] eigmin(::Array{Complex{Int64},2}) at ./linalg/eigen.jl:259
```
"""
function eigmin(A::Union{Number, StridedMatrix}; permute::Bool=true, scale::Bool=true)
Expand Down
3 changes: 2 additions & 1 deletion base/nullable.jl
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@ Nullable{String}()

julia> unsafe_get(x)
ERROR: UndefRefError: access to undefined reference
in unsafe_get(::Nullable{String}) at ./nullable.jl:123
Stacktrace:
[1] unsafe_get(::Nullable{String}) at ./nullable.jl:124

julia> x = 1
1
Expand Down
18 changes: 13 additions & 5 deletions base/replutil.jl
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,9 @@ end

function showerror(io::IO, ex, bt; backtrace=true)
try
showerror(io, ex)
with_output_color(have_color ? error_color() : :nothing, io) do io
showerror(io, ex)
end
finally
backtrace && show_backtrace(io, bt)
end
Expand Down Expand Up @@ -577,15 +579,21 @@ function show_method_candidates(io::IO, ex::MethodError, kwargs::Vector=Any[])
end
end

function show_trace_entry(io, frame, n)
function show_trace_entry(io, frame, n; prefix = " in ")
print(io, "\n")
show(io, frame, full_path=true)
show(io, frame, full_path=true; prefix = prefix)
n > 1 && print(io, " (repeats ", n, " times)")
end

function show_backtrace(io::IO, t::Vector)
process_entry(last_frame, n) =
show_trace_entry(io, last_frame, n)
n_frames = 0
frame_counter = 0
process_backtrace((a,b) -> n_frames += 1, t)
n_frames != 0 && print(io, "\nStacktrace:")
process_entry = (last_frame, n) -> begin
frame_counter += 1
show_trace_entry(io, last_frame, n, prefix = string(" [", frame_counter, "] "))
end
process_backtrace(process_entry, t)
end

Expand Down
42 changes: 24 additions & 18 deletions base/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1031,31 +1031,37 @@ end

function show_lambda_types(io::IO, li::Core.MethodInstance)
# print a method signature tuple for a lambda definition
if li.specTypes === Tuple
print(io, li.def.name, "(...)")
return
end

sig = li.specTypes.parameters
ft = sig[1]
if ft <: Function && isempty(ft.parameters) &&
isdefined(ft.name.module, ft.name.mt.name) &&
ft == typeof(getfield(ft.name.module, ft.name.mt.name))
print(io, ft.name.mt.name)
elseif isa(ft, DataType) && ft.name === Type.name && isleaftype(ft)
f = ft.parameters[1]
print(io, f)
else
print(io, "(::", ft, ")")
local sig
returned_from_do = false
Base.with_output_color(have_color ? stackframe_function_color() : :nothing, io) do io
if li.specTypes === Tuple
print(io, li.def.name, "(...)")
returned_from_do = true
return
end
sig = li.specTypes.parameters
ft = sig[1]
if ft <: Function && isempty(ft.parameters) &&
isdefined(ft.name.module, ft.name.mt.name) &&
ft == typeof(getfield(ft.name.module, ft.name.mt.name))
print(io, ft.name.mt.name)
elseif isa(ft, DataType) && ft.name === Type.name && isleaftype(ft)
f = ft.parameters[1]
print(io, f)
else
print(io, "(::", ft, ")")
end
end
returned_from_do && return
first = true
print(io, '(')
print_style = have_color ? :bold : :nothing
print_with_color(print_style, io, "(")
for i = 2:length(sig) # fixme (iter): `eachindex` with offset?
first || print(io, ", ")
first = false
print(io, "::", sig[i])
end
print(io, ')')
print_with_color(print_style, io, ")")
nothing
end

Expand Down
20 changes: 12 additions & 8 deletions base/stacktraces.jl
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ function show_spec_linfo(io::IO, frame::StackFrame)
if frame.func === empty_sym
@printf(io, "ip:%#x", frame.pointer)
else
print(io, frame.func)
print_with_color(Base.have_color ? Base.stackframe_function_color() : :nothing, io, string(frame.func))
end
else
linfo = get(frame.linfo)
Expand All @@ -200,16 +200,20 @@ function show_spec_linfo(io::IO, frame::StackFrame)
end
end

function show(io::IO, frame::StackFrame; full_path::Bool=false)
print(io, " in ")
function show(io::IO, frame::StackFrame; full_path::Bool=false,
prefix = " in ")
print(io, prefix)
show_spec_linfo(io, frame)
if frame.file !== empty_sym
file_info = full_path ? string(frame.file) : basename(string(frame.file))
print(io, " at ", file_info, ":")
if frame.line >= 0
print(io, frame.line)
else
print(io, "?")
print(io, " at ")
Base.with_output_color(Base.have_color ? Base.stackframe_lineinfo_color() : :nothing, io) do io
print(io, file_info, ":")
if frame.line >= 0
print(io, frame.line)
else
print(io, "?")
end
end
end
if frame.inlined
Expand Down
3 changes: 2 additions & 1 deletion base/test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -972,7 +972,8 @@ Body:

julia> @inferred f(1,2,3)
ERROR: return type Int64 does not match inferred return type Union{Float64,Int64}
in error(::String) at ./error.jl:21
Stacktrace:
[1] error(::String) at ./error.jl:21

julia> @inferred max(1,2)
2
Expand Down
2 changes: 1 addition & 1 deletion base/util.jl
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ function with_output_color(f::Function, color::Union{Int, Symbol}, io::IO, args.
have_color && print(buf, get(text_colors, color, color_normal))
try f(IOContext(buf, io), args...)
finally
have_color && print(buf, get(disable_text_style, color, text_colors[:default]))
have_color && color != :nothing && print(buf, get(disable_text_style, color, text_colors[:default]))
have_color && (bold || color == :bold) && print(buf, disable_text_style[:bold])
print(io, String(take!(buf)))
end
Expand Down
6 changes: 3 additions & 3 deletions test/cmdlineargs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -366,12 +366,12 @@ end
for precomp in ("yes", "no")
bt = readstring(pipeline(ignorestatus(`$(Base.julia_cmd()) --startup-file=no --precompiled=$precomp
-E 'include("____nonexistent_file")'`), stderr=catcmd))
@test contains(bt, "in include_from_node1")
@test contains(bt, "include_from_node1")
if is_windows() && Sys.WORD_SIZE == 32 && precomp == "yes"
# fixme, issue #17251
@test_broken contains(bt, "in include_from_node1(::String) at $(joinpath(".","loading.jl"))")
@test_broken contains(bt, "include_from_node1(::String) at $(joinpath(".","loading.jl"))")
else
@test contains(bt, "in include_from_node1(::String) at $(joinpath(".","loading.jl"))")
@test contains(bt, "include_from_node1(::String) at $(joinpath(".","loading.jl"))")
end
lno = match(r"at \.[\/\\]loading\.jl:(\d+)", bt)
@test length(lno.captures) == 1
Expand Down
4 changes: 2 additions & 2 deletions test/compile.jl
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ try
end
""")

t = redirected_stderr("ERROR: LoadError: Declaring __precompile__(false) is not allowed in files that are being precompiled.\n in __precompile__")
t = redirected_stderr("ERROR: LoadError: Declaring __precompile__(false) is not allowed in files that are being precompiled.\nStacktrace:\n [1] __precompile__")
try
Base.compilecache("Baz") # from __precompile__(false)
error("__precompile__ disabled test failed")
Expand Down Expand Up @@ -314,7 +314,7 @@ try
error("break me")
end
""")
t = redirected_stderr("ERROR: LoadError: break me\n in error")
t = redirected_stderr("ERROR: LoadError: break me\nStacktrace:\n [1] error")
try
Base.require(:FooBar)
error("\"LoadError: break me\" test failed")
Expand Down