Skip to content

Commit 73240a8

Browse files
committed
Fix promote_op() and some corner-case operators on Number
Use common promote_op() based on one() for all Number types: this fixes promote_op(+, ::Bool), which returned Int, and promote_op(==, ::Complex, ::Complex), which returned Complex{Bool}. Also fix a few corner cases which did not work or were type-instable. Add systematic tests to catch this kind of bug.
1 parent b892a25 commit 73240a8

File tree

8 files changed

+65
-20
lines changed

8 files changed

+65
-20
lines changed

base/bool.jl

-4
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,3 @@ fld(x::Bool, y::Bool) = div(x,y)
7272
cld(x::Bool, y::Bool) = div(x,y)
7373
rem(x::Bool, y::Bool) = y ? false : throw(DivideError())
7474
mod(x::Bool, y::Bool) = rem(x,y)
75-
76-
promote_op(op, ::Type{Bool}, ::Type{Bool}) = typeof(op(true, true))
77-
promote_op(::typeof(^), ::Type{Bool}, ::Type{Bool}) = Bool
78-
promote_op{T<:Integer}(::typeof(^), ::Type{Bool}, ::Type{T}) = Bool

base/complex.jl

+1-12
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,6 @@ promote_rule{T<:Real,S<:Real}(::Type{Complex{T}}, ::Type{S}) =
2626
promote_rule{T<:Real,S<:Real}(::Type{Complex{T}}, ::Type{Complex{S}}) =
2727
Complex{promote_type(T,S)}
2828

29-
promote_op{T<:Real,S<:Real}(op, ::Type{Complex{T}}, ::Type{Complex{S}}) =
30-
Complex{promote_op(op,T,S)}
31-
promote_op{T<:Real,S<:Real}(op, ::Type{Complex{T}}, ::Type{S}) =
32-
Complex{promote_op(op,T,S)}
33-
promote_op{T<:Real,S<:Real}(op, ::Type{T}, ::Type{Complex{S}}) =
34-
Complex{promote_op(op,T,S)}
35-
promote_op{T<:Integer,S<:Integer}(::typeof(^), ::Type{T}, ::Type{Complex{S}}) =
36-
Complex{Float64}
37-
promote_op{T<:Integer,S<:Integer}(::typeof(.^), ::Type{T}, ::Type{Complex{S}}) =
38-
Complex{Float64}
39-
4029
widen{T}(::Type{Complex{T}}) = Complex{widen(T)}
4130

4231
real(z::Complex) = z.re
@@ -461,7 +450,7 @@ function ^{T<:AbstractFloat}(z::Complex{T}, p::Complex{T})
461450
if p==2 #square
462451
zr, zi = reim(z)
463452
x = (zr-zi)*(zr+zi)
464-
y = 2zr*zi
453+
y = T(2)*zr*zi
465454
if isnan(x)
466455
if isinf(y)
467456
x = copysign(zero(T),zr)

base/gmp.jl

+1
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ end
429429
^(x::BigInt , y::Bool ) = y ? x : one(x)
430430
^(x::BigInt , y::Integer) = bigint_pow(x, y)
431431
^(x::Integer, y::BigInt ) = bigint_pow(BigInt(x), y)
432+
^(x::Bool , y::BigInt ) = Base.power_by_squaring(x, y)
432433

433434
function powermod(x::BigInt, p::BigInt, m::BigInt)
434435
r = BigInt()

base/int.jl

-2
Original file line numberDiff line numberDiff line change
@@ -305,8 +305,6 @@ promote_rule{T<:BitSigned64}(::Type{UInt64}, ::Type{T}) = UInt64
305305
promote_rule{T<:Union{UInt32, UInt64}}(::Type{T}, ::Type{Int128}) = Int128
306306
promote_rule{T<:BitSigned}(::Type{UInt128}, ::Type{T}) = UInt128
307307

308-
promote_op{R<:Integer,S<:Integer}(op, ::Type{R}, ::Type{S}) = typeof(op(one(R), one(S)))
309-
310308
## traits ##
311309

312310
typemin(::Type{Int8 }) = Int8(-128)

base/intfuncs.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ ndigits0z(x::Integer) = ndigits0z(unsigned(abs(x)))
186186

187187
const ndigits_max_mul = Core.sizeof(Int) == 4 ? 69000000 : 290000000000000000
188188

