Fix type instability in convs using CompoundPeriod (#54995)
The functions `toms`, `tons`, and `days` uses `sum` over a vector of
`Period`s to obtain the conversion of a `CompoundPeriod`. However, the
compiler cannot infer the return type because those functions can return
either `Int` or `Float` depending on the type of the `Period`. This PR
forces the result of those functions to be `Float64`, fixing the type
stability.
Before this PR we had:
```julia
julia> using Dates
julia> p = Dates.Second(1) + Dates.Minute(1) + Dates.Year(1)
1 year, 1 minute, 1 second
julia> @code_warntype Dates.tons(p)
MethodInstance for Dates.tons(::Dates.CompoundPeriod)
from tons(c::Dates.CompoundPeriod) @ Dates ~/.julia/juliaup/julia-nightly/share/julia/stdlib/v1.12/Dates/src/periods.jl:458
Arguments
#self#::Core.Const(Dates.tons)
c::Dates.CompoundPeriod
Body::Any
1 ─ %1 = Dates.isempty::Core.Const(isempty)
│ %2 = Base.getproperty(c, :periods)::Vector{Period}
│ %3 = (%1)(%2)::Bool
└── goto #3 if not %3
2 ─ return 0.0
3 ─ %6 = Dates.Float64::Core.Const(Float64)
│ %7 = Dates.sum::Core.Const(sum)
│ %8 = Dates.tons::Core.Const(Dates.tons)
│ %9 = Base.getproperty(c, :periods)::Vector{Period}
│ %10 = (%7)(%8, %9)::Any
│ %11 = (%6)(%10)::Any
└── return %11
julia> @code_warntype Dates.toms(p)
MethodInstance for Dates.toms(::Dates.CompoundPeriod)
from toms(c::Dates.CompoundPeriod) @ Dates ~/.julia/juliaup/julia-nightly/share/julia/stdlib/v1.12/Dates/src/periods.jl:454
Arguments
#self#::Core.Const(Dates.toms)
c::Dates.CompoundPeriod
Body::Any
1 ─ %1 = Dates.isempty::Core.Const(isempty)
│ %2 = Base.getproperty(c, :periods)::Vector{Period}
│ %3 = (%1)(%2)::Bool
└── goto #3 if not %3
2 ─ return 0.0
3 ─ %6 = Dates.Float64::Core.Const(Float64)
│ %7 = Dates.sum::Core.Const(sum)
│ %8 = Dates.toms::Core.Const(Dates.toms)
│ %9 = Base.getproperty(c, :periods)::Vector{Period}
│ %10 = (%7)(%8, %9)::Any
│ %11 = (%6)(%10)::Any
└── return %11
julia> @code_warntype Dates.days(p)
MethodInstance for Dates.days(::Dates.CompoundPeriod)
from days(c::Dates.CompoundPeriod) @ Dates ~/.julia/juliaup/julia-nightly/share/julia/stdlib/v1.12/Dates/src/periods.jl:468
Arguments
#self#::Core.Const(Dates.days)
c::Dates.CompoundPeriod
Body::Any
1 ─ %1 = Dates.isempty::Core.Const(isempty)
│ %2 = Base.getproperty(c, :periods)::Vector{Period}
│ %3 = (%1)(%2)::Bool
└── goto #3 if not %3
2 ─ return 0.0
3 ─ %6 = Dates.Float64::Core.Const(Float64)
│ %7 = Dates.sum::Core.Const(sum)
│ %8 = Dates.days::Core.Const(Dates.days)
│ %9 = Base.getproperty(c, :periods)::Vector{Period}
│ %10 = (%7)(%8, %9)::Any
│ %11 = (%6)(%10)::Any
└── return %11
```
After this PR we have:
```julia
julia> using Dates
julia> p = Dates.Second(1) + Dates.Minute(1) + Dates.Year(1)
1 year, 1 minute, 1 second
julia> @code_warntype Dates.tons(p)
MethodInstance for Dates.tons(::Dates.CompoundPeriod)
from tons(c::Dates.CompoundPeriod) @ Dates ~/.julia/juliaup/julia-nightly/share/julia/stdlib/v1.12/Dates/src/periods.jl:458
Arguments
#self#::Core.Const(Dates.tons)
c::Dates.CompoundPeriod
Body::Float64
1 ─ %1 = Dates.isempty::Core.Const(isempty)
│ %2 = Base.getproperty(c, :periods)::Vector{Period}
│ %3 = (%1)(%2)::Bool
└── goto #3 if not %3
2 ─ return 0.0
3 ─ %6 = Dates.Float64::Core.Const(Float64)
│ %7 = Dates.sum::Core.Const(sum)
│ %8 = Dates.tons::Core.Const(Dates.tons)
│ %9 = Base.getproperty(c, :periods)::Vector{Period}
│ %10 = (%7)(%8, %9)::Any
│ %11 = (%6)(%10)::Any
│ %12 = Dates.Float64::Core.Const(Float64)
│ %13 = Core.typeassert(%11, %12)::Float64
└── return %13
julia> @code_warntype Dates.toms(p)
MethodInstance for Dates.toms(::Dates.CompoundPeriod)
from toms(c::Dates.CompoundPeriod) @ Dates ~/.julia/juliaup/julia-nightly/share/julia/stdlib/v1.12/Dates/src/periods.jl:454
Arguments
#self#::Core.Const(Dates.toms)
c::Dates.CompoundPeriod
Body::Float64
1 ─ %1 = Dates.isempty::Core.Const(isempty)
│ %2 = Base.getproperty(c, :periods)::Vector{Period}
│ %3 = (%1)(%2)::Bool
└── goto #3 if not %3
2 ─ return 0.0
3 ─ %6 = Dates.Float64::Core.Const(Float64)
│ %7 = Dates.sum::Core.Const(sum)
│ %8 = Dates.toms::Core.Const(Dates.toms)
│ %9 = Base.getproperty(c, :periods)::Vector{Period}
│ %10 = (%7)(%8, %9)::Any
│ %11 = (%6)(%10)::Any
│ %12 = Dates.Float64::Core.Const(Float64)
│ %13 = Core.typeassert(%11, %12)::Float64
└── return %13
julia> @code_warntype Dates.days(p)
MethodInstance for Dates.days(::Dates.CompoundPeriod)
from days(c::Dates.CompoundPeriod) @ Dates ~/.julia/juliaup/julia-nightly/share/julia/stdlib/v1.12/Dates/src/periods.jl:468
Arguments
#self#::Core.Const(Dates.days)
c::Dates.CompoundPeriod
Body::Float64
1 ─ %1 = Dates.isempty::Core.Const(isempty)
│ %2 = Base.getproperty(c, :periods)::Vector{Period}
│ %3 = (%1)(%2)::Bool
└── goto #3 if not %3
2 ─ return 0.0
3 ─ %6 = Dates.Float64::Core.Const(Float64)
│ %7 = Dates.sum::Core.Const(sum)
│ %8 = Dates.days::Core.Const(Dates.days)
│ %9 = Base.getproperty(c, :periods)::Vector{Period}
│ %10 = (%7)(%8, %9)::Any
│ %11 = (%6)(%10)::Any
│ %12 = Dates.Float64::Core.Const(Float64)
│ %13 = Core.typeassert(%11, %12)::Float64
└── return %13
```