From 3ad148a4e6a06f5db3d49742eca8368148c4f584 Mon Sep 17 00:00:00 2001
From: Martin Holters <martin.holters@hsu-hh.de>
Date: Thu, 7 Jul 2016 12:00:39 +0200
Subject: [PATCH] Use broadcast for array ops, closes #17254

---
 base/arraymath.jl | 28 ++--------------------------
 base/broadcast.jl | 40 +++++-----------------------------------
 test/arrayops.jl  | 19 +++++++++++++++++++
 3 files changed, 26 insertions(+), 61 deletions(-)

diff --git a/base/arraymath.jl b/base/arraymath.jl
index cb3cd4625e26e6..ffd8d98afda66c 100644
--- a/base/arraymath.jl
+++ b/base/arraymath.jl
@@ -51,33 +51,9 @@ end
 
 for f in (:+, :-, :div, :mod, :&, :|, :$)
     @eval begin
-        function ($f){S,T}(A::Range{S}, B::Range{T})
-            F = similar(A, promote_op($f,S,T), promote_shape(size(A),size(B)))
-            for (iF, iA, iB) in zip(eachindex(F), eachindex(A), eachindex(B))
-                @inbounds F[iF] = ($f)(A[iA], B[iB])
-            end
-            return F
-        end
-        function ($f){S,T}(A::AbstractArray{S}, B::Range{T})
-            F = similar(A, promote_op($f,S,T), promote_shape(A,B))
-            for (iF, iA, iB) in zip(eachindex(F), eachindex(A), eachindex(B))
-                @inbounds F[iF] = ($f)(A[iA], B[iB])
-            end
-            return F
-        end
-        function ($f){S,T}(A::Range{S}, B::AbstractArray{T})
-            F = similar(B, promote_op($f,S,T), promote_shape(A,B))
-            for (iF, iA, iB) in zip(eachindex(F), eachindex(A), eachindex(B))
-                @inbounds F[iF] = ($f)(A[iA], B[iB])
-            end
-            return F
-        end
         function ($f){S,T}(A::AbstractArray{S}, B::AbstractArray{T})
-            F = similar(A, promote_op($f,S,T), promote_shape(A,B))
-            for (iF, iA, iB) in zip(eachindex(F), eachindex(A), eachindex(B))
-                @inbounds F[iF] = ($f)(A[iA], B[iB])
-            end
-            return F
+            promote_shape(A,B) # check size compatibility
+            return broadcast($f, A, B)
         end
     end
 end
diff --git a/base/broadcast.jl b/base/broadcast.jl
index ab8fee3c97753d..27f0f0242c7778 100644
--- a/base/broadcast.jl
+++ b/base/broadcast.jl
@@ -264,44 +264,14 @@ end
 
 ## elementwise operators ##
 
-.÷(A::AbstractArray, B::AbstractArray) = broadcast(÷, A, B)
-.%(A::AbstractArray, B::AbstractArray) = broadcast(%, A, B)
-.<<(A::AbstractArray, B::AbstractArray) = broadcast(<<, A, B)
-.>>(A::AbstractArray, B::AbstractArray) = broadcast(>>, A, B)
-
+# should this be deprecated? Only use in Base is in sparsematrix.jl
 eltype_plus(As::AbstractArray...) = promote_eltype_op(+, As...)
 
-.+(As::AbstractArray...) = broadcast!(+, Array{eltype_plus(As...)}(broadcast_shape(As...)), As...)
-
-function .-(A::AbstractArray, B::AbstractArray)
-    broadcast!(-, Array{promote_op(-, eltype(A), eltype(B))}(broadcast_shape(A,B)), A, B)
-end
-
-eltype_mul(As::AbstractArray...) = promote_eltype_op(*, As...)
-
-.*(As::AbstractArray...) = broadcast!(*, Array{eltype_mul(As...)}(broadcast_shape(As...)), As...)
-
-function ./(A::AbstractArray, B::AbstractArray)
-    broadcast!(/, Array{promote_op(/, eltype(A), eltype(B))}(broadcast_shape(A, B)), A, B)
-end
-
-function .\(A::AbstractArray, B::AbstractArray)
-    broadcast!(\, Array{promote_op(\, eltype(A), eltype(B))}(broadcast_shape(A, B)), A, B)
-end
-
-typealias RatIntT{T<:Integer} Union{Type{Rational{T}},Type{T}}
-typealias CRatIntT{T<:Integer} Union{Type{Complex{Rational{T}}},Type{Complex{T}},Type{Rational{T}},Type{T}}
-type_rdiv{T<:Integer,S<:Integer}(::RatIntT{T}, ::RatIntT{S}) =
-    Rational{promote_type(T,S)}
-type_rdiv{T<:Integer,S<:Integer}(::CRatIntT{T}, ::CRatIntT{S}) =
-    Complex{Rational{promote_type(T,S)}}
-function .//(A::AbstractArray, B::AbstractArray)
-    broadcast!(//, Array{type_rdiv(eltype(A), eltype(B))}(broadcast_shape(A, B)), A, B)
-end
-
-function .^(A::AbstractArray, B::AbstractArray)
-    broadcast!(^, Array{promote_op(^, eltype(A), eltype(B))}(broadcast_shape(A, B)), A, B)
+for op in (:÷, :%, :<<, :>>, :-, :/, :\, ://, :^)
+    @eval $(Symbol(:., op))(A::AbstractArray, B::AbstractArray) = broadcast($(op), A, B)
 end
+.+(As::AbstractArray...) = broadcast(+, As...)
+.*(As::AbstractArray...) = broadcast(*, As...)
 
 # ## element-wise comparison operators returning BitArray ##
 
diff --git a/test/arrayops.jl b/test/arrayops.jl
index c7e0356e00b37b..bd02179ba3694f 100644
--- a/test/arrayops.jl
+++ b/test/arrayops.jl
@@ -1668,3 +1668,22 @@ let A = zeros(3,3)
     @test size(A[:,UInt(1):UInt(2)]) == (3,2)
     @test size(similar(A, UInt(3), 0x3)) == size(similar(A, (UInt(3), 0x3))) == (3,3)
 end
+
+# issue 17254
+module AutoRetType
+
+using Base.Test
+
+immutable Foo end
+for op in (:+, :*, :÷, :%, :<<, :>>, :-, :/, :\, ://, :^)
+    @eval import Base.$(op)
+    @eval $(op)(::Foo, ::Foo) = Foo()
+end
+A = fill(Foo(), 10, 10)
+@test typeof(A+A) == Matrix{Foo}
+@test typeof(A-A) == Matrix{Foo}
+for op in (:.+, :.*, :.÷, :.%, :.<<, :.>>, :.-, :./, :.\, :.//, :.^)
+    @eval @test typeof($(op)(A,A)) == Matrix{Foo}
+end
+
+end