From f9db5d91ca55bc0f9ef487ec114fda6324f19965 Mon Sep 17 00:00:00 2001 From: Martin Holters Date: Fri, 11 Feb 2022 12:15:08 +0100 Subject: [PATCH] Reduce number of `getindex(::Type, ...)` methods Previously, there were special cases for `T[]`, `T[a]`, `T[a,b]` and `T[a,b,c]`. Together with the general case for more elements, that meant five methods to consider in cases like `T[x...]` where the length of `x` was not known at compile time. That was beyond the inference limit and such a call would be inferred as `Any`. So this change gets rid of all the special cases. The loop-based general case worked well if all arguments were of the same type, but otherwise suffered from type-instability inside the loop. Without the special cases for low element count this would be hit more often, so for the non-homogenous case, the loop is replaced with a call to `afoldl` that basically unrolls the loop for up to 32 elements. --- base/array.jl | 17 ++++++++++------- test/arrayops.jl | 4 +++- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/base/array.jl b/base/array.jl index cf5bbc05e412a..b8ad7e137f25e 100644 --- a/base/array.jl +++ b/base/array.jl @@ -402,17 +402,20 @@ julia> getindex(Int8, 1, 2, 3) """ function getindex(::Type{T}, vals...) where T a = Vector{T}(undef, length(vals)) - @inbounds for i = 1:length(vals) - a[i] = vals[i] + if vals isa NTuple + @inbounds for i in 1:length(vals) + a[i] = vals[i] + end + else + # use afoldl to avoid type instability inside loop + afoldl(1, vals...) do i, v + @inbounds a[i] = v + return i + 1 + end end return a end -getindex(::Type{T}) where {T} = (@inline; Vector{T}()) -getindex(::Type{T}, x) where {T} = (@inline; a = Vector{T}(undef, 1); @inbounds a[1] = x; a) -getindex(::Type{T}, x, y) where {T} = (@inline; a = Vector{T}(undef, 2); @inbounds (a[1] = x; a[2] = y); a) -getindex(::Type{T}, x, y, z) where {T} = (@inline; a = Vector{T}(undef, 3); @inbounds (a[1] = x; a[2] = y; a[3] = z); a) - function getindex(::Type{Any}, @nospecialize vals...) a = Vector{Any}(undef, length(vals)) @inbounds for i = 1:length(vals) diff --git a/test/arrayops.jl b/test/arrayops.jl index 84b0e7d259f45..b2badb66ce93d 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -2318,10 +2318,12 @@ let A = zeros(Int, 2, 2), B = zeros(Float64, 2, 2) f40() = Float64[A A] f41() = [A B] f42() = Int[A B] + f43() = Int[A...] + f44() = Float64[A..., B...] for f in [f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, - f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42] + f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42, f43, f44] @test isconcretetype(Base.return_types(f, ())[1]) end end