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

Use promote_op in broadcasting and matrix multiplication #13803

Merged
merged 1 commit into from
Oct 29, 2015
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
9 changes: 9 additions & 0 deletions base/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1269,6 +1269,15 @@ function map_promote(f, A::AbstractArray)
return promote_to!(f, 2, dest, A)
end

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

## 1 argument
map!{F}(f::F, A::AbstractArray) = map!(f, A, A)
function map!{F}(f::F, dest::AbstractArray, A::AbstractArray)
Expand Down
2 changes: 2 additions & 0 deletions base/bool.jl
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,5 @@ fld(x::Bool, y::Bool) = div(x,y)
cld(x::Bool, y::Bool) = div(x,y)
rem(x::Bool, y::Bool) = y ? false : throw(DivideError())
mod(x::Bool, y::Bool) = rem(x,y)

promote_op(op, ::Type{Bool}, ::Type{Bool}) = typeof(op(true, true))
34 changes: 11 additions & 23 deletions base/broadcast.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
module Broadcast

using ..Cartesian
import Base.promote_eltype
import Base.@get!
import Base.num_bit_chunks, Base._msk_end, Base.unsafe_bitgetindex
using Base: promote_op, promote_eltype, promote_eltype_op, @get!, _msk_end, unsafe_bitgetindex
using Base: AddFun, SubFun, MulFun, LDivFun, RDivFun, PowFun
import Base: .+, .-, .*, ./, .\, .//, .==, .<, .!=, .<=, .%, .<<, .>>, .^
export broadcast, broadcast!, broadcast_function, broadcast!_function, bitbroadcast
export broadcast_getindex, broadcast_setindex!
Expand Down Expand Up @@ -232,7 +231,7 @@ for (Bsig, Asig, gbf, gbb) in
end


broadcast(f, As...) = broadcast!(f, Array(promote_eltype(As...), broadcast_shape(As...)), As...)
broadcast(f, As...) = broadcast!(f, Array(promote_eltype_op(f, As...), broadcast_shape(As...)), As...)

bitbroadcast(f, As...) = broadcast!(f, BitArray(broadcast_shape(As...)), As...)

Expand Down Expand Up @@ -286,35 +285,28 @@ end

## elementwise operators ##

.*(As::AbstractArray...) = broadcast(*, As...)
.%(A::AbstractArray, B::AbstractArray) = broadcast(%, A, B)
.<<(A::AbstractArray, B::AbstractArray) = broadcast(<<, A, B)
.>>(A::AbstractArray, B::AbstractArray) = broadcast(>>, A, B)

eltype_plus(As::AbstractArray...) = promote_eltype(As...)
eltype_plus(As::AbstractArray{Bool}...) = typeof(true+true)
eltype_plus(As::AbstractArray...) = promote_eltype_op(AddFun(), As...)

.+(As::AbstractArray...) = broadcast!(+, Array(eltype_plus(As...), broadcast_shape(As...)), As...)

type_minus(T, S) = promote_type(T, S)
type_minus(::Type{Bool}, ::Type{Bool}) = typeof(true-true)

function .-(A::AbstractArray, B::AbstractArray)
broadcast!(-, Array(type_minus(eltype(A), eltype(B)), broadcast_shape(A,B)), A, B)
broadcast!(-, Array(promote_op(SubFun(), eltype(A), eltype(B)), broadcast_shape(A,B)), A, B)
end

type_div(T,S) = promote_type(T,S)
type_div{T<:Integer,S<:Integer}(::Type{T},::Type{S}) = typeof(one(T)/one(S))
type_div{T,S}(::Type{Complex{T}},::Type{Complex{S}}) = Complex{type_div(T,S)}
type_div{T,S}(::Type{Complex{T}},::Type{S}) = Complex{type_div(T,S)}
type_div{T,S}(::Type{T},::Type{Complex{S}}) = Complex{type_div(T,S)}
eltype_mul(As::AbstractArray...) = promote_eltype_op(MulFun(), As...)

.*(As::AbstractArray...) = broadcast!(*, Array(eltype_mul(As...), broadcast_shape(As...)), As...)

function ./(A::AbstractArray, B::AbstractArray)
broadcast!(/, Array(type_div(eltype(A), eltype(B)), broadcast_shape(A, B)), A, B)
broadcast!(/, Array(promote_op(RDivFun(), eltype(A), eltype(B)), broadcast_shape(A, B)), A, B)
end

