From 75c4eff8b3dcf30d1ed579bdb5c8cc7de93bcdd0 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 30 Oct 2023 20:42:22 +0000 Subject: [PATCH] combine reduce_empty methods for Union{} eltypes With #49470, these can all be dispatched to the same method now, avoiding unnecessary code duplication for this case. This partly reverts f2dcc44d20082d9e5a06c6abd6345c65b64984fb, but our edges against methods should be better than the ones against MethodError these days. --- base/errorshow.jl | 7 ++----- base/reduce.jl | 17 +++++++---------- test/reduce.jl | 12 +++++------- 3 files changed, 14 insertions(+), 22 deletions(-) diff --git a/base/errorshow.jl b/base/errorshow.jl index 0440e2073ead0..24663604f1a74 100644 --- a/base/errorshow.jl +++ b/base/errorshow.jl @@ -254,7 +254,6 @@ function showerror(io::IO, ex::MethodError) return showerror_ambiguous(io, meth, f, arg_types) end arg_types_param::SimpleVector = arg_types.parameters - show_candidates = true print(io, "MethodError: ") ft = typeof(f) f_is_function = false @@ -270,9 +269,6 @@ function showerror(io::IO, ex::MethodError) if f === Base.convert && length(arg_types_param) == 2 && !is_arg_types f_is_function = true show_convert_error(io, ex, arg_types_param) - elseif f === mapreduce_empty || f === reduce_empty - print(io, "reducing over an empty collection is not allowed; consider supplying `init` to the reducer") - show_candidates = false elseif isempty(methods(f)) && isa(f, DataType) && isabstracttype(f) print(io, "no constructors have been defined for ", f) elseif isempty(methods(f)) && !isa(f, Function) && !isa(f, Type) @@ -346,11 +342,12 @@ function showerror(io::IO, ex::MethodError) end end Experimental.show_error_hints(io, ex, arg_types_param, kwargs) - show_candidates && try + try show_method_candidates(io, ex, kwargs) catch ex @error "Error showing method candidates, aborted" exception=ex,catch_backtrace() end + nothing end striptype(::Type{T}) where {T} = T diff --git a/base/reduce.jl b/base/reduce.jl index f9411f8b5d783..6a0d46c61fcd9 100644 --- a/base/reduce.jl +++ b/base/reduce.jl @@ -316,10 +316,11 @@ pairwise_blocksize(::typeof(abs2), ::typeof(+)) = 4096 # handling empty arrays -_empty_reduce_error() = throw(ArgumentError("reducing over an empty collection is not allowed")) -_empty_reduce_error(@nospecialize(f), @nospecialize(T::Type)) = throw(ArgumentError(""" - reducing with $f over an empty collection of element type $T is not allowed. - You may be able to prevent this error by supplying an `init` value to the reducer.""")) +_empty_reduce_error() = throw(ArgumentError("reducing over an empty collection is not allowed; consider supplying `init` to the reducer")) +reduce_empty(f, T) = _empty_reduce_error() +mapreduce_empty(f, op, T) = _empty_reduce_error() +reduce_empty(f, ::Type{Union{}}, splat...) = _empty_reduce_error() +mapreduce_empty(f, op, ::Type{Union{}}, splat...) = _empty_reduce_error() """ Base.reduce_empty(op, T) @@ -339,20 +340,16 @@ is generally ambiguous, and especially so when the element type is unknown). As an alternative, consider supplying an `init` value to the reducer. """ -reduce_empty(::typeof(+), ::Type{Union{}}) = _empty_reduce_error(+, Union{}) reduce_empty(::typeof(+), ::Type{T}) where {T} = zero(T) reduce_empty(::typeof(+), ::Type{Bool}) = zero(Int) -reduce_empty(::typeof(*), ::Type{Union{}}) = _empty_reduce_error(*, Union{}) reduce_empty(::typeof(*), ::Type{T}) where {T} = one(T) reduce_empty(::typeof(*), ::Type{<:AbstractChar}) = "" reduce_empty(::typeof(&), ::Type{Bool}) = true reduce_empty(::typeof(|), ::Type{Bool}) = false -reduce_empty(::typeof(add_sum), ::Type{Union{}}) = _empty_reduce_error(add_sum, Union{}) reduce_empty(::typeof(add_sum), ::Type{T}) where {T} = reduce_empty(+, T) reduce_empty(::typeof(add_sum), ::Type{T}) where {T<:SmallSigned} = zero(Int) reduce_empty(::typeof(add_sum), ::Type{T}) where {T<:SmallUnsigned} = zero(UInt) -reduce_empty(::typeof(mul_prod), ::Type{Union{}}) = _empty_reduce_error(mul_prod, Union{}) reduce_empty(::typeof(mul_prod), ::Type{T}) where {T} = reduce_empty(*, T) reduce_empty(::typeof(mul_prod), ::Type{T}) where {T<:SmallSigned} = one(Int) reduce_empty(::typeof(mul_prod), ::Type{T}) where {T<:SmallUnsigned} = one(UInt) @@ -753,7 +750,7 @@ julia> maximum([1,2,3]) 3 julia> maximum(()) -ERROR: MethodError: reducing over an empty collection is not allowed; consider supplying `init` to the reducer +ERROR: ArgumentError: reducing over an empty collection is not allowed; consider supplying `init` to the reducer Stacktrace: [...] @@ -785,7 +782,7 @@ julia> minimum([1,2,3]) 1 julia> minimum([]) -ERROR: MethodError: reducing over an empty collection is not allowed; consider supplying `init` to the reducer +ERROR: ArgumentError: reducing over an empty collection is not allowed; consider supplying `init` to the reducer Stacktrace: [...] diff --git a/test/reduce.jl b/test/reduce.jl index 2c852084de37e..f5140c8a34bd9 100644 --- a/test/reduce.jl +++ b/test/reduce.jl @@ -53,8 +53,8 @@ end @test reduce(max, [8 6 7 5 3 0 9]) == 9 @test reduce(+, 1:5; init=1000) == (1000 + 1 + 2 + 3 + 4 + 5) @test reduce(+, 1) == 1 -@test_throws "reducing with * over an empty collection of element type Union{} is not allowed" reduce(*, ()) -@test_throws "reducing with * over an empty collection of element type Union{} is not allowed" reduce(*, Union{}[]) +@test_throws "reducing over an empty collection is not allowed" reduce(*, ()) +@test_throws "reducing over an empty collection is not allowed" reduce(*, Union{}[]) # mapreduce @test mapreduce(-, +, [-10 -9 -3]) == ((10 + 9) + 3) @@ -91,8 +91,7 @@ end @test mapreduce(abs2, *, Float64[]) === 1.0 @test mapreduce(abs2, max, Float64[]) === 0.0 @test mapreduce(abs, max, Float64[]) === 0.0 -@test_throws ["reducing over an empty collection is not allowed", - "consider supplying `init`"] mapreduce(abs2, &, Float64[]) +@test_throws "reducing over an empty collection is not allowed" mapreduce(abs2, &, Float64[]) @test_throws str -> !occursin("Closest candidates are", str) mapreduce(abs2, &, Float64[]) @test_throws "reducing over an empty collection is not allowed" mapreduce(abs2, |, Float64[]) @@ -144,9 +143,8 @@ fz = float(z) @test sum(z) === 136 @test sum(fz) === 136.0 -@test_throws "reducing with add_sum over an empty collection of element type Union{} is not allowed" sum(Union{}[]) -@test_throws ["reducing over an empty collection is not allowed", - "consider supplying `init`"] sum(sin, Int[]) +@test_throws "reducing over an empty collection is not allowed" sum(Union{}[]) +@test_throws "reducing over an empty collection is not allowed" sum(sin, Int[]) @test sum(sin, 3) == sin(3.0) @test sum(sin, [3]) == sin(3.0) a = sum(sin, z)