These stack traces are out of control

As per my edit, the solution is to check a flag in the relevant show method. A lot of digging later (and also my first time using Debugger.jl, which was awesome, by the way), I found out this can be done by modifying this line in Base.

It’s quite a long function so I’m hiding it, but the diff between this and Base is 3 lines (and could technically be just one).

Summary
@eval Base function show_tuple_as_call(io::IO, name::Symbol, sig::Type, demangle=false, kwargs=nothing)
    # print a method signature tuple for a lambda definition
    in_backtrace = get(io, :backtrace, false)
    color = get(io, :color, false) && in_backtrace ? stackframe_function_color() : :nothing
    if sig === Tuple
        printstyled(io, demangle ? demangle_function_name(name) : name, "(...)", color=color)
        return
    end
    tv = Any[]
    env_io = io
    while isa(sig, UnionAll)
        push!(tv, sig.var)
        env_io = IOContext(env_io, :unionall_env => sig.var)
        sig = sig.body
    end
    sig = sig.parameters
    with_output_color(color, env_io) do io
        ft = sig[1]
        uw = unwrap_unionall(ft)
        if ft <: Function && isa(uw, DataType) && isempty(uw.parameters) &&
                isdefined(uw.name.module, uw.name.mt.name) &&
                ft == typeof(getfield(uw.name.module, uw.name.mt.name))
            print(io, (demangle ? demangle_function_name : identity)(uw.name.mt.name))
        elseif isa(ft, DataType) && ft.name === Type.body.name && !Core.Compiler.has_free_typevars(ft)
            f = ft.parameters[1]
            print(io, f)
        else
            print(io, "(::", ft, ")")
        end
    end
    first = true
    
    print_style = get(io, :color, false) && in_backtrace ? :bold : :nothing
    printstyled(io, "(", color=print_style)
    for i = 2:length(sig)  # fixme (iter): `eachindex` with offset?
        first || print(io, ", ")
        first = false
        print(env_io, "::", in_backtrace ? typename(sig[i]) : sig[i])
    end
    if kwargs !== nothing
        print(io, "; ")
        first = true
        for (k, t) in kwargs
            first || print(io, ", ")
            first = false
            print(io, k, "::")
            show(io, t)
        end
    end
    printstyled(io, ")", color=print_style)
    show_method_params(io, tv)
    nothing
end

For the effect, see:

## Create a contrived stacktrace to see the effect
## and a similar method for h so we get "Closest candidates"
julia> begin 
           f(x) = g(x, x, x)
           g(x, y, z) = h(x, y, z)
           h(x::Complicated{Float64}, y::Complicated{Float64}) = "anything"
       end

julia> struct Complicated{a,b,c,d} end

julia> C = Complicated{ntuple(i->Float64, 4)...}()
Complicated{Float64,Float64,Float64,Float64}()

julia> f(C)
ERROR: MethodError: no method matching h(::Complicated{Float64,Float64,Float64,Float64}, ::Complicated{Float64,Float64,Float64,Float64}, ::Complicated{Float64,Float64,Float64,Float64})
Closest candidates are:
  h(::Complicated{Float64,b,c,d} where d where c where b, ::Complicated{Float64,b,c,d} where d where c where b) at REPL[16]:1
Stacktrace:
 [1] g(::Complicated, ::Complicated, ::Complicated) at ./REPL[16]:1
 [2] f(::Complicated) at ./REPL[16]:1
 [3] top-level scope at REPL[19]:1

We get the full method signature in the method error itself and in the closest candidates (which we may need to know to disambiguate the error), but the type name in the stacktrace is always shortened. It’s still worth considering I think whether this is behavior that should be enabled by default, or whether only certain “complicated” types should feature this, i.e. if this is opt-in by the struct creator.

1 Like