Skip to content

Commit 4d9db8b

Browse files
authored
Fix world-age issue with three-argument convfact (JuliaPhysics#791)
* Make convfact(T, s, t) not generated * Only convert convfact to built-in float types * Add test * Rename floattype → convfact_floattype
1 parent 2c09a34 commit 4d9db8b

File tree

2 files changed

+18
-6
lines changed

2 files changed

+18
-6
lines changed

src/conversion.jl

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,10 @@ convfact(s::Units{S}, t::Units{S}) where {S} = 1
5050
convfact(T::Type, s::Units, t::Units)
5151
Returns the appropriate conversion factor from unit `t` to unit `s` for the number type `T`.
5252
"""
53-
@generated function convfact(::Type{T}, s::Units, t::Units) where T
54-
cf = convfact(s(), t())
53+
function convfact(::Type{T}, s::Units, t::Units) where T
54+
cf = convfact(s, t)
5555
if cf isa AbstractFloat
56-
F = floattype(T)
56+
F = convfact_floattype(T)
5757
# Since conversion factors only have Float64 precision,
5858
# there is no point in converting to BigFloat
5959
convert(F == BigFloat ? Float64 : F, cf)
@@ -62,17 +62,20 @@ Returns the appropriate conversion factor from unit `t` to unit `s` for the numb
6262
end
6363
end
6464

65-
function floattype(::Type{T}) where T
65+
function convfact_floattype(::Type{T}) where T
6666
# Use try-catch instead of hasmethod because a
6767
# fallback method might exist but throw an error
6868
try
69-
F = float(real(T))
70-
F <: AbstractFloat ? F : Float64
69+
_convfact_floattype(float(real(T)))
7170
catch
7271
Float64
7372
end
7473
end
7574

75+
_convfact_floattype(::Type) = Float64
76+
_convfact_floattype(::Type{Float16}) = Float16
77+
_convfact_floattype(::Type{Float32}) = Float32
78+
7679
"""
7780
uconvert(a::Units, x::Quantity{T,D,U}) where {T,D,U}
7881
Convert a [`Unitful.Quantity`](@ref) to different units. The conversion will

test/runtests.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,14 @@ Base.:*(x::ErrReal, y::Float64) = x.num * y
128128
Base.real(x::ErrReal) = error("real not defined")
129129
Base.float(x::ErrReal) = error("float not defined")
130130

131+
# A number type for which `real` and `float` do not return a built-in type
132+
struct MyFloat64 <: AbstractFloat
133+
num::Float64
134+
end
135+
Base.:*(x::MyFloat64, y::Float64) = x.num * y
136+
# Base.real(x::MyFloat) = x
137+
# Base.float(x::MyFloat) = x
138+
131139
@testset "Conversion" begin
132140
@testset "> Unitless ↔ unitful conversion" begin
133141
@test_throws DimensionError convert(typeof(3m), 1)
@@ -286,6 +294,7 @@ Base.float(x::ErrReal) = error("float not defined")
286294
@test Unitful.numtype(uconvert(°, (Float16(2+ im) * rad)) === ComplexF16
287295
@test uconvert(rad, NonReal(360)°) == uconvert(rad, 360°)
288296
@test uconvert(rad, ErrReal(360)°) == uconvert(rad, 360°)
297+
@test uconvert(rad, MyFloat64(360)°) == uconvert(rad, 360°)
289298
# Floating point overflow/underflow in uconvert can happen if the
290299
# conversion factor is large, because uconvert does not cancel
291300
# common basefactors (or just for really large exponents and/or

0 commit comments

Comments
 (0)