From 90b4eedbf4b2beae0b12e6b8317e15ef0bb91126 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Wed, 16 Aug 2023 06:36:38 -0400 Subject: [PATCH] Limit type-printing in MethodError (#50809) This applies the same `...` depth-based parametric truncation to the signature in `MethodError` that we use in printing stacktraces. Fixes #50803 --- base/client.jl | 4 ++-- base/errorshow.jl | 20 ++++++++++++-------- base/show.jl | 11 ++++++++--- test/errorshow.jl | 19 +++++++++++++++++++ 4 files changed, 41 insertions(+), 13 deletions(-) diff --git a/base/client.jl b/base/client.jl index 4ae345b14f113..247c102894688 100644 --- a/base/client.jl +++ b/base/client.jl @@ -103,8 +103,8 @@ scrub_repl_backtrace(stack::ExceptionStack) = ExceptionStack(Any[(;x.exception, backtrace = scrub_repl_backtrace(x.backtrace)) for x in stack]) istrivialerror(stack::ExceptionStack) = - length(stack) == 1 && length(stack[1].backtrace) ≤ 1 - # frame 1 = top level; assumes already went through scrub_repl_backtrace + length(stack) == 1 && length(stack[1].backtrace) ≤ 1 && !isa(stack[1].exception, MethodError) + # frame 1 = top level; assumes already went through scrub_repl_backtrace; MethodError see #50803 function display_error(io::IO, stack::ExceptionStack) printstyled(io, "ERROR: "; bold=true, color=Base.error_color()) diff --git a/base/errorshow.jl b/base/errorshow.jl index aee1f6b6fdf32..8f54fc94a5f84 100644 --- a/base/errorshow.jl +++ b/base/errorshow.jl @@ -268,20 +268,24 @@ function showerror(io::IO, ex::MethodError) f_is_function = true end print(io, "no method matching ") - show_signature_function(io, isa(f, Type) ? Type{f} : typeof(f)) - print(io, "(") + iob = IOContext(IOBuffer(), io) # for type abbreviation as in #49795; some, like `convert(T, x)`, should not abbreviate + show_signature_function(iob, isa(f, Type) ? Type{f} : typeof(f)) + print(iob, "(") for (i, typ) in enumerate(arg_types_param) - print(io, "::", typ) - i == length(arg_types_param) || print(io, ", ") + print(iob, "::", typ) + i == length(arg_types_param) || print(iob, ", ") end if !isempty(kwargs) - print(io, "; ") + print(iob, "; ") for (i, (k, v)) in enumerate(kwargs) - print(io, k, "::", typeof(v)) - i == length(kwargs)::Int || print(io, ", ") + print(iob, k, "::", typeof(v)) + i == length(kwargs)::Int || print(iob, ", ") end end - print(io, ")") + print(iob, ")") + str = String(take!(unwrapcontext(iob)[1])) + str = type_limited_string_from_context(io, str) + print(io, str) end # catch the two common cases of element-wise addition and subtraction if (f === Base.:+ || f === Base.:-) && length(arg_types_param) == 2 diff --git a/base/show.jl b/base/show.jl index 5a9d3f43964cc..3c42648e23457 100644 --- a/base/show.jl +++ b/base/show.jl @@ -2559,17 +2559,22 @@ function show_tuple_as_call(out::IO, name::Symbol, sig::Type; print_within_stacktrace(io, ")", bold=true) show_method_params(io, tv) str = String(take!(unwrapcontext(io)[1])) + str = type_limited_string_from_context(out, str) + print(out, str) + nothing +end + +function type_limited_string_from_context(out::IO, str::String) typelimitflag = get(out, :stacktrace_types_limited, nothing) if typelimitflag isa RefValue{Bool} - sz = get(out, :displaysize, (typemax(Int), typemax(Int)))::Tuple{Int, Int} + sz = get(out, :displaysize, displaysize(out))::Tuple{Int, Int} str_lim = type_depth_limit(str, max(sz[2], 120)) if sizeof(str_lim) < sizeof(str) typelimitflag[] = true end str = str_lim end - print(out, str) - nothing + return str end # limit nesting depth of `{ }` until string textwidth is less than `n` diff --git a/test/errorshow.jl b/test/errorshow.jl index 3c0daa2b480a7..1210fd7abcbd3 100644 --- a/test/errorshow.jl +++ b/test/errorshow.jl @@ -549,6 +549,25 @@ foo_9965(x::Int) = 2x @test occursin("got unsupported keyword argument \"w\"", String(take!(io))) end +@testset "MethodError with long types (#50803)" begin + a = view(reinterpret(reshape, UInt8, PermutedDimsArray(rand(5, 7), (2, 1))), 2:3, 2:4, 1:4) # a mildly-complex type + function f50803 end + ex50803 = try + f50803(a, a, a, a, a, a) + catch e + e + end::MethodError + tlf = Ref(false) + str = sprint(Base.showerror, ex50803; context=(:displaysize=>(1000, 120), :stacktrace_types_limited=>tlf)) + @test tlf[] + @test occursin("::SubArray{…}", str) + tlf[] = false + str = sprint(Base.showerror, ex50803; context=(:displaysize=>(1000, 10000), :stacktrace_types_limited=>tlf)) + @test !tlf[] + str = sprint(Base.showerror, ex50803; context=(:displaysize=>(1000, 120))) + @test !occursin("::SubArray{…}", str) +end + # Issue #20556 import REPL module EnclosingModule