function .\(A::AbstractArray, B::AbstractArray)
broadcast!(\, Array(type_div(eltype(A), eltype(B)), broadcast_shape(A, B)), A, B)
broadcast!(\, Array(promote_op(LDivFun(), eltype(A), eltype(B)), broadcast_shape(A, B)), A, B)
end

typealias RatIntT{T<:Integer} Union{Type{Rational{T}},Type{T}}
Expand All @@ -327,12 +319,8 @@ function .//(A::AbstractArray, B::AbstractArray)
broadcast!(//, Array(type_rdiv(eltype(A), eltype(B)), broadcast_shape(A, B)), A, B)
end

type_pow(T,S) = promote_type(T,S)
type_pow{S<:Integer}(::Type{Bool},::Type{S}) = Bool
type_pow{S}(T,::Type{Rational{S}}) = type_pow(T, type_div(S, S))

function .^(A::AbstractArray, B::AbstractArray)
broadcast!(^, Array(type_pow(eltype(A), eltype(B)), broadcast_shape(A, B)), A, B)
broadcast!(^, Array(promote_op(PowFun(), eltype(A), eltype(B)), broadcast_shape(A, B)), A, B)
end

## element-wise comparison operators returning BitArray ##
Expand Down
7 changes: 7 additions & 0 deletions base/complex.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ promote_rule{T<:Real,S<:Real}(::Type{Complex{T}}, ::Type{S}) =
promote_rule{T<:Real,S<:Real}(::Type{Complex{T}}, ::Type{Complex{S}}) =
Complex{promote_type(T,S)}

promote_op{T<:Real,S<:Real}(op, ::Type{Complex{T}}, ::Type{Complex{S}}) =
Complex{promote_op(op,T,S)}
promote_op{T<:Real,S<:Real}(op, ::Type{Complex{T}}, ::Type{S}) =
Complex{promote_op(op,T,S)}
promote_op{T<:Real,S<:Real}(op, ::Type{T}, ::Type{Complex{S}}) =
Complex{promote_op(op,T,S)}

widen{T}(::Type{Complex{T}}) = Complex{widen(T)}

real(z::Complex) = z.re
Expand Down
4 changes: 4 additions & 0 deletions base/functors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ EqX{T}(x::T) = EqX{T}(x)

call(f::EqX, y) = f.x == y

# More promote_op rules

promote_op{T<:Integer}(::PowFun, ::Type{Bool}, ::Type{T}) = Bool

#### Bitwise operators ####

# BitFunctors are functions that behave in the same bit-wise manner when applied
Expand Down
2 changes: 2 additions & 0 deletions base/int.jl
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,8 @@ promote_rule(::Type{UInt128}, ::Type{Int32} ) = UInt128
promote_rule(::Type{UInt128}, ::Type{Int64} ) = UInt128
promote_rule(::Type{UInt128}, ::Type{Int128}) = UInt128

promote_op{R<:Integer,S<:Integer}(op, ::Type{R}, ::Type{S}) = typeof(op(one(R), one(S)))

## traits ##

typemin(::Type{Int8 }) = Int8(-128)
Expand Down
1 change: 1 addition & 0 deletions base/linalg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Base: USE_BLAS64, abs, big, ceil, conj, convert, copy, copy!, copy_transp
imag, inv, isapprox, kron, ndims, power_by_squaring, print_matrix, promote_rule, real,
round, setindex!, show, similar, size, transpose, transpose!, trunc, unsafe_getindex,
unsafe_setindex!
using Base: promote_op, MulFun

export
# Modules
Expand Down
38 changes: 19 additions & 19 deletions base/linalg/matmul.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ function scale!(C::AbstractMatrix, b::AbstractVector, A::AbstractMatrix)
end
C
end
scale(A::Matrix, b::Vector) = scale!(similar(A, promote_type(eltype(A),eltype(b))), A, b)
scale(b::Vector, A::Matrix) = scale!(similar(b, promote_type(eltype(A),eltype(b)), size(A)), b, A)
scale(A::Matrix, b::Vector) = scale!(similar(A, promote_op(MulFun(),eltype(A),eltype(b))), A, b)
scale(b::Vector, A::Matrix) = scale!(similar(b, promote_op(MulFun(),eltype(b),eltype(A)), size(A)), b, A)

# Dot products

Expand Down Expand Up @@ -78,11 +78,11 @@ At_mul_B{T<:BlasComplex}(x::StridedVector{T}, y::StridedVector{T}) = [BLAS.dotu(

# Matrix-vector multiplication
function (*){T<:BlasFloat,S}(A::StridedMatrix{T}, x::StridedVector{S})
TS = promote_type(arithtype(T),arithtype(S))
TS = promote_op(MulFun(),arithtype(T),arithtype(S))
A_mul_B!(similar(x, TS, size(A,1)), A, convert(AbstractVector{TS}, x))
end
function (*){T,S}(A::AbstractMatrix{T}, x::AbstractVector{S})
TS = promote_type(arithtype(T),arithtype(S))
TS = promote_op(MulFun(),arithtype(T),arithtype(S))
A_mul_B!(similar(x,TS,size(A,1)),A,x)
end
(*)(A::AbstractVector, B::AbstractMatrix) = reshape(A,length(A),1)*B
Expand All @@ -101,22 +101,22 @@ end
A_mul_B!(y::StridedVector, A::StridedVecOrMat, x::StridedVector) = generic_matvecmul!(y, 'N', A, x)

function At_mul_B{T<:BlasFloat,S}(A::StridedMatrix{T}, x::StridedVector{S})
TS = promote_type(arithtype(T),arithtype(S))
TS = promote_op(MulFun(),arithtype(T),arithtype(S))
At_mul_B!(similar(x,TS,size(A,2)), A, convert(AbstractVector{TS}, x))
end
function At_mul_B{T,S}(A::StridedMatrix{T}, x::StridedVector{S})
TS = promote_type(arithtype(T),arithtype(S))
TS = promote_op(MulFun(),arithtype(T),arithtype(S))
At_mul_B!(similar(x,TS,size(A,2)), A, x)
end
At_mul_B!{T<:BlasFloat}(y::StridedVector{T}, A::StridedVecOrMat{T}, x::StridedVector{T}) = gemv!(y, 'T', A, x)
At_mul_B!(y::StridedVector, A::StridedVecOrMat, x::StridedVector) = generic_matvecmul!(y, 'T', A, x)

function Ac_mul_B{T<:BlasFloat,S}(A::StridedMatrix{T}, x::StridedVector{S})
TS = promote_type(arithtype(T),arithtype(S))
TS = promote_op(MulFun(),arithtype(T),arithtype(S))
Ac_mul_B!(similar(x,TS,size(A,2)),A,convert(AbstractVector{TS},x))
end
function Ac_mul_B{T,S}(A::StridedMatrix{T}, x::StridedVector{S})
TS = promote_type(arithtype(T),arithtype(S))
TS = promote_op(MulFun(),arithtype(T),arithtype(S))
Ac_mul_B!(similar(x,TS,size(A,2)), A, x)
end

Expand All @@ -127,7 +127,7 @@ Ac_mul_B!(y::StridedVector, A::StridedVecOrMat, x::StridedVector) = generic_matv
# Matrix-matrix multiplication

function (*){T,S}(A::AbstractMatrix{T}, B::StridedMatrix{S})
TS = promote_type(arithtype(T), arithtype(S))
TS = promote_op(MulFun(), arithtype(T), arithtype(S))
A_mul_B!(similar(B, TS, (size(A,1), size(B,2))), A, B)
end
A_mul_B!{T<:BlasFloat}(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) = gemm_wrapper!(C, 'N', 'N', A, B)
Expand All @@ -144,14 +144,14 @@ end
A_mul_B!(C::StridedMatrix, A::StridedVecOrMat, B::StridedVecOrMat) = generic_matmatmul!(C, 'N', 'N', A, B)

function At_mul_B{T,S}(A::AbstractMatrix{T}, B::StridedMatrix{S})
TS = promote_type(arithtype(T), arithtype(S))
TS = promote_op(MulFun(),arithtype(T), arithtype(S))
At_mul_B!(similar(B, TS, (size(A,2), size(B,2))), A, B)
end
At_mul_B!{T<:BlasFloat}(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) = is(A,B) ? syrk_wrapper!(C, 'T', A) : gemm_wrapper!(C, 'T', 'N', A, B)
At_mul_B!(C::StridedMatrix, A::StridedVecOrMat, B::StridedVecOrMat) = generic_matmatmul!(C, 'T', 'N', A, B)

function A_mul_Bt{T,S}(A::AbstractMatrix{T}, B::StridedMatrix{S})
TS = promote_type(arithtype(T), arithtype(S))
TS = promote_op(MulFun(),arithtype(T), arithtype(S))
A_mul_Bt!(similar(B, TS, (size(A,1), size(B,1))), A, B)
end
A_mul_Bt!{T<:BlasFloat}(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) = is(A,B) ? syrk_wrapper!(C, 'N', A) : gemm_wrapper!(C, 'N', 'T', A, B)
Expand All @@ -168,7 +168,7 @@ end
A_mul_Bt!(C::StridedVecOrMat, A::StridedVecOrMat, B::StridedVecOrMat) = generic_matmatmul!(C, 'N', 'T', A, B)

function At_mul_Bt{T,S}(A::AbstractMatrix{T}, B::StridedVecOrMat{S})
TS = promote_type(arithtype(T), arithtype(S))
TS = promote_op(MulFun(),arithtype(T), arithtype(S))
At_mul_Bt!(similar(B, TS, (size(A,2), size(B,1))), A, B)
end
At_mul_Bt!{T<:BlasFloat}(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) = gemm_wrapper!(C, 'T', 'T', A, B)
Expand All @@ -177,7 +177,7 @@ At_mul_Bt!(C::StridedMatrix, A::StridedVecOrMat, B::StridedVecOrMat) = generic_m
Ac_mul_B{T<:BlasReal}(A::StridedMatrix{T}, B::StridedMatrix{T}) = At_mul_B(A, B)
Ac_mul_B!{T<:BlasReal}(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) = At_mul_B!(C, A, B)
function Ac_mul_B{T,S}(A::StridedMatrix{T}, B::StridedMatrix{S})
TS = promote_type(arithtype(T), arithtype(S))
TS = promote_op(MulFun(),arithtype(T), arithtype(S))
Ac_mul_B!(similar(B, TS, (size(A,2), size(B,2))), A, B)
end
Ac_mul_B!{T<:BlasComplex}(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) = is(A,B) ? herk_wrapper!(C,'C',A) : gemm_wrapper!(C,'C', 'N', A, B)
Expand All @@ -186,16 +186,16 @@ Ac_mul_B!(C::StridedMatrix, A::StridedVecOrMat, B::StridedVecOrMat) = generic_ma
A_mul_Bc{T<:BlasFloat,S<:BlasReal}(A::StridedMatrix{T}, B::StridedMatrix{S}) = A_mul_Bt(A, B)
A_mul_Bc!{T<:BlasFloat,S<:BlasReal}(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{S}) = A_mul_Bt!(C, A, B)
function A_mul_Bc{T,S}(A::StridedMatrix{T}, B::StridedMatrix{S})
TS = promote_type(arithtype(T),arithtype(S))
TS = promote_op(MulFun(),arithtype(T),arithtype(S))
A_mul_Bc!(similar(B,TS,(size(A,1),size(B,1))),A,B)
end
A_mul_Bc!{T<:BlasComplex}(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) = is(A,B) ? herk_wrapper!(C, 'N', A) : gemm_wrapper!(C, 'N', 'C', A, B)
A_mul_Bc!(C::StridedMatrix, A::StridedVecOrMat, B::StridedVecOrMat) = generic_matmatmul!(C, 'N', 'C', A, B)

Ac_mul_Bc{T,S}(A::AbstractMatrix{T}, B::StridedMatrix{S}) = Ac_mul_Bc!(similar(B, promote_type(arithtype(T), arithtype(S)), (size(A,2), size(B,1))), A, B)
Ac_mul_Bc{T,S}(A::AbstractMatrix{T}, B::StridedMatrix{S}) = Ac_mul_Bc!(similar(B, promote_op(MulFun(),arithtype(T), arithtype(S)), (size(A,2), size(B,1))), A, B)
Ac_mul_Bc!{T<:BlasFloat}(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) = gemm_wrapper!(C, 'C', 'C', A, B)
Ac_mul_Bc!(C::StridedMatrix, A::StridedVecOrMat, B::StridedVecOrMat) = generic_matmatmul!(C, 'C', 'C', A, B)
Ac_mul_Bt{T,S}(A::AbstractMatrix{T}, B::StridedMatrix{S}) = Ac_mul_Bt(similar(B, promote_type(arithtype(A), arithtype(B)), (size(A,2), size(B,1))), A, B)
Ac_mul_Bt{T,S}(A::AbstractMatrix{T}, B::StridedMatrix{S}) = Ac_mul_Bt(similar(B, promote_op(MulFun(),arithtype(A), arithtype(B)), (size(A,2), size(B,1))), A, B)
Ac_mul_Bt!(C::StridedMatrix, A::StridedVecOrMat, B::StridedVecOrMat) = generic_matmatmul!(C, 'C', 'T', A, B)

# Supporting functions for matrix multiplication
Expand Down Expand Up @@ -425,7 +425,7 @@ end
function generic_matmatmul{T,S}(tA, tB, A::AbstractVecOrMat{T}, B::AbstractMatrix{S})
mA, nA = lapack_size(tA, A)
mB, nB = lapack_size(tB, B)
C = similar(B, promote_type(arithtype(T),arithtype(S)), mA, nB)
C = similar(B, promote_op(MulFun(),arithtype(T),arithtype(S)), mA, nB)
generic_matmatmul!(C, tA, tB, A, B)
end

Expand Down Expand Up @@ -630,7 +630,7 @@ end

# multiply 2x2 matrices
function matmul2x2{T,S}(tA, tB, A::AbstractMatrix{T}, B::AbstractMatrix{S})
matmul2x2!(similar(B, promote_type(T,S), 2, 2), tA, tB, A, B)
matmul2x2!(similar(B, promote_op(MulFun(),T,S), 2, 2), tA, tB, A, B)
end

function matmul2x2!{T,S,R}(C::AbstractMatrix{R}, tA, tB, A::AbstractMatrix{T}, B::AbstractMatrix{S})
Expand Down Expand Up @@ -659,7 +659,7 @@ end

# Multiply 3x3 matrices
function matmul3x3{T,S}(tA, tB, A::AbstractMatrix{T}, B::AbstractMatrix{S})
matmul3x3!(similar(B, promote_type(T,S), 3, 3), tA, tB, A, B)
matmul3x3!(similar(B, promote_op(MulFun(),T,S), 3, 3), tA, tB, A, B)
end

function matmul3x3!{T,S,R}(C::AbstractMatrix{R}, tA, tB, A::AbstractMatrix{T}, B::AbstractMatrix{S})
Expand Down
3 changes: 3 additions & 0 deletions base/promotion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,10 @@ checked_mul(x::Integer, y::Integer) = checked_mul(promote(x,y)...)
# as needed. For example, if you need to provide a custom result type
# for the multiplication of two types,
# promote_op{R<:MyType,S<:MyType}(::MulFun, ::Type{R}, ::Type{S}) = MyType{multype(R,S)}
promote_op(::Any) = (@_pure_meta; Bottom)
promote_op(::Any, T) = (@_pure_meta; T)
promote_op{R,S}(::Any, ::Type{R}, ::Type{S}) = (@_pure_meta; promote_type(R, S))
promote_op(op, T, S, U, V...) = (@_pure_meta; promote_op(op, T, promote_op(op, S, U, V...)))

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

Expand Down
2 changes: 1 addition & 1 deletion base/sparse/sparsematrix.jl
Original file line number Diff line number Diff line change
Expand Up @@ -972,7 +972,7 @@ end # macro
(.-)(A::Number, B::SparseMatrixCSC) = A .- full(B)
( -)(A::Array , B::SparseMatrixCSC) = A - full(B)

(.*)(A::AbstractArray, B::AbstractArray) = broadcast_zpreserving(*, A, B)
(.*)(A::AbstractArray, B::AbstractArray) = broadcast_zpreserving(MulFun(), A, B)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any idea why this didn't need to be Base.MulFun or explicitly imported in base/sparse.jl ? On release-0.4 this causes a test failure unless it's qualified

ERROR: LoadError: On worker 4:
LoadError: test error in expression: full(factorize(A)) ≈ full(factorize(SymTridiagonal(d,e)))
UndefVarError: MulFun not defined
 [inlined code] from sparse/sparsematrix.jl:1026
 in full at linalg/ldlt.jl:82
 in anonymous at test.jl:90
 in do_test at test.jl:50
 [inlined code] from /home/tkelman/Julia/julia-0.4/test/linalg/dense.jl:123
 in anonymous at no file:0
 [inlined code] from essentials.jl:112
 in include_string at loading.jl:266
 in include_from_node1 at ./loading.jl:307
 [inlined code] from util.jl:179
 in runtests at /home/tkelman/Julia/julia-0.4/test/testdefs.jl:7
 in anonymous at multi.jl:908
 in run_work_thunk at multi.jl:646
 [inlined code] from multi.jl:908
 in anonymous at task.jl:63
while loading /home/tkelman/Julia/julia-0.4/test/linalg/dense.jl, in expression starting on line 37
while loading /home/tkelman/Julia/julia-0.4/test/runtests.jl, in expression starting on line 13
        From worker 4:       * linalg/dense

which makes me wonder whether that test or the underlying code paths have changed, or if this line is missing coverage on master?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should definitely be added to the using statements in sparse.jl. Do you want to add that, or should I?

The error is really bizarre: according to https://codecov.io/github/JuliaLang/julia/base/sparse/sparsematrix.jl?ref=9eb74d4730961f52b37ccb8cfdea3b21455e7365#l-976, that line is well-covered.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm changing this line to Base.MulFun in the backport. I'm not sure what's going on with master here but I'm moving on to other backports so not thinking too much about it right this second.

(.*)(A::SparseMatrixCSC, B::Number) = SparseMatrixCSC(A.m, A.n, copy(A.colptr), copy(A.rowval), A.nzval .* B)
(.*)(A::Number, B::SparseMatrixCSC) = SparseMatrixCSC(B.m, B.n, copy(B.colptr), copy(B.rowval), A .* B.nzval)

Expand Down
8 changes: 6 additions & 2 deletions test/arrayops.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1233,7 +1233,7 @@ b = rand(6,7)
# return type declarations (promote_op)
module RetTypeDecl
using Base.Test
import Base: +, *, .*
import Base: +, *, .*, zero

immutable MeterUnits{T,P} <: Number
val::T
Expand All @@ -1243,9 +1243,11 @@ module RetTypeDecl
m = MeterUnits(1.0, 1) # 1.0 meter, i.e. units of length
m2 = MeterUnits(1.0, 2) # 1.0 meter^2, i.e. units of area

(+){T}(x::MeterUnits{T,1}, y::MeterUnits{T,1}) = MeterUnits{T,1}(x.val+y.val)
(+){T,pow}(x::MeterUnits{T,pow}, y::MeterUnits{T,pow}) = MeterUnits{T,pow}(x.val+y.val)
(*){T,pow}(x::Int, y::MeterUnits{T,pow}) = MeterUnits{typeof(x*one(T)),pow}(x*y.val)
(*){T}(x::MeterUnits{T,1}, y::MeterUnits{T,1}) = MeterUnits{T,2}(x.val*y.val)
(.*){T}(x::MeterUnits{T,1}, y::MeterUnits{T,1}) = MeterUnits{T,2}(x.val*y.val)
zero{T,pow}(x::MeterUnits{T,pow}) = MeterUnits{T,pow}(zero(T))

Base.promote_op{R,S}(::Base.AddFun, ::Type{MeterUnits{R,1}}, ::Type{MeterUnits{S,1}}) = MeterUnits{promote_type(R,S),1}
Base.promote_op{R,S}(::Base.MulFun, ::Type{MeterUnits{R,1}}, ::Type{MeterUnits{S,1}}) = MeterUnits{promote_type(R,S),2}
Expand All @@ -1255,6 +1257,8 @@ module RetTypeDecl
@test @inferred([m,m]+m) == [m+m,m+m]
@test @inferred(m.*[m,m]) == [m2,m2]
@test @inferred([m,m].*m) == [m2,m2]
@test @inferred([m 2m; m m]*[m,m]) == [3m2,2m2]
@test @inferred([m m].*[m,m]) == [m2 m2; m2 m2]
end

# range, range ops
Expand Down