-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Force inference of convert(::Type{T}, ::T) where T
via typeasserts
#46573
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or alternatively, we can add type constraint on the method signatures, e.g. first(r::OneTo{T}) where {T<:Integer} = oneunit(T)
.
And I guess we should do this automatically in inference, i.e. restrict method signatures using struct type information?
The issue with restricting the definition above to e.g.
This would be lovely :) |
That is impossible:
|
I of course agree that it is impossible to have a E.g., I see a method instance for |
Would this work instead for it: diff --git a/base/number.jl b/base/number.jl
index 7436655bfa..77f9eb79fa 100644
--- a/base/number.jl
+++ b/base/number.jl
@@ -4,7 +4,7 @@
# Numbers are convertible
convert(::Type{T}, x::T) where {T<:Number} = x
-convert(::Type{T}, x::Number) where {T<:Number} = T(x)
+convert(::Type{T}, x::Number) where {T<:Number} = T(x)::T
"""
isinteger(x) -> Bool The output looks correct to me for inference of that function for the general case without needing this PR's specific change |
No, we can see those are different:
|
Ah, makes sense: thanks for clarifying. Your Is a test for this, or? |
|
I think it may be worth doing all of them at once, WDYT? $ git grep -n 'convert(.\+\<T('
base/Enums.jl:20:Base.cconvert(::Type{T}, x::Enum{T2}) where {T<:Integer,T2<:Integer} = T(x)
base/array.jl:613:convert(::Type{T}, a::AbstractArray) where {T<:Array} = a isa T ? a : T(a)
base/baseext.jl:19:convert(::Type{T}, arg) where {T<:VecElement} = T(arg)
base/bitarray.jl:580:convert(T::Type{<:BitArray}, a::AbstractArray) = a isa T ? a : T(a)
base/char.jl:184:convert(::Type{T}, x::Number) where {T<:AbstractChar} = T(x)
base/char.jl:185:convert(::Type{T}, x::AbstractChar) where {T<:Number} = T(x)
base/char.jl:186:convert(::Type{T}, c::AbstractChar) where {T<:AbstractChar} = T(c)
base/number.jl:7:convert(::Type{T}, x::Number) where {T<:Number} = T(x)::T
base/pointer.jl:23:convert(::Type{T}, x::Ptr) where {T<:Integer} = T(UInt(x))
base/range.jl:255:convert(::Type{T}, r::AbstractRange) where {T<:AbstractRange} = r isa T ? r : T(r)
base/set.jl:551:convert(::Type{T}, s::AbstractSet) where {T<:AbstractSet} = T(s)
base/strings/basic.jl:232:convert(::Type{T}, s::AbstractString) where {T<:AbstractString} = T(s)::T
base/twiceprecision.jl:273:convert(::Type{T}, x::TwicePrecision) where {T<:Number} = T(x)
doc/src/manual/conversion-and-promotion.md:114:Note that the behavior of `convert(T, x)` appears to be nearly identical to `T(x)`.
doc/src/manual/conversion-and-promotion.md:184:convert(::Type{T}, x::Number) where {T<:Number} = T(x)
stdlib/Dates/src/periods.jl:437: @eval Base.convert(::Type{$T}, x::$Tc) = $T(divexact(value(x), $N))
stdlib/Dates/test/periods.jl:286: Base.convert(::Type{T}, b::Beat) where {T<:Dates.Millisecond} = T(Dates.toms(b))
stdlib/LinearAlgebra/src/bidiag.jl:203:convert(T::Type{<:Bidiagonal}, m::AbstractMatrix) = m isa T ? m : T(m)
stdlib/LinearAlgebra/src/factorization.jl:57:convert(::Type{T}, f::Factorization) where {T<:Factorization} = T(f)
stdlib/LinearAlgebra/src/factorization.jl:59:convert(::Type{T}, f::Factorization) where {T<:AbstractArray} = T(f)
stdlib/LinearAlgebra/src/givens.jl:47:convert(::Type{T}, r::AbstractRotation) where {T<:AbstractRotation} = T(r)
stdlib/LinearAlgebra/src/special.jl:72:convert(T::Type{<:LowerTriangular}, m::Union{LowerTriangular,UnitLowerTriangular}) = m isa T ? m : T(m)
stdlib/LinearAlgebra/src/special.jl:73:convert(T::Type{<:UpperTriangular}, m::Union{UpperTriangular,UnitUpperTriangular}) = m isa T ? m : T(m)
stdlib/LinearAlgebra/src/symmetric.jl:195:convert(T::Type{<:Symmetric}, m::Union{Symmetric,Hermitian}) = m isa T ? m : T(m)
stdlib/LinearAlgebra/src/symmetric.jl:196:convert(T::Type{<:Hermitian}, m::Union{Symmetric,Hermitian}) = m isa T ? m : T(m)
stdlib/LinearAlgebra/test/svd.jl:137: @test convert(Array, usv) ≈ T(asym)
stdlib/SharedArrays/src/SharedArrays.jl:377:convert(T::Type{<:SharedArray}, a::Array) = T(a)
test/atomics.jl:292:Base.convert(T::Type{<:UndefComplex}, S) = T()
test/int.jl:103: @test convert(Unsigned, T(3.0)) === UInt(3)
test/sorting.jl:476: Base.convert(::Type{T_30763{$T}}, n::Integer) = T_30763{$T}($T(n))
test/testhelpers/Furlongs.jl:28:Base.convert(::Type{T}, y::Number) where {T<:Furlong{0}} = T(y)
test/testhelpers/Furlongs.jl:33:Base.convert(::Type{T}, y::Furlong) where {T<:Furlong{0}} = T(y)
test/testhelpers/Furlongs.jl:36:Base.convert(::Type{T}, y::Furlong) where {T<:Furlong} = T(y)
test/testhelpers/OffsetArrays.jl:450:Base.convert(::Type{T}, M::AbstractArray) where {T<:OffsetArray} = M isa T ? M : T(M) |
(or even more broadly, it might apply to any of these methods, or even to any convert method except for Tuples)
|
Okay, that's a much bigger change, yeah 😮. I went ahead and did that in bf242fb, going through them one by one via julia> ms = methods(convert, Tuple{Type{T},T} where T)
julia> for (i,m) in enumerate(ms)
fn = String(m.file)
fn = replace(fn, "/cache/build/default-amdci5-5/julialang/julia-master/usr/share/julia/stdlib/v1.9/"=>"/stdlib/")
b = "/home/tchr/dev/julia" # hardcoded path
if !startswith(fn, "/stdlib/")
fn = "/base/"*fn
end
edit(b * fn, m.line)
end There were two entries in SparseArrays that I didn't look at since they are no longer in Base. This change seems related to the discussion in #42372, so I figured I'd cross-link that. It's not my understanding that this change actually makes a decision on the proposal there, since this only covers |
last(::OneTo{<:Any})
convert(::Type{T}, T) where T
via typeasserts
convert(::Type{T}, T) where T
via typeassertsconvert(::Type{T}, ::T) where T
via typeasserts
There are test-failures related to the new test which I don't fully understand. Instead of always returning Any[Integer, Integer]
Any[Union{}, Main.Furlongs.Furlong{0}, Main.Furlongs.Furlong{0}, Main.Furlongs.Furlong, Any, Any, Any, Main.Furlongs.Furlong, Main.Furlongs.Furlong, Union{}, Union{}, Union{}, Main.Quaternions.Quaternion, Number, Number]
Any[Union{}, Union{}, Union{}, Main.Furlongs.Furlong{0}, Main.Furlongs.Furlong{0}, Main.Furlongs.Furlong, Any, Any, Any, Main.Furlongs.Furlong, Main.Furlongs.Furlong, Number, Union{}, Number]
Any[Main.Quaternions.Quaternion, Number, Number]
Any[Main.Test76Main_LinearAlgebra_generic.TestGeneric.MyDual, Union{}, Union{}, Main.Quaternions.Quaternion, Union{}, Union{}, Main.Furlongs.Furlong{0}, Main.Furlongs.Furlong{0}, Main.Furlongs.Furlong, Any, Any, Any, Main.Furlongs.Furlong, Main.Furlongs.Furlong, Number, Number]
Any[Main.Test67Main_LinearAlgebra_generic.TestGeneric.MyDual, Union{}, Main.Quaternions.Quaternion, Union{}, Union{}, Main.Furlongs.Furlong{0}, Main.Furlongs.Furlong{0}, Main.Furlongs.Furlong, Any, Any, Any, Main.Furlongs.Furlong, Main.Furlongs.Furlong, Number, Union{}, Number] It seems like different |
Those come from some of the testhelper files. That does make this test much less reliable than desired. Let's just drop it? |
Oki, done. |
Gentle bump for this: anything else needed here? |
Duplicates improvement made to Base's Enums: JuliaLang/julia#46573
I was looking at invalidations in StaticArrays and this place came up.
The situation is that there exist some callers of
last
withOneTo{Any}
which gets inferred asAny
. An example isBase.to_shape(::OneTo{<:Any})
(which in turn gets called by some specializations ofsimilar
, which get invalidated by StaticArrays).But the allowable typevars in
OneTo{T}
areT<:Integer
, so we can constrain the result of the access to the field values toInteger
rather thanAny
. This e.g. letsBase.to_shape(::OneTo{<:Any})
infer asInt64
instead ofAny
.I figured I might as well do the same thing for
first(::OneTo)
while I was at it.This seems to cut out roughly 260 invalidations from StaticArrays (~about 50% of current invalidations).