Help with register_error_hint

Hi, I want to add some useful hints but for some reason I can’t trigger the
callback for a UndefVarError exception.

module Hinter

    only_int(x::Int)      = 1
    any_number(x::Number) = 2

    function __init__()

        empty!(Base.Experimental._hint_handlers)

        # Documentation example
        Base.Experimental.register_error_hint(MethodError) do io, exc, argtypes, kwargs
            if exc.f == only_int
                # Color is not necessary, this is just to show it's possible.
                print(io, "\nDid you mean to call ")
                printstyled(io, "`any_number`?", color=:cyan)
            end
        end

        # Extra hint
        Base.Experimental.register_error_hint(UndefVarError) do io, exc, argtypes, kwargs
            printstyled(io, "\nHi, `UndefVarError`!", color=:cyan)
        end

    end

end

## ----------------------------------------------------------------------------------------
# Documentation exmaple is working
Hinter.only_int(1.0)
#=
ERROR: LoadError: MethodError: no method matching only_int(::Float64)
HINT: Did you mean to call `any_number`?
Closest candidates are:
  only_int(::Int64) at /Users/Pereiro/.julia/dev/DrWatson/dev/dev.jl:34
Stacktrace:
 [1] top-level scope at /Users/Pereiro/.julia/dev/DrWatson/dev/dev.jl:64
 [2] include_string(::Function, ::Module, ::String, ::String) at ./loading.jl:1088
in expression starting at /Users/Pereiro/.julia/dev/DrWatson/dev/dev.jl:64
=#

## ----------------------------------------------------------------------------------------
# My custom custom hint isn't. 
# I hit an UndefVarError, but is failing to hint
Hinter.only_int2(1.0)
#=
ERROR: LoadError: UndefVarError: only_int2 not defined
Stacktrace:
 [1] getproperty(::Module, ::Symbol) at ./Base.jl:26
 [2] top-level scope at /Users/Pereiro/.julia/dev/DrWatson/dev/dev.jl:69
 [3] include_string(::Function, ::Module, ::String, ::String) at ./loading.jl:1088
in expression starting at /Users/Pereiro/.julia/dev/DrWatson/dev/dev.jl:69
=#

## ----------------------------------------------------------------------------------------
# The dictionary is populated 
Base.Experimental._hint_handlers
#=
IdDict{Type,Array{Any,1}} with 2 entries:
  MethodError   => Any[#1]
  UndefVarError => Any[#2]
=#

## ----------------------------------------------------------------------------------------
# I can call my function
Base.Experimental._hint_handlers[UndefVarError][1](stdout, :bla, :bla, :bla)
#=
Hi, `UndefVarError`!
=#

Any thought what am i missing?
Thank

This is just a guess, but it can be related to the fact your UndefVarError is being wrapped in a LoadError, so you had to add a hint to a LoadError that only happens if it wraps a UndefVarError.

I already had problems with this behavior (LoadError wrapping) when I was designing a timeout system (basically, in a series of runs for a scientific experiment, I wanted to throw TimeoutExceptions when runs passed the time limit, but this should be captured and not stop the process because some timeouts are expected). I think the wrapping happens if the exception is thrown inside a macro or something like that (there are some cases). I recommend searching for more info on LoadError.

Hi, thank for the quick reply. I actually already tried that but I did not included in the MWE.

I actually put all in a try statement, check the type of the error and rethrow it and nothing.

# checking err type
try
    Hinter.only_int2(1.0)
catch err
    @show typeof(err)
    rethrow(err)
end
#=
typeof(err) = UndefVarError
ERROR: LoadError: UndefVarError: only_int2 not defined
# No hint
Stacktrace:
 [1] getproperty(::Module, ::Symbol) at ./Base.jl:26
 [2] top-level scope at /Users/Pereiro/.julia/dev/DrWatson/dev/dev.jl:113
 [3] include_string(::Function, ::Module, ::String, ::String) at ./loading.jl:1088
in expression starting at /Users/Pereiro/.julia/dev/DrWatson/dev/dev.jl:112
=#

This is because showerror for UndefVarError does not currently call back into show_error_hints. It is still an experimental feature, so it isn’t implemented consistently by all exceptions yet. I actually did implement this as part of RFC: allow ** as unary and binary operator by simeonschaub · Pull Request #39089 · JuliaLang/julia · GitHub, so if you want to make a PR, it should be quite straightforward to extract that part.

4 Likes

Hi thanks, I made the pull request #39850

2 Likes

This was merged in v1.6! Urra!

1 Like