From e021706206d31b157db73b532c7caf1ee6808785 Mon Sep 17 00:00:00 2001 From: Neven Sajko Date: Mon, 3 Mar 2025 23:02:41 +0100 Subject: [PATCH] `Base`: bootstrap: eliminate `Array`-specific `length` methods Three methods of `length` are deleted. Made possible by moving the following methods to earlier within the bootstrapping: * `size(a::Array)` * `length(t::AbstractArray)` Improves abstract return type inference of `f(x::Array) = length(a)` because the method count is now low enough for the world-splitting optimization to kick in. --- base/abstractarray.jl | 2 +- base/array.jl | 1 - base/essentials.jl | 6 ++---- test/arrayops.jl | 22 ++++++++++++++++++++++ 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 3773502f0cd26..d4d430a5a1811 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -312,7 +312,7 @@ julia> length([1 2; 3 4]) 4 ``` """ -length(t::AbstractArray) = (@inline; prod(size(t))) +length(t::AbstractArray) # `eachindex` is mostly an optimization of `keys` eachindex(itrs...) = keys(itrs...) diff --git a/base/array.jl b/base/array.jl index dd7e4a9d40b37..d983cbb1df1aa 100644 --- a/base/array.jl +++ b/base/array.jl @@ -191,7 +191,6 @@ function size(a::Array, d::Int) sz = getfield(a, :size) return d > length(sz) ? 1 : getfield(sz, d, false) # @inbounds end -size(a::Array) = getfield(a, :size) asize_from(a::Array, n) = n > ndims(a) ? () : (size(a,n), asize_from(a, n+1)...) diff --git a/base/essentials.jl b/base/essentials.jl index e37ce55dac4e6..c998e492469de 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -7,10 +7,8 @@ const Callable = Union{Function,Type} const Bottom = Union{} # Define minimal array interface here to help code used in macros: -length(a::Array{T, 0}) where {T} = 1 -length(a::Array{T, 1}) where {T} = getfield(a, :size)[1] -length(a::Array{T, 2}) where {T} = (sz = getfield(a, :size); sz[1] * sz[2]) -# other sizes are handled by generic prod definition for AbstractArray +size(a::Array) = getfield(a, :size) +length(t::AbstractArray) = (@inline; prod(size(t))) length(a::GenericMemory) = getfield(a, :length) throw_boundserror(A, I) = (@noinline; throw(BoundsError(A, I))) diff --git a/test/arrayops.jl b/test/arrayops.jl index 7d018e991c3a8..a8b9cdef711b6 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -3273,6 +3273,28 @@ end "BoundsError: attempt to access 2×2 Matrix{Float64} at index [10, \"bad index\"]" end +@testset "return type inference of function that calls `length(::Array)`" begin + f(x) = length(x) + @test Int === Base.infer_return_type(f, Tuple{Array}) +end + +@testset "return type inference of `sizeof(::Array)`" begin + @test isconcretetype(Base.infer_return_type(sizeof, Tuple{Array})) +end + +@testset "return type inference of `getindex(::Array, ::Colon)`" begin + f = a -> a[:] + @test Vector == Base.infer_return_type(f, Tuple{Array}) + @test Vector{Float32} === Base.infer_return_type(f, Tuple{Array{Float32}}) +end + +@testset "return type inference of linear `eachindex` for `Array` and `Memory`" begin + f = a -> eachindex(IndexLinear(), a) + for typ in (Array, Memory, Union{Array, Memory}) + @test isconcretetype(Base.infer_return_type(f, Tuple{typ})) + end +end + @testset "inference of Union{T,Nothing} arrays 26771" begin f(a) = (v = [1, nothing]; [v[x] for x in a]) @test only(Base.return_types(f, (Int,))) === Union{Array{Int,0}, Array{Nothing,0}}