diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 067cdd0093174..7a61baf7185df 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -1407,12 +1407,12 @@ 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...))) +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 map!{F}(f::F, A::AbstractArray) = map!(f, A, A) diff --git a/base/arraymath.jl b/base/arraymath.jl index 696ab37b871ab..516fbe2af98ee 100644 --- a/base/arraymath.jl +++ b/base/arraymath.jl @@ -35,30 +35,26 @@ function !(A::AbstractArray{Bool}) end ## Binary arithmetic operators ## -@pure promote_array_type{S<:Number, A<:AbstractArray}(F, ::Type{S}, ::Type{A}) = - promote_array_type(F, S, eltype(A), promote_op(F, S, eltype(A))) -@pure promote_array_type{S<:Number, A<:AbstractArray}(F, ::Type{A}, ::Type{S}) = - promote_array_type(F, S, eltype(A), promote_op(F, eltype(A), S)) -@pure promote_array_type{S, A, P}(F, ::Type{S}, ::Type{A}, ::Type{P}) = P -@pure promote_array_type{S<:Real, A<:AbstractFloat, P}(F, ::Type{S}, ::Type{A}, ::Type{P}) = A -@pure promote_array_type{S<:Integer, A<:Integer, P}(F::typeof(./), ::Type{S}, ::Type{A}, ::Type{P}) = P -@pure promote_array_type{S<:Integer, A<:Integer, P}(F::typeof(.\), ::Type{S}, ::Type{A}, ::Type{P}) = P -@pure promote_array_type{S<:Integer, A<:Integer, P}(F, ::Type{S}, ::Type{A}, ::Type{P}) = A -@pure promote_array_type{S<:Integer, P}(F::typeof(./), ::Type{S}, ::Type{Bool}, ::Type{P}) = P -@pure promote_array_type{S<:Integer, P}(F::typeof(.\), ::Type{S}, ::Type{Bool}, ::Type{P}) = P -@pure promote_array_type{S<:Integer, P}(F, ::Type{S}, ::Type{Bool}, ::Type{P}) = P +promote_array_type(F, ::Type, ::Type, T::Type) = T +promote_array_type{S<:Real, A<:AbstractFloat}(F, ::Type{S}, ::Type{A}, ::Type) = A +promote_array_type{S<:Integer, A<:Integer}(F, ::Type{S}, ::Type{A}, ::Type) = A +promote_array_type{S<:Integer, A<:Integer}(::typeof(./), ::Type{S}, ::Type{A}, T::Type) = T +promote_array_type{S<:Integer, A<:Integer}(::typeof(.\), ::Type{S}, ::Type{A}, T::Type) = T +promote_array_type{S<:Integer}(::typeof(./), ::Type{S}, ::Type{Bool}, T::Type) = T +promote_array_type{S<:Integer}(::typeof(.\), ::Type{S}, ::Type{Bool}, T::Type) = T +promote_array_type{S<:Integer}(F, ::Type{S}, ::Type{Bool}, T::Type) = T for f in (:+, :-, :div, :mod, :&, :|, :$) - @eval ($f){S,T}(A::AbstractArray{S}, B::AbstractArray{T}) = - _elementwise($f, A, B, promote_eltype_op($f, A, B)) + @eval ($f)(A::AbstractArray, B::AbstractArray) = + _elementwise($f, promote_op($f, eltype(A), eltype(B)), A, B) end -function _elementwise{S,T}(op, A::AbstractArray{S}, B::AbstractArray{T}, ::Type{Any}) - promote_shape(A,B) # check size compatibility +function _elementwise(op, ::Type{Any}, A::AbstractArray, B::AbstractArray) + promote_shape(A, B) # check size compatibility return broadcast(op, A, B) end -function _elementwise{S,T,R}(op, A::AbstractArray{S}, B::AbstractArray{T}, ::Type{R}) - F = similar(A, R, promote_shape(A,B)) +function _elementwise(op, T::Type, A::AbstractArray, B::AbstractArray) + F = similar(A, T, promote_shape(A, B)) for (iF, iA, iB) in zip(eachindex(F), eachindex(A), eachindex(B)) @inbounds F[iF] = op(A[iA], B[iB]) end @@ -67,15 +63,21 @@ end for f in (:.+, :.-, :.*, :./, :.\, :.^, :.÷, :.%, :.<<, :.>>, :div, :mod, :rem, :&, :|, :$) @eval begin - function ($f){T}(A::Number, B::AbstractArray{T}) - F = similar(B, promote_array_type($f,typeof(A),typeof(B))) + 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) for (iF, iB) in zip(eachindex(F), eachindex(B)) @inbounds F[iF] = ($f)(A, B[iB]) end return F end - function ($f){T}(A::AbstractArray{T}, B::Number) - F = similar(A, promote_array_type($f,typeof(A),typeof(B))) + 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) for (iF, iA) in zip(eachindex(F), eachindex(A)) @inbounds F[iF] = ($f)(A[iA], B) end diff --git a/base/bitarray.jl b/base/bitarray.jl index 0fc33f46a1e5b..3963c16474255 100644 --- a/base/bitarray.jl +++ b/base/bitarray.jl @@ -1035,18 +1035,29 @@ for f in (:+, :-) return r end end + for (f) in (:.+, :.-) - for (arg1, arg2, T, fargs) in ((:(B::BitArray), :(x::Bool) , Int , :(b, x)), - (:(B::BitArray), :(x::Number) , :(promote_array_type($f, BitArray, typeof(x))), :(b, x)), - (:(x::Bool) , :(B::BitArray), Int , :(x, b)), - (:(x::Number) , :(B::BitArray), :(promote_array_type($f, typeof(x), BitArray)), :(x, b))) + for (arg1, arg2, T, t) in ((:(B::BitArray), :(x::Bool) , Int , (:b, :x)), + (:(B::BitArray), :(x::Number) , :(Bool, typeof(x)), (:b, :x)), + (:(x::Bool) , :(B::BitArray), Int , (:x, :b)), + (:(x::Number) , :(B::BitArray), :(typeof(x), Bool), (:x, :b))) @eval function ($f)($arg1, $arg2) - r = Array{$T}(size(B)) + $(if T === Int + quote + r = Array{Int}(size(B)) + end + else + quote + T = promote_op($f, $(T.args[1]), $(T.args[2])) + T === Any && return [($f)($(t[1]), $(t[2])) for b in B] + r = Array{T}(size(B)) + end + end) bi = start(B) ri = 1 while !done(B, bi) b, bi = next(B, bi) - @inbounds r[ri] = ($f)($fargs...) + @inbounds r[ri] = ($f)($(t[1]), $(t[2])) ri += 1 end return r @@ -1078,9 +1089,8 @@ function div(x::Bool, B::BitArray) end function div(x::Number, B::BitArray) all(B) || throw(DivideError()) - pt = promote_array_type(div, typeof(x), BitArray) y = div(x, true) - reshape(pt[ y for i = 1:length(B) ], size(B)) + return fill(y, size(B)) end function mod(A::BitArray, B::BitArray) @@ -1099,15 +1109,16 @@ function mod(x::Bool, B::BitArray) end function mod(x::Number, B::BitArray) all(B) || throw(DivideError()) - pt = promote_array_type(mod, typeof(x), BitArray) y = mod(x, true) - reshape(pt[ y for i = 1:length(B) ], size(B)) + return fill(y, size(B)) end for f in (:div, :mod) @eval begin function ($f)(B::BitArray, x::Number) - F = Array{promote_array_type($f, BitArray, typeof(x))}(size(B)) + T = promote_op($f, Bool, typeof(x)) + T === Any && return [($f)(b, x) for b in B] + F = Array{T}(size(B)) for i = 1:length(F) F[i] = ($f)(B[i], x) end diff --git a/base/broadcast.jl b/base/broadcast.jl index 937d66375bd9a..e42f2a67edfbc 100644 --- a/base/broadcast.jl +++ b/base/broadcast.jl @@ -3,7 +3,7 @@ module Broadcast using Base.Cartesian -using Base: promote_op, promote_eltype, promote_eltype_op, @get!, _msk_end, unsafe_bitgetindex, linearindices, tail, OneTo, to_shape +using Base: promote_eltype_op, @get!, _msk_end, unsafe_bitgetindex, linearindices, tail, OneTo, to_shape import Base: .+, .-, .*, ./, .\, .//, .==, .<, .!=, .<=, .÷, .%, .<<, .>>, .^ export broadcast, broadcast!, bitbroadcast, dotview export broadcast_getindex, broadcast_setindex! @@ -299,7 +299,7 @@ end ## elementwise operators ## for op in (:÷, :%, :<<, :>>, :-, :/, :\, ://, :^) - @eval $(Symbol(:., op))(A::AbstractArray, B::AbstractArray) = broadcast($(op), A, B) + @eval $(Symbol(:., op))(A::AbstractArray, B::AbstractArray) = broadcast($op, A, B) end .+(As::AbstractArray...) = broadcast(+, As...) .*(As::AbstractArray...) = broadcast(*, As...) diff --git a/base/char.jl b/base/char.jl index 52aa1492e2f86..58481c6d39c2a 100644 --- a/base/char.jl +++ b/base/char.jl @@ -40,10 +40,6 @@ hash(x::Char, h::UInt) = hash_uint64(((UInt64(x)+hashchar_seed)<<32) $ UInt64(h) +(x::Char, y::Integer) = Char(Int32(x) + Int32(y)) +(x::Integer, y::Char) = y + x -Base.promote_op{I<:Integer}(::typeof(-), ::Type{Char}, ::Type{I}) = Char -Base.promote_op{I<:Integer}(::typeof(+), ::Type{Char}, ::Type{I}) = Char -Base.promote_op{I<:Integer}(::typeof(+), ::Type{I}, ::Type{Char}) = Char - bswap(x::Char) = Char(bswap(UInt32(x))) print(io::IO, c::Char) = (write(io, c); nothing) diff --git a/base/complex.jl b/base/complex.jl index da644f9412331..7be18a036f951 100644 --- a/base/complex.jl +++ b/base/complex.jl @@ -804,7 +804,8 @@ big{T<:AbstractFloat,N}(A::AbstractArray{Complex{T},N}) = convert(AbstractArray{ ## promotion to complex ## -promote_array_type{S<:Union{Complex, Real}, AT<:AbstractFloat, P}(F, ::Type{S}, ::Type{Complex{AT}}, ::Type{P}) = Complex{AT} +_default_type(T::Type{Complex}) = Complex{Int} +promote_array_type{S<:Union{Complex, Real}, T<:AbstractFloat}(F, ::Type{S}, ::Type{Complex{T}}, ::Type) = Complex{T} function complex{S<:Real,T<:Real}(A::AbstractArray{S}, B::AbstractArray{T}) if size(A) != size(B); throw(DimensionMismatch()); end diff --git a/base/dates/arithmetic.jl b/base/dates/arithmetic.jl index 4a94fc13df911..94752ffe2390a 100644 --- a/base/dates/arithmetic.jl +++ b/base/dates/arithmetic.jl @@ -94,21 +94,3 @@ end # AbstractArray{TimeType}, AbstractArray{TimeType} (-){T<:TimeType}(x::OrdinalRange{T}, y::OrdinalRange{T}) = collect(x) - collect(y) (-){T<:TimeType}(x::Range{T}, y::Range{T}) = collect(x) - collect(y) - -# promotion rules - -for op in (:+, :-, :.+, :.-) - @eval begin - Base.promote_op{P<:Period}(::typeof($op), ::Type{P}, ::Type{P}) = P - Base.promote_op{P1<:Period,P2<:Period}(::typeof($op), ::Type{P1}, ::Type{P2}) = CompoundPeriod - Base.promote_op{D<:Date}(::typeof($op), ::Type{D}, ::Type{D}) = Day - Base.promote_op{D<:DateTime}(::typeof($op), ::Type{D}, ::Type{D}) = Millisecond - end -end - -for op in (:/, :%, :div, :mod, :./, :.%) - @eval begin - Base.promote_op{P<:Period}(::typeof($op), ::Type{P}, ::Type{P}) = typeof($op(1,1)) - Base.promote_op{P<:Period,R<:Real}(::typeof($op), ::Type{P}, ::Type{R}) = P - end -end diff --git a/base/float.jl b/base/float.jl index 20b7e9a2513ca..01767dd3d4123 100644 --- a/base/float.jl +++ b/base/float.jl @@ -230,6 +230,8 @@ promote_rule(::Type{Float64}, ::Type{Float32}) = Float64 widen(::Type{Float16}) = Float32 widen(::Type{Float32}) = Float64 +_default_type(T::Union{Type{Real},Type{AbstractFloat}}) = Float64 + ## floating point arithmetic ## -(x::Float32) = box(Float32,neg_float(unbox(Float32,x))) -(x::Float64) = box(Float64,neg_float(unbox(Float64,x))) diff --git a/base/int.jl b/base/int.jl index ca3242cc682f5..79cfb0ddafb0b 100644 --- a/base/int.jl +++ b/base/int.jl @@ -305,6 +305,9 @@ promote_rule{T<:BitSigned64}(::Type{UInt64}, ::Type{T}) = UInt64 promote_rule{T<:Union{UInt32, UInt64}}(::Type{T}, ::Type{Int128}) = Int128 promote_rule{T<:BitSigned}(::Type{UInt128}, ::Type{T}) = UInt128 +_default_type(T::Type{Unsigned}) = UInt +_default_type(T::Union{Type{Integer},Type{Signed}}) = Int + ## traits ## typemin(::Type{Int8 }) = Int8(-128) diff --git a/base/irrationals.jl b/base/irrationals.jl index e76f40760c0b9..a5e091f5ca1e3 100644 --- a/base/irrationals.jl +++ b/base/irrationals.jl @@ -10,13 +10,6 @@ promote_rule{s}(::Type{Irrational{s}}, ::Type{Float32}) = Float32 promote_rule{s,t}(::Type{Irrational{s}}, ::Type{Irrational{t}}) = Float64 promote_rule{s,T<:Number}(::Type{Irrational{s}}, ::Type{T}) = promote_type(Float64,T) -promote_op{S<:Irrational,T<:Irrational}(op::Any, ::Type{S}, ::Type{T}) = - promote_op(op, Float64, Float64) -promote_op{S<:Irrational,T<:Number}(op::Any, ::Type{S}, ::Type{T}) = - promote_op(op, Float64, T) -promote_op{S<:Irrational,T<:Number}(op::Any, ::Type{T}, ::Type{S}) = - promote_op(op, T, Float64) - convert(::Type{AbstractFloat}, x::Irrational) = Float64(x) convert(::Type{Float16}, x::Irrational) = Float16(Float32(x)) convert{T<:Real}(::Type{Complex{T}}, x::Irrational) = convert(Complex{T}, convert(T,x)) diff --git a/base/linalg/matmul.jl b/base/linalg/matmul.jl index 6c9117a3cd06e..aa713321a42bb 100644 --- a/base/linalg/matmul.jl +++ b/base/linalg/matmul.jl @@ -76,11 +76,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_op(*,arithtype(T),arithtype(S)) + TS = promote_op(*, 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_op(*,arithtype(T),arithtype(S)) + TS = promote_op(*, 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 @@ -99,22 +99,22 @@ end A_mul_B!(y::AbstractVector, A::AbstractVecOrMat, x::AbstractVector) = generic_matvecmul!(y, 'N', A, x) function At_mul_B{T<:BlasFloat,S}(A::StridedMatrix{T}, x::StridedVector{S}) - TS = promote_op(*,arithtype(T),arithtype(S)) + TS = promote_op(*, 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::AbstractMatrix{T}, x::AbstractVector{S}) - TS = promote_op(*,arithtype(T),arithtype(S)) + TS = promote_op(*, 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::AbstractVector, A::AbstractVecOrMat, x::AbstractVector) = generic_matvecmul!(y, 'T', A, x) function Ac_mul_B{T<:BlasFloat,S}(A::StridedMatrix{T}, x::StridedVector{S}) - TS = promote_op(*,arithtype(T),arithtype(S)) + TS = promote_op(*, 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::AbstractMatrix{T}, x::AbstractVector{S}) - TS = promote_op(*,arithtype(T),arithtype(S)) + TS = promote_op(*, arithtype(T), arithtype(S)) Ac_mul_B!(similar(x,TS,size(A,2)), A, x) end @@ -142,14 +142,14 @@ end A_mul_B!(C::AbstractMatrix, A::AbstractVecOrMat, B::AbstractVecOrMat) = generic_matmatmul!(C, 'N', 'N', A, B) function At_mul_B{T,S}(A::AbstractMatrix{T}, B::AbstractMatrix{S}) - TS = promote_op(*,arithtype(T), arithtype(S)) + TS = promote_op(*, 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::AbstractMatrix, A::AbstractVecOrMat, B::AbstractVecOrMat) = generic_matmatmul!(C, 'T', 'N', A, B) function A_mul_Bt{T,S}(A::AbstractMatrix{T}, B::AbstractMatrix{S}) - TS = promote_op(*,arithtype(T), arithtype(S)) + TS = promote_op(*, 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) @@ -166,7 +166,7 @@ end A_mul_Bt!(C::AbstractVecOrMat, A::AbstractVecOrMat, B::AbstractVecOrMat) = generic_matmatmul!(C, 'N', 'T', A, B) function At_mul_Bt{T,S}(A::AbstractMatrix{T}, B::AbstractVecOrMat{S}) - TS = promote_op(*,arithtype(T), arithtype(S)) + TS = promote_op(*, 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) @@ -175,7 +175,7 @@ At_mul_Bt!(C::AbstractMatrix, A::AbstractVecOrMat, B::AbstractVecOrMat) = generi 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::AbstractMatrix{T}, B::AbstractMatrix{S}) - TS = promote_op(*,arithtype(T), arithtype(S)) + TS = promote_op(*, 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) @@ -184,13 +184,14 @@ Ac_mul_B!(C::AbstractMatrix, A::AbstractVecOrMat, B::AbstractVecOrMat) = generic 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::AbstractMatrix{T}, B::AbstractMatrix{S}) - TS = promote_op(*,arithtype(T),arithtype(S)) + TS = promote_op(*, 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::AbstractMatrix, A::AbstractVecOrMat, B::AbstractVecOrMat) = generic_matmatmul!(C, 'N', 'C', A, B) -Ac_mul_Bc{T,S}(A::AbstractMatrix{T}, B::AbstractMatrix{S}) = Ac_mul_Bc!(similar(B, promote_op(*,arithtype(T), arithtype(S)), (size(A,2), size(B,1))), A, B) +Ac_mul_Bc{T,S}(A::AbstractMatrix{T}, B::AbstractMatrix{S}) = + Ac_mul_Bc!(similar(B, promote_op(*, 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::AbstractMatrix, A::AbstractVecOrMat, B::AbstractVecOrMat) = generic_matmatmul!(C, 'C', 'C', A, B) Ac_mul_Bt!(C::AbstractMatrix, A::AbstractVecOrMat, B::AbstractVecOrMat) = generic_matmatmul!(C, 'C', 'T', A, B) @@ -423,7 +424,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_op(*,arithtype(T),arithtype(S)), mA, nB) + C = similar(B, promote_op(*, arithtype(T), arithtype(S)), mA, nB) generic_matmatmul!(C, tA, tB, A, B) end @@ -617,7 +618,7 @@ end # multiply 2x2 matrices function matmul2x2{T,S}(tA, tB, A::AbstractMatrix{T}, B::AbstractMatrix{S}) - matmul2x2!(similar(B, promote_op(*,T,S), 2, 2), tA, tB, A, B) + matmul2x2!(similar(B, promote_op(*, 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}) @@ -646,7 +647,7 @@ end # Multiply 3x3 matrices function matmul3x3{T,S}(tA, tB, A::AbstractMatrix{T}, B::AbstractMatrix{S}) - matmul3x3!(similar(B, promote_op(*,T,S), 3, 3), tA, tB, A, B) + matmul3x3!(similar(B, promote_op(*, 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}) diff --git a/base/number.jl b/base/number.jl index d2d3270f1cfc4..42ffb708736ee 100644 --- a/base/number.jl +++ b/base/number.jl @@ -63,16 +63,4 @@ zero{T<:Number}(::Type{T}) = convert(T,0) one(x::Number) = oftype(x,1) one{T<:Number}(::Type{T}) = convert(T,1) -promote_op{R,S<:Number}(::Type{R}, ::Type{S}) = (@_pure_meta; R) # to fix ambiguities -function promote_op{T<:Number}(op, ::Type{T}) - S = typeof(op(one(T))) - # preserve the most general (abstract) type when possible - return isleaftype(T) ? S : typejoin(S, T) -end -function promote_op{R<:Number,S<:Number}(op, ::Type{R}, ::Type{S}) - T = typeof(op(one(R), one(S))) - # preserve the most general (abstract) type when possible - return isleaftype(R) && isleaftype(S) ? T : typejoin(R, S, T) -end - factorial(x::Number) = gamma(x + 1) # fallback for x not Integer diff --git a/base/pkg/resolve/fieldvalue.jl b/base/pkg/resolve/fieldvalue.jl index a3666388d35a7..fe175ce356b0b 100644 --- a/base/pkg/resolve/fieldvalue.jl +++ b/base/pkg/resolve/fieldvalue.jl @@ -42,7 +42,6 @@ Base.typemin(::Type{FieldValue}) = (x=typemin(Int); y=typemin(VersionWeight); Fi Base.:-(a::FieldValue, b::FieldValue) = FieldValue(a.l0-b.l0, a.l1-b.l1, a.l2-b.l2, a.l3-b.l3, a.l4-b.l4) Base.:+(a::FieldValue, b::FieldValue) = FieldValue(a.l0+b.l0, a.l1+b.l1, a.l2+b.l2, a.l3+b.l3, a.l4+b.l4) -Base.promote_op(::Union{typeof(+), typeof(-)}, ::Type{FieldValue}, ::Type{FieldValue}) = FieldValue function Base.isless(a::FieldValue, b::FieldValue) a.l0 < b.l0 && return true diff --git a/base/promotion.jl b/base/promotion.jl index 778de13c004c9..a3be3c27829d4 100644 --- a/base/promotion.jl +++ b/base/promotion.jl @@ -217,13 +217,38 @@ max(x::Real, y::Real) = max(promote(x,y)...) min(x::Real, y::Real) = min(promote(x,y)...) minmax(x::Real, y::Real) = minmax(promote(x, y)...) -# "Promotion" that takes a function into account. You can override this -# 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}(::typeof(*), ::Type{R}, ::Type{S}) = MyType{multype(R,S)} -promote_op(::Any) = (@_pure_meta; Bottom) -promote_op(::Any, ::Any, ::Any...) = (@_pure_meta; Any) -promote_op{T}(::Type{T}, ::Any) = (@_pure_meta; T) +# "Promotion" that takes a function into account. These are meant to be +# used mainly by broadcast methods, so it is adviced against overriding them +if isdefined(Core, :Inference) + function _promote_op(op, T::Type) + G = Tuple{Generator{Tuple{T},typeof(op)}} + R = Core.Inference.return_type(first, G) + return isleaftype(R) ? R : Any + end + function _promote_op(op, R::Type, S::Type) + 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 + end +else + _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) + T = _promote_op(f, _default_type(S)) + return isleaftype(S) ? T : typejoin(S, T) +end +function promote_op(f, R::Type, S::Type) + 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) +end ## catch-alls to prevent infinite recursion when definitions are missing ## diff --git a/doc/devdocs/promote-op.rst b/doc/devdocs/promote-op.rst deleted file mode 100644 index 53a5a93768549..0000000000000 --- a/doc/devdocs/promote-op.rst +++ /dev/null @@ -1,36 +0,0 @@ -.. currentmodule:: Base - -.. _devdocs-promote-op: - -Operator-sensitive promotion -============================ - -In certain cases, the :ref:`simple rules for promotion -` may not be sufficient. For example, consider a -type that can represent an object with physical units, here restricted -to a single unit like "meter":: - - immutable MeterUnits{T,P} <: Number - val::T - end - MeterUnits{T}(val::T, pow::Int) = MeterUnits{T,pow}(val) - - 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 - -Now let's define the operations ``+`` and ``*`` for these objects: -``m+m`` should have the type of ``m`` but ``m*m`` should have the type -of ``m2``. When the result type depends on the operation, and not -just the input types, ``promote_rule`` will be inadequate. - -Fortunately, it's possible to provide such definitions via ``promote_op``:: - - Base.promote_op{R,S}(::typeof(+), ::Type{MeterUnits{R,1}}, ::Type{MeterUnits{S,1}}) = MeterUnits{promote_type(R,S),1} - Base.promote_op{R,S}(::typeof(*), ::Type{MeterUnits{R,1}}, ::Type{MeterUnits{S,1}}) = MeterUnits{promote_type(R,S),2} - Base.promote_op{R,S}(::typeof(.*), ::Type{MeterUnits{R,1}}, ::Type{MeterUnits{S,1}}) = MeterUnits{promote_type(R,S),2} - -The first one defines the promotion rule for ``+``, and the second one -for ``*``. - -It's worth noting that as julia's internal representation of functions -evolves, this interface may change in a future version of Julia. diff --git a/test/arrayops.jl b/test/arrayops.jl index 92549881f665b..b52f04e4a0bda 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -1424,7 +1424,6 @@ b = rand(6,7) @test_throws ArgumentError copy!(a,2:3,1:3,b,1:5,2:7) @test_throws ArgumentError Base.copy_transpose!(a,2:3,1:3,b,1:5,2:7) -# return type declarations (promote_op) module RetTypeDecl using Base.Test import Base: +, *, .*, convert @@ -1442,7 +1441,6 @@ module RetTypeDecl (*){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) convert{T,pow}(::Type{MeterUnits{T,pow}}, y::Real) = MeterUnits{T,pow}(convert(T,y)) - Base.promote_op{R,S}(::typeof(*), ::Type{MeterUnits{R,1}}, ::Type{MeterUnits{S,1}}) = MeterUnits{promote_type(R,S),2} @test @inferred(m+[m,m]) == [m+m,m+m] @test @inferred([m,m]+m) == [m+m,m+m] diff --git a/test/broadcast.jl b/test/broadcast.jl index 70b2b39beb3fc..c4ff2cc43f98a 100644 --- a/test/broadcast.jl +++ b/test/broadcast.jl @@ -224,12 +224,11 @@ let x = sin.(1:10) @test sin.(atan2.(x, 3.7)) == broadcast(x -> sin(atan2(x,3.7)), x) @test atan2.(x, 3.7) == broadcast(x -> atan2(x,3.7), x) == broadcast(atan2, x, 3.7) end -# Use side effects to check for loop fusion. Note that, due to #17314, -# a broadcasted function is currently called an extra time with an argument 1. +# Use side effects to check for loop fusion. let g = Int[] - f17300(x) = begin; push!(g, x); x+1; end + f17300(x) = begin; push!(g, x); x+2; end f17300.(f17300.(f17300.(1:3))) - @test g == [1,2,3, 1,2,3, 2,3,4, 3,4,5] + @test g == [1,3,5, 2,4,6, 3,5,7] end # fusion with splatted args: let x = sin.(1:10), a = [x] @@ -294,3 +293,15 @@ end let foo = [[1,2,3],[4,5,6],[7,8,9]] @test max.(foo...) == broadcast(max, foo...) == [7,8,9] end + +# Issue 17314 +@test broadcast(x->log(log(log(x))), [1000]) == [log(log(log(1000)))] +let f17314 = x -> x < 0 ? false : x + @test eltype(broadcast(f17314, 1:3)) === Int + @test eltype(broadcast(f17314, -1:1)) === Integer + @test eltype(broadcast(f17314, Int[])) === Union{} +end +let io = IOBuffer() + broadcast(x->print(io,x), 1:5) # broadcast with side effects + @test takebuf_array(io) == [0x31,0x32,0x33,0x34,0x35] +end diff --git a/test/linalg/matmul.jl b/test/linalg/matmul.jl index 44bb9a6afa85b..4755f1d9ddd64 100644 --- a/test/linalg/matmul.jl +++ b/test/linalg/matmul.jl @@ -320,10 +320,10 @@ end immutable RootInt i::Int end -import Base: *, transpose, promote_op +import Base: *, transpose (*)(x::RootInt, y::RootInt) = x.i*y.i transpose(x::RootInt) = x -promote_op(::typeof(*), ::Type{RootInt}, ::Type{RootInt}) = Int +@test Base.promote_op(*, RootInt, RootInt) === Int a = [RootInt(3)] C = [0] diff --git a/test/numbers.jl b/test/numbers.jl index 8ef819c0685ae..a0ccc138e776f 100644 --- a/test/numbers.jl +++ b/test/numbers.jl @@ -2791,21 +2791,21 @@ let types = (Base.BitInteger_types..., BigInt, Bool, Complex{Int}, Complex{UInt}, Complex32, Complex64, Complex128) for S in types for op in (+, -) - T = @inferred Base.promote_op(op, S) + T = @inferred Base._promote_op(op, S) t = @inferred op(one(S)) @test T === typeof(t) end - end - - @test @inferred(Base.promote_op(!, Bool)) === Bool - for R in types, S in types - for op in (+, -, *, /, ^) - T = @inferred Base.promote_op(op, R, S) - t = @inferred op(one(R), one(S)) - @test T === typeof(t) + for R in types + for op in (+, -, *, /, ^) + T = @inferred Base._promote_op(op, S, R) + t = @inferred op(one(S), one(R)) + @test T === typeof(t) + end end end + + @test @inferred(Base._promote_op(!, Bool)) === Bool end let types = (Base.BitInteger_types..., BigInt, Bool, @@ -2813,23 +2813,23 @@ let types = (Base.BitInteger_types..., BigInt, Bool, Float16, Float32, Float64, BigFloat) for S in types, T in types for op in (<, >, <=, >=, (==)) - @test @inferred(Base.promote_op(op, S, T)) === Bool + @test @inferred(Base._promote_op(op, S, T)) === Bool end end end let types = (Base.BitInteger_types..., BigInt, Bool) for S in types - T = @inferred Base.promote_op(~, S) + T = @inferred Base._promote_op(~, S) t = @inferred ~one(S) @test T === typeof(t) - end - for S in types, T in types - for op in (&, |, <<, >>, (>>>), %, ÷) - T = @inferred Base.promote_op(op, S, T) - t = @inferred op(one(S), one(T)) - @test T === typeof(t) + for R in types + for op in (&, |, <<, >>, (>>>), %, ÷) + T = @inferred Base._promote_op(op, S, R) + t = @inferred op(one(S), one(R)) + @test T === typeof(t) + end end end end