Skip to content

Commit cd30223

Browse files
authored
Merge pull request #84 from SymbolicML/numeric-promotion
Fix numeric promotion rules
2 parents f2eea2a + 72b7c22 commit cd30223

File tree

2 files changed

+44
-6
lines changed

2 files changed

+44
-6
lines changed

src/utils.jl

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,29 @@ end
4343
function Base.promote_rule(::Type{<:Quantity{T1,D1}}, ::Type{<:Quantity{T2,D2}}) where {T1,T2,D1,D2}
4444
return Quantity{promote_type(T1,T2),promote_type(D1,D2)}
4545
end
46+
47+
# Define promotion rules for all basic numeric types, individually.
48+
# We don't want to define an opinionated promotion on <:Number,
49+
# or even <:AbstractFloat, as it could conflict with other
50+
# abstract number packages which may try to do the same thing.
51+
# (which would lead to ambiguities)
52+
const BASE_NUMERIC_TYPES = Union{
53+
Bool, Int8, UInt8, Int16, UInt16, Int32, UInt32,
54+
Int64, UInt64, Int128, UInt128, Float16, Float32,
55+
Float64, BigFloat, BigInt, ComplexF16, ComplexF32,
56+
ComplexF64, Complex{BigFloat}, Rational{Int8}, Rational{UInt8},
57+
Rational{Int16}, Rational{UInt16}, Rational{Int32}, Rational{UInt32},
58+
Rational{Int64}, Rational{UInt64}, Rational{Int128}, Rational{UInt128},
59+
Rational{BigInt},
60+
}
61+
for (type, _, _) in ABSTRACT_QUANTITY_TYPES
62+
@eval function Base.promote_rule(::Type{Q}, ::Type{T2}) where {T,D,Q<:$type{T,D},T2<:BASE_NUMERIC_TYPES}
63+
return with_type_parameters(Q, promote_type(T, T2), D)
64+
end
65+
@eval function Base.convert(::Type{Q}, x::BASE_NUMERIC_TYPES) where {T,D,Q<:$type{T,D}}
66+
return new_quantity(Q, convert(T, x), D())
67+
end
68+
end
4669
function Base.promote_rule(::Type{<:AbstractQuantity}, ::Type{<:Number})
4770
return Number
4871
end

test/unittests.jl

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -452,15 +452,30 @@ end
452452
q2 = Quantity(2, mass=1)
453453
@test typeof(promote(q1, q2)) == typeof((q1, q1))
454454

455-
x = [0.5, 0.5u"km/s"]
456-
@test x isa Vector{Number}
457-
458-
x = [0.5, GenericQuantity(0.5u"km/s")]
459-
@test x isa Vector{Any}
455+
q = 0.5u"km/s"
456+
x = [0.5, q]
457+
@test x isa Vector{typeof(q)}
458+
@test x[1] == convert(typeof(q), 0.5)
459+
460+
q = GenericQuantity(0.5u"km/s")
461+
x = [0.5, q]
462+
@test x isa Vector{typeof(q)}
463+
464+
# Promotion with custom numeric type:
465+
@eval struct MyNumber <: Real
466+
x::Float64
467+
end
468+
a = 0.5u"km/s"
469+
b = MyNumber(0.5)
470+
ar = [a, b]
471+
@test ar isa Vector{Number}
472+
@test a === ar[1]
473+
@test b === ar[2]
474+
@test promote_type(MyNumber, typeof(a)) == Number
460475

461476
# Explicit conversion so coverage can see it:
462477
D = DEFAULT_DIM_TYPE
463-
@test promote_type(Quantity{Float32,D}, Float64) == Number
478+
@test promote_type(Quantity{Float32,D}, Float64) == Quantity{Float64,D}
464479
@test promote_type(Quantity{Float32,D}, Quantity{Float64,D}) == Quantity{Float64,D}
465480
@test promote_type(Quantity{Float32,D}, GenericQuantity{Float64,D}) == GenericQuantity{Float64,D}
466481
@test promote_type(GenericQuantity{Float32,D}, GenericQuantity{Float64,D}) == GenericQuantity{Float64,D}

0 commit comments

Comments
 (0)