Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve promote_op #17929

Merged
merged 1 commit into from
Aug 11, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions base/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1578,11 +1578,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