Skip to content

Commit

Permalink
combine reduce_empty methods for Union{} eltypes
Browse files Browse the repository at this point in the history
With #49470, these can all be dispatched to the same method now,
avoiding unnecessary code duplication for this case.

This partly reverts f2dcc44, but our
edges against methods should be better than the ones against
MethodError these days.
  • Loading branch information
vtjnash committed Nov 2, 2023
1 parent 2a84214 commit f34931d
Show file tree
Hide file tree
Showing 3 changed files with 14 additions and 22 deletions.
7 changes: 2 additions & 5 deletions base/errorshow.jl
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,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
Expand All @@ -258,9 +257,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)
Expand Down Expand Up @@ -334,11 +330,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
Expand Down
17 changes: 7 additions & 10 deletions base/reduce.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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:
[...]
Expand Down Expand Up @@ -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:
[...]
Expand Down
12 changes: 5 additions & 7 deletions test/reduce.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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[])

Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit f34931d

Please sign in to comment.