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

REPL calls display_error in obsolete world #19864

Closed
stevengj opened this issue Jan 4, 2017 · 6 comments · Fixed by #19916
Closed

REPL calls display_error in obsolete world #19864

stevengj opened this issue Jan 4, 2017 · 6 comments · Fixed by #19916
Labels
regression Regression in behavior compared to a previous version REPL Julia's REPL (Read Eval Print Loop)

Comments

@stevengj
Copy link
Member

stevengj commented Jan 4, 2017

This was noticed by @omus on the mailing list:

julia> type MyUndefVarError <: Exception
           var::Symbol
       end

julia> Base.showerror(io::IO, e::MyUndefVarError) = print(io, e.var, " not defined");

julia> throw(MyUndefVarError(:foo))  # Should show `ERROR: foo not defined`
ERROR: MyUndefVarError(:foo)

The problem seems to be that the REPL is calling display_error in an obsolete world.

One solution could be for display_error to use eval or invokelatest (#19784) to call showerror, in order to get the latest method.

@stevengj stevengj added regression Regression in behavior compared to a previous version REPL Julia's REPL (Read Eval Print Loop) labels Jan 4, 2017
@vtjnash
Copy link
Member

vtjnash commented Jan 4, 2017

This was quasi-intentional, but I agree that we should change it. However, I think if the attempt to print the error fails, we should try again, but not using the newest world.

@stevengj
Copy link
Member Author

stevengj commented Jan 4, 2017

Why not just always use the newest world when displaying an error? Performance isn't an issue in that context.

Note that the attempt to print the error did not "fail" in the example above, it just succeeded using the default show method.

@mbauman
Copy link
Member

mbauman commented Jan 4, 2017

Here's a case where it fails very badly:

julia> immutable Twos <: AbstractVector{Int}
       end

julia> Base.getindex(::Twos, ::Int) = 2

julia> Base.size(::Twos) = (2,)

julia> [][Twos()]
ERROR: BoundsError: attempt to access 0-element Array{Any,1} at index [
Stacktrace:
 [1] throw_boundserror(::Array{Any,1}, ::Tuple{Twos}) at ./abstractarray.jl:335
 [2] checkbounds at ./abstractarray.jl:292 [inlined]
 [3] _getindex at ./multidimensional.jl:293 [inlined]
 [4] getindex(::Array{Any,1}, ::Twos) at ./abstractarray.jl:785SYSTEM: show(lasterr) caused an error
MethodError(size,(ERROR: MethodError: no method matching size(::Twos)
The applicable method may be too new: running in world age 20474, while current world is 20485.
Closest candidates are:
  size(::Twos) at REPL[3]:1 (method too new to be called from this world context.)
  size{T,N}(::AbstractArray{T,N}, ::Any) at abstractarray.jl:22
  size{N}(::Any, ::Integer, ::Integer, ::Integer...) at abstractarray.jl:23
  ...
Stacktrace:
 [1] array_eltype_show_how(::Twos) at ./show.jl:1700
 [2] show_vector(::IOContext{Base.Terminals.TTYTerminal}, ::Twos, ::String, ::String) at ./show.jl:1704
 [3] #showarray#253(::Bool, ::Function, ::IOContext{Base.Terminals.TTYTerminal}, ::Twos, ::Bool) at ./show.jl:1635
 [4] show_delim_array(::IOContext{Base.Terminals.TTYTerminal}, ::Tuple{Twos}, ::Char, ::Char, ::Char, ::Bool, ::Int64, ::Int64) at ./show.jl:383
 [5] show(::IOContext{Base.Terminals.TTYTerminal}, ::Tuple{Twos}) at ./show.jl:404
 [6] show_default(::Base.Terminals.TTYTerminal, ::Any) at ./show.jl:131
 [7] print(::Base.Terminals.TTYTerminal, ::MethodError) at ./strings/io.jl:18
 [8] print(::Base.Terminals.TTYTerminal, ::MethodError, ::Char, ::Vararg{Char,N}) at ./strings/io.jl:29
 [9] print_response(::Base.Terminals.TTYTerminal, ::Any, ::Array{Ptr{Void},1}, ::Bool, ::Bool, ::Void) at ./REPL.jl:168
 [10] print_response(::Base.REPL.LineEditREPL, ::Any, ::Array{Ptr{Void},1}, ::Bool, ::Bool) at ./REPL.jl:139
 [11] (::Base.REPL.##18#19{Bool,Base.REPL.##29#38{Base.REPL.LineEditREPL,Base.REPL.REPLHistoryProvider},Base.REPL.LineEditREPL,Base.LineEdit.Prompt})(::Base.LineEdit.MIState, ::Base.AbstractIOBuffer{Array{UInt8,1}}, ::Bool) at ./REPL.jl:654
 [12] run_interface(::Base.Terminals.TTYTerminal, ::Base.LineEdit.ModalInterface) at ./LineEdit.jl:1580
 [13] run_interface(::Base.Terminals.TTYTerminal, ::Base.LineEdit.ModalInterface) at /Users/mbauman/Applications/julia-0.6/lib/julia/sys.dylib:?
 [14] run_frontend(::Base.REPL.LineEditREPL, ::Base.REPL.REPLBackendRef) at ./REPL.jl:931
 [15] run_repl(::Base.REPL.LineEditREPL, ::Base.##778#779) at ./REPL.jl:190
 [16] _start() at ./client.jl:406
 [17] _start() at /Users/mbauman/Applications/julia-0.6/lib/julia/sys.dylib:?

[mbauman:~/Code/julia-0.6]
$

@vtjnash
Copy link
Member

vtjnash commented Jan 4, 2017

Why not just always use the newest world when displaying an error? Performance isn't an issue in that context.

Mostly it's just an assumption that if there's a bad function definition that is breaking display_error, it might be possible to recover and at least show something useful by using the old definition of display_error. I agree that default of calling it in the newest world makes sense.

@stevengj
Copy link
Member Author

stevengj commented Jan 4, 2017

We could do

try
    invokelatest(showerror, io, er, bt)
catch
    showerror(io, er, bt) # try old-world showerror if latest one fails
end

in display_error; I guess that is what you are suggesting.

@KristofferC
Copy link
Member

If your error has an exception, why wouldn't you want to know about it?

println(errio, err)
will print something useful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
regression Regression in behavior compared to a previous version REPL Julia's REPL (Read Eval Print Loop)
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants