Skip to content

Commit e9e748e

Browse files
committed
Limit inference based initialization to concrete cases.
1 parent 86b3d99 commit e9e748e

File tree

1 file changed

+24
-38
lines changed

1 file changed

+24
-38
lines changed

base/reducedim.jl

Lines changed: 24 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -124,45 +124,31 @@ function _reducedim_init(f, op, fv, fop, A, region)
124124
end
125125

126126
# initialization when computing minima and maxima requires a little care
127-
for (f1, f2, initval, typeextreme) in ((:min, :max, :Inf, :typemax), (:max, :min, :(-Inf), :typemin))
128-
@eval function reducedim_init(f, op::typeof($f1), A::AbstractArray, region)
129-
# First compute the reduce indices. This will throw an ArgumentError
130-
# if any region is invalid
131-
ri = reduced_indices(A, region)
132-
133-
# Next, throw if reduction is over a region with length zero
134-
any(i -> isempty(axes(A, i)), region) && _empty_reduce_error()
135-
136-
# Make a view of the first slice of the region
137-
A1 = view(A, ri...)
138-
139-
if isempty(A1)
140-
# If the slice is empty just return non-view version as the initial array
141-
return copy(A1)
142-
else
143-
# otherwise use the min/max of the first slice as initial value
144-
v0 = mapreduce(f, $f2, A1)
145-
146-
T = _realtype(f, promote_union(eltype(A)))
147-
Tr = v0 isa T ? T : typeof(v0)
148-
149-
# but NaNs and missing need to be avoided as initial values
150-
if (v0 == v0) === false
151-
# v0 is NaN
152-
v0 = $initval
153-
elseif isunordered(v0)
154-
# v0 is missing or a third-party unordered value
155-
Tnm = nonmissingtype(Tr)
156-
# TODO: Some types, like BigInt, don't support typemin/typemax.
157-
# So a Matrix{Union{BigInt, Missing}} can still error here.
158-
v0 = $typeextreme(Tnm)
159-
end
160-
# v0 may have changed type.
161-
Tr = v0 isa T ? T : typeof(v0)
162-
163-
return reducedim_initarray(A, region, v0, Tr)
164-
end
127+
function reducedim_init(f::F, op::Union{typeof(min),typeof(max)}, A::AbstractArray, region) where {F}
128+
# First compute the reduce indices. This will throw an ArgumentError
129+
# if any region is invalid
130+
ri = reduced_indices(A, region)
131+
132+
# Next, throw if reduction is over a region with length zero
133+
any(i -> isempty(axes(A, i)), region) && _empty_reduce_error()
134+
135+
# Make a view of the first slice of the region
136+
A1 = view(A, ri...)
137+
138+
# Then we try to derive the container's eltype.
139+
T = _return_type(f, Tuple{eltype(A)})
140+
if isempty(A) || (isconcretetype(nonmissingtype(T)) && T === _return_type(op, Tuple{T,T}))
141+
# Trust the inference result only when:
142+
# 1.`nonmissingtype(T)` is concrete. And `T`'s `min`/`max` is well defined.
143+
# 2. `A1` is empty.
144+
return map!(f, reducedim_initarray(A,region,_InitialValue(),T), A1)
165145
end
146+
# Otherwise, we'd better not rely on inference.
147+
v0 = mapreduce(f, op, A1) # 1. Try to reduce A1
148+
T = _realtype(f, promote_union(eltype(A))) # 2. A possible wrong guess.
149+
Tr = v0 isa T ? T : typeof(v0) # 3. If T is wrong. Use typeof(v0) instead.
150+
# Note: `Tr` still might be wrong, but this can't be truely resolved except we reduce `A`.
151+
return map!(f, reducedim_initarray(A,region,_InitialValue(),Tr), A1)
166152
end
167153

168154
reducedim_init(f::Union{typeof(abs),typeof(abs2)}, op::typeof(max), A::AbstractArray{T}, region) where {T} =

0 commit comments

Comments
 (0)