Skip to content

Commit df5286a

Browse files
pabloferztkelman
authored andcommittedAug 20, 2016
Improve inferability of promote_op
(cherry picked from commit 6fd91b2) ref #17929
1 parent 14a5744 commit df5286a

File tree

3 files changed

+28
-29
lines changed

3 files changed

+28
-29
lines changed
 

‎base/abstractarray.jl

+5-5
Original file line numberDiff line numberDiff line change
@@ -1653,11 +1653,11 @@ end
16531653

16541654
# These are needed because map(eltype, As) is not inferrable
16551655
promote_eltype_op(::Any) = (@_pure_meta; Bottom)
1656-
promote_eltype_op(op, A) = (@_pure_meta; _promote_op(op, eltype(A)))
1657-
promote_eltype_op{T}(op, ::AbstractArray{T}) = (@_pure_meta; _promote_op(op, T))
1658-
promote_eltype_op{T}(op, ::AbstractArray{T}, A) = (@_pure_meta; _promote_op(op, T, eltype(A)))
1659-
promote_eltype_op{T}(op, A, ::AbstractArray{T}) = (@_pure_meta; _promote_op(op, eltype(A), T))
1660-
promote_eltype_op{R,S}(op, ::AbstractArray{R}, ::AbstractArray{S}) = (@_pure_meta; _promote_op(op, R, S))
1656+
promote_eltype_op(op, A) = (@_pure_meta; promote_op(op, eltype(A)))
1657+
promote_eltype_op{T}(op, ::AbstractArray{T}) = (@_pure_meta; promote_op(op, T))
1658+
promote_eltype_op{T}(op, ::AbstractArray{T}, A) = (@_pure_meta; promote_op(op, T, eltype(A)))
1659+
promote_eltype_op{T}(op, A, ::AbstractArray{T}) = (@_pure_meta; promote_op(op, eltype(A), T))
1660+
promote_eltype_op{R,S}(op, ::AbstractArray{R}, ::AbstractArray{S}) = (@_pure_meta; promote_op(op, R, S))
16611661
promote_eltype_op(op, A, B, C, D...) = (@_pure_meta; promote_eltype_op(op, promote_eltype_op(op, A, B), C, D...))
16621662

16631663
## 1 argument

‎base/arraymath.jl

+12-12
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ promote_array_type{S<:Integer}(::typeof(.\), ::Type{S}, ::Type{Bool}, T::Type) =
4646
promote_array_type{S<:Integer}(F, ::Type{S}, ::Type{Bool}, T::Type) = T
4747

4848
for f in (:+, :-, :div, :mod, :&, :|, :$)
49-
@eval ($f)(A::AbstractArray, B::AbstractArray) =
50-
_elementwise($f, promote_op($f, eltype(A), eltype(B)), A, B)
49+
@eval ($f){R,S}(A::AbstractArray{R}, B::AbstractArray{S}) =
50+
_elementwise($f, promote_op($f, R, S), A, B)
5151
end
5252
function _elementwise(op, ::Type{Any}, A::AbstractArray, B::AbstractArray)
5353
promote_shape(A, B) # check size compatibility
@@ -63,21 +63,21 @@ end
6363

6464
for f in (:.+, :.-, :.*, :./, :.\, :.^, :, :.%, :.<<, :.>>, :div, :mod, :rem, :&, :|, :$)
6565
@eval begin
66-
function ($f)(A::Number, B::AbstractArray)
67-
P = promote_op($f, typeof(A), eltype(B))
68-
T = promote_array_type($f, typeof(A), eltype(B), P)
69-
T === Any && return [($f)(A, b) for b in B]
70-
F = similar(B, T)
66+
function ($f){T}(A::Number, B::AbstractArray{T})
67+
R = promote_op($f, typeof(A), T)
68+
S = promote_array_type($f, typeof(A), T, R)
69+
S === Any && return [($f)(A, b) for b in B]
70+
F = similar(B, S)
7171
for (iF, iB) in zip(eachindex(F), eachindex(B))
7272
@inbounds F[iF] = ($f)(A, B[iB])
7373
end
7474
return F
7575
end
76-
function ($f)(A::AbstractArray, B::Number)
77-
P = promote_op($f, eltype(A), typeof(B))
78-
T = promote_array_type($f, typeof(B), eltype(A), P)
79-
T === Any && return [($f)(a, B) for a in A]
80-
F = similar(A, T)
76+
function ($f){T}(A::AbstractArray{T}, B::Number)
77+
R = promote_op($f, T, typeof(B))
78+
S = promote_array_type($f, typeof(B), T, R)
79+
S === Any && return [($f)(a, B) for a in A]
80+
F = similar(A, S)
8181
for (iF, iA) in zip(eachindex(F), eachindex(A))
8282
@inbounds F[iF] = ($f)(A[iA], B)
8383
end

‎base/promotion.jl

+11-12
Original file line numberDiff line numberDiff line change
@@ -220,34 +220,33 @@ minmax(x::Real, y::Real) = minmax(promote(x, y)...)
220220
# "Promotion" that takes a function into account. These are meant to be
221221
# used mainly by broadcast methods, so it is advised against overriding them
222222
if isdefined(Core, :Inference)
223-
function _promote_op(op, T::Type)
223+
function _promote_op(op, T::ANY)
224224
G = Tuple{Generator{Tuple{T},typeof(op)}}
225-
R = Core.Inference.return_type(first, G)
226-
return isleaftype(R) ? R : Any
225+
return Core.Inference.return_type(first, G)
227226
end
228-
function _promote_op(op, R::Type, S::Type)
227+
function _promote_op(op, R::ANY, S::ANY)
229228
F = typeof(a -> op(a...))
230229
G = Tuple{Generator{Zip2{Tuple{R},Tuple{S}},F}}
231-
T = Core.Inference.return_type(first, G)
232-
return isleaftype(T) ? T : Any
230+
return Core.Inference.return_type(first, G)
233231
end
234232
else
235-
_promote_op(::Any...) = (@_pure_meta; Any)
233+
_promote_op(::ANY...) = (@_pure_meta; Any)
236234
end
237235
_default_type(T::Type) = (@_pure_meta; T)
238236

239237
promote_op(::Any...) = (@_pure_meta; Any)
240238
promote_op(T::Type, ::Any) = (@_pure_meta; T)
241239
promote_op(T::Type, ::Type) = (@_pure_meta; T) # To handle ambiguities
242240
# Promotion that tries to preserve non-concrete types
243-
function promote_op(f, S::Type)
241+
function promote_op{S}(f, ::Type{S})
244242
T = _promote_op(f, _default_type(S))
245-
return isleaftype(S) ? T : typejoin(S, T)
243+
isleaftype(S) && return isleaftype(T) ? T : Any
244+
return typejoin(S, T)
246245
end
247-
function promote_op(f, R::Type, S::Type)
246+
function promote_op{R,S}(f, ::Type{R}, ::Type{S})
248247
T = _promote_op(f, _default_type(R), _default_type(S))
249-
isleaftype(R) && return isleaftype(S) ? T : typejoin(S, T)
250-
return isleaftype(S) ? typejoin(R, T) : typejoin(R, S, T)
248+
isleaftype(R) && isleaftype(S) && return isleaftype(T) ? T : Any
249+
return typejoin(R, S, T)
251250
end
252251

253252
## catch-alls to prevent infinite recursion when definitions are missing ##

0 commit comments

Comments
 (0)
Please sign in to comment.