Skip to content

Commit

Permalink
Merge pull request #17929 from pabloferz/pz/promop
Browse files Browse the repository at this point in the history
Improve promote_op
  • Loading branch information
JeffBezanson authored Aug 11, 2016
2 parents b066714 + 6fd91b2 commit f964e10
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 29 deletions.
10 changes: 5 additions & 5 deletions base/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1653,11 +1653,11 @@ end

# These are needed because map(eltype, As) is not inferrable
promote_eltype_op(::Any) = (@_pure_meta; Bottom)
promote_eltype_op(op, A) = (@_pure_meta; _promote_op(op, eltype(A)))
promote_eltype_op{T}(op, ::AbstractArray{T}) = (@_pure_meta; _promote_op(op, T))
promote_eltype_op{T}(op, ::AbstractArray{T}, A) = (@_pure_meta; _promote_op(op, T, eltype(A)))
promote_eltype_op{T}(op, A, ::AbstractArray{T}) = (@_pure_meta; _promote_op(op, eltype(A), T))
promote_eltype_op{R,S}(op, ::AbstractArray{R}, ::AbstractArray{S}) = (@_pure_meta; _promote_op(op, R, S))
promote_eltype_op(op, A) = (@_pure_meta; promote_op(op, eltype(A)))
promote_eltype_op{T}(op, ::AbstractArray{T}) = (@_pure_meta; promote_op(op, T))
promote_eltype_op{T}(op, ::AbstractArray{T}, A) = (@_pure_meta; promote_op(op, T, eltype(A)))
promote_eltype_op{T}(op, A, ::AbstractArray{T}) = (@_pure_meta; promote_op(op, eltype(A), T))
promote_eltype_op{R,S}(op, ::AbstractArray{R}, ::AbstractArray{S}) = (@_pure_meta; promote_op(op, R, S))
promote_eltype_op(op, A, B, C, D...) = (@_pure_meta; promote_eltype_op(op, promote_eltype_op(op, A, B), C, D...))

## 1 argument
Expand Down
24 changes: 12 additions & 12 deletions base/arraymath.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ promote_array_type{S<:Integer}(::typeof(.\), ::Type{S}, ::Type{Bool}, T::Type) =
promote_array_type{S<:Integer}(F, ::Type{S}, ::Type{Bool}, T::Type) = T

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

for f in (:.+, :.-, :.*, :./, :.\, :.^, :, :.%, :.<<, :.>>, :div, :mod, :rem, :&, :|, :$)
@eval begin
function ($f)(A::Number, B::AbstractArray)
P = promote_op($f, typeof(A), eltype(B))
T = promote_array_type($f, typeof(A), eltype(B), P)
T === Any && return [($f)(A, b) for b in B]
F = similar(B, T)
function ($f){T}(A::Number, B::AbstractArray{T})
R = promote_op($f, typeof(A), T)
S = promote_array_type($f, typeof(A), T, R)
S === Any && return [($f)(A, b) for b in B]
F = similar(B, S)
for (iF, iB) in zip(eachindex(F), eachindex(B))
@inbounds F[iF] = ($f)(A, B[iB])
end
return F
end
function ($f)(A::AbstractArray, B::Number)
P = promote_op($f, eltype(A), typeof(B))
T = promote_array_type($f, typeof(B), eltype(A), P)
T === Any && return [($f)(a, B) for a in A]
F = similar(A, T)
function ($f){T}(A::AbstractArray{T}, B::Number)
R = promote_op($f, T, typeof(B))
S = promote_array_type($f, typeof(B), T, R)
S === Any && return [($f)(a, B) for a in A]
F = similar(A, S)
for (iF, iA) in zip(eachindex(F), eachindex(A))
@inbounds F[iF] = ($f)(A[iA], B)
end
Expand Down
23 changes: 11 additions & 12 deletions base/promotion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -220,34 +220,33 @@ minmax(x::Real, y::Real) = minmax(promote(x, y)...)
# "Promotion" that takes a function into account. These are meant to be
# used mainly by broadcast methods, so it is advised against overriding them
if isdefined(Core, :Inference)
function _promote_op(op, T::Type)
function _promote_op(op, T::ANY)
G = Tuple{Generator{Tuple{T},typeof(op)}}
R = Core.Inference.return_type(first, G)
return isleaftype(R) ? R : Any
return Core.Inference.return_type(first, G)
end
function _promote_op(op, R::Type, S::Type)
function _promote_op(op, R::ANY, S::ANY)
F = typeof(a -> op(a...))
G = Tuple{Generator{Zip2{Tuple{R},Tuple{S}},F}}
T = Core.Inference.return_type(first, G)
return isleaftype(T) ? T : Any
return Core.Inference.return_type(first, G)
end
else
_promote_op(::Any...) = (@_pure_meta; Any)
_promote_op(::ANY...) = (@_pure_meta; Any)
end
_default_type(T::Type) = (@_pure_meta; T)

promote_op(::Any...) = (@_pure_meta; Any)
promote_op(T::Type, ::Any) = (@_pure_meta; T)
promote_op(T::Type, ::Type) = (@_pure_meta; T) # To handle ambiguities
# Promotion that tries to preserve non-concrete types
function promote_op(f, S::Type)
function promote_op{S}(f, ::Type{S})
T = _promote_op(f, _default_type(S))
return isleaftype(S) ? T : typejoin(S, T)
isleaftype(S) && return isleaftype(T) ? T : Any
return typejoin(S, T)
end
function promote_op(f, R::Type, S::Type)
function promote_op{R,S}(f, ::Type{R}, ::Type{S})
T = _promote_op(f, _default_type(R), _default_type(S))
isleaftype(R) && return isleaftype(S) ? T : typejoin(S, T)
return isleaftype(S) ? typejoin(R, T) : typejoin(R, S, T)
isleaftype(R) && isleaftype(S) && return isleaftype(T) ? T : Any
return typejoin(R, S, T)
end

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

0 comments on commit f964e10

Please sign in to comment.