189-
function ndigits0znb(n::Int, b::Int)
189+
function ndigits0znb(n::Integer, b::Integer)
190190
d = 0
191191
while n != 0
192192
n = cld(n,b)
@@ -198,7 +198,7 @@ end
198198
function ndigits0z(n::Unsigned, b::Int)
199199
d = 0
200200
if b < 0
201-
d = ndigits0znb(signed(n), b)
201+
d = ndigits0znb(n, b)
202202
else
203203
b == 2 && return (sizeof(n)<<3-leading_zeros(n))
204204
b == 8 && return div((sizeof(n)<<3)-leading_zeros(n)+2,3)

base/promotion.jl

+3
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,9 @@ promote_op{T}(::Type{T}, ::Any) = (@_pure_meta; T)
227227
promote_op{R,S}(::Any, ::Type{R}, ::Type{S}) = (@_pure_meta; promote_type(R, S))
228228
promote_op(op, T, S, U, V...) = (@_pure_meta; promote_op(op, T, promote_op(op, S, U, V...)))
229229

230+
promote_op{T<:Number}(op, ::Type{T}) = typeof(op(one(T)))
231+
promote_op{R<:Number,S<:Number}(op, ::Type{R}, ::Type{S}) = typeof(op(one(R), one(S)))
232+
230233
## catch-alls to prevent infinite recursion when definitions are missing ##
231234

232235
no_op_err(name, T) = error(name," not defined for ",T)

test/broadcast.jl

+5
Original file line numberDiff line numberDiff line change
@@ -196,3 +196,8 @@ end
196196
let a = broadcast(Float32, [3, 4, 5])
197197
@test eltype(a) == Float32
198198
end
199+
200+
# PR 16988
201+
@test Base.promote_op(+, Bool) === Int
202+
@test isa(broadcast(+, true), Array{Int,0})
203+
@test Base.promote_op(Float64, Bool) === Float64

test/numbers.jl

+53
Original file line numberDiff line numberDiff line change
@@ -2742,3 +2742,56 @@ testmi(typemin(Int)+1:typemin(Int)+1000, -100:100)
27422742
@test_throws ArgumentError Base.multiplicativeinverse(0)
27432743
testmi(map(UInt32, 0:1000), map(UInt32, 1:100))
27442744
testmi(typemax(UInt32)-UInt32(1000):typemax(UInt32), map(UInt32, 1:100))
2745+
2746+
# PR #16995
2747+
let types = (Base.BitInteger_types..., BigInt, Bool,
2748+
Rational{Int}, Rational{BigInt},
2749+
Float16, Float32, Float64, BigFloat,
2750+
Complex32, Complex64, Complex128)
2751+
for S in types
2752+
for op in (+, -)
2753+
@test Base.promote_op(op, S) === typeof(op(one(S)))
2754+
@inferred Base.promote_op(op, S)
2755+
@inferred op(one(S))
2756+
end
2757+
end
2758+
2759+
@test Base.promote_op(!, Bool) === Bool
2760+
@inferred Base.promote_op(!, Bool)
2761+
2762+
for S in types, T in types
2763+
for op in (+, -, *, /, ^, (==))
2764+
@test Base.promote_op(op, S, T) === typeof(op(one(S), one(T)))
2765+
@inferred Base.promote_op(op, S, T)
2766+
@inferred op(one(S), one(T))
2767+
end
2768+
end
2769+
end
2770+
2771+
let types = (Base.BitInteger_types..., BigInt, Bool,
2772+
Rational{Int}, Rational{BigInt},
2773+
Float16, Float32, Float64, BigFloat)
2774+
for S in types, T in types
2775+
for op in (<, >, <=, >=)
2776+
@test Base.promote_op(op, S, T) === typeof(op(one(S), one(T)))
2777+
@inferred Base.promote_op(op, S, T)
2778+
@inferred op(one(S), one(T))
2779+
end
2780+
end
2781+
end
2782+
2783+
let types = (Base.BitInteger_types..., BigInt, Bool)
2784+
for S in types
2785+
@test Base.promote_op(~, S) === typeof(~one(S))
2786+
@inferred Base.promote_op(~, S)
2787+
@inferred ~one(S)
2788+
end
2789+
2790+
for S in types, T in types
2791+
for op in (&, |, <<, >>, (>>>), %, ÷)
2792+
@test Base.promote_op(op, S, T) === typeof(op(one(S), one(T)))
2793+
@inferred Base.promote_op(op, S, T)
2794+
@inferred op(one(S), one(T))
2795+
end
2796+
end
2797+
end

0 commit comments

Comments
 (0)