Skip to content

Commit

Permalink
simplify rules for mixed-signedness integer arithmetic (#9292) (#23811)
Browse files Browse the repository at this point in the history
- for different-size arguments, the larger type wins
- otherwise the unsigned type wins
  • Loading branch information
JeffBezanson authored Sep 22, 2017
1 parent 9036d30 commit 5af2021
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 18 deletions.
4 changes: 4 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,10 @@ This section lists changes that do not have deprecation warnings.
consistent with its documentation. Previously it would return a `BitArray{0}` for scalar
`x` ([#20233]).

* The rules for mixed-signedness integer arithmetic (e.g. `Int32(1) + UInt64(1)`) have been
simplified: if the arguments have different sizes (in bits), then the type of the larger
argument is used. If the arguments have the same size, the unsigned type is used ([#9292]).

Library improvements
--------------------

Expand Down
33 changes: 15 additions & 18 deletions base/int.jl
Original file line number Diff line number Diff line change
Expand Up @@ -602,24 +602,21 @@ end

## integer promotions ##

promote_rule(::Type{Int8}, ::Type{Int16}) = Int16
promote_rule(::Type{UInt8}, ::Type{UInt16}) = UInt16
promote_rule(::Type{Int32}, ::Type{<:Union{Int8,Int16}}) = Int32
promote_rule(::Type{UInt32}, ::Type{<:Union{UInt8,UInt16}}) = UInt32
promote_rule(::Type{Int64}, ::Type{<:Union{Int8,Int16,Int32}}) = Int64
promote_rule(::Type{UInt64}, ::Type{<:Union{UInt8,UInt16,UInt32}}) = UInt64
promote_rule(::Type{Int128}, ::Type{<:BitSigned64}) = Int128
promote_rule(::Type{UInt128}, ::Type{<:BitUnsigned64}) = UInt128
for T in BitSigned_types
@eval promote_rule(::Type{<:Union{UInt8,UInt16}}, ::Type{$T}) =
$(sizeof(T) < sizeof(Int) ? Int : T)
end
@eval promote_rule(::Type{UInt32}, ::Type{<:Union{Int8,Int16,Int32}}) =
$(Core.sizeof(Int) == 8 ? Int : UInt)
promote_rule(::Type{UInt32}, ::Type{Int64}) = Int64
promote_rule(::Type{UInt64}, ::Type{<:BitSigned64}) = UInt64
promote_rule(::Type{<:Union{UInt32, UInt64}}, ::Type{Int128}) = Int128
promote_rule(::Type{UInt128}, ::Type{<:BitSigned}) = UInt128
# with different sizes, promote to larger type
promote_rule(::Type{Int16}, ::Union{Type{Int8}, Type{UInt8}}) = Int16
promote_rule(::Type{Int32}, ::Union{Type{Int16}, Type{Int8}, Type{UInt16}, Type{UInt8}}) = Int32
promote_rule(::Type{Int64}, ::Union{Type{Int16}, Type{Int32}, Type{Int8}, Type{UInt16}, Type{UInt32}, Type{UInt8}}) = Int64
promote_rule(::Type{Int128}, ::Union{Type{Int16}, Type{Int32}, Type{Int64}, Type{Int8}, Type{UInt16}, Type{UInt32}, Type{UInt64}, Type{UInt8}}) = Int128
promote_rule(::Type{UInt16}, ::Union{Type{Int8}, Type{UInt8}}) = UInt16
promote_rule(::Type{UInt32}, ::Union{Type{Int16}, Type{Int8}, Type{UInt16}, Type{UInt8}}) = UInt32
promote_rule(::Type{UInt64}, ::Union{Type{Int16}, Type{Int32}, Type{Int8}, Type{UInt16}, Type{UInt32}, Type{UInt8}}) = UInt64
promote_rule(::Type{UInt128}, ::Union{Type{Int16}, Type{Int32}, Type{Int64}, Type{Int8}, Type{UInt16}, Type{UInt32}, Type{UInt64}, Type{UInt8}}) = UInt128
# with mixed signedness and same size, Unsigned wins
promote_rule(::Type{UInt8}, ::Type{Int8} ) = UInt8
promote_rule(::Type{UInt16}, ::Type{Int16} ) = UInt16
promote_rule(::Type{UInt32}, ::Type{Int32} ) = UInt32
promote_rule(::Type{UInt64}, ::Type{Int64} ) = UInt64
promote_rule(::Type{UInt128}, ::Type{Int128}) = UInt128

_default_type(::Type{Unsigned}) = UInt
_default_type(::Union{Type{Integer},Type{Signed}}) = Int
Expand Down
22 changes: 22 additions & 0 deletions test/int.jl
Original file line number Diff line number Diff line change
Expand Up @@ -229,3 +229,25 @@ end
@test x[end] == 1180591620717411303424
@test eltype(x) == BigInt
end

# issue #9292
@testset "mixed signedness arithmetic" begin
for T in Base.BitInteger_types
for S in Base.BitInteger_types
a, b = one(T), one(S)
for c in (a+b, a-b, a*b)
if T === S
@test c isa T
elseif sizeof(T) > sizeof(S)
# larger type wins
@test c isa T
elseif sizeof(S) > sizeof(T)
@test c isa S
else
# otherwise Unsigned wins
@test c isa (T <: Unsigned ? T : S)
end
end
end
end
end

0 comments on commit 5af2021

Please sign in to comment.