From df28bf7c3df5e5f2e456e4cf6a39b62ffb3f2cbd Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 12 Mar 2024 14:30:20 -0400 Subject: [PATCH] use afoldl instead of tail recursion for tuples (#53665) It is easy to accidentally call these functions (they are used by vcat, which is syntax) with very long lists of values, causing inference to crash and take a long time. The `afoldl` function can handle that very well however, while naive recursion did not. Fixes #53585 --- base/abstractarray.jl | 6 ++++-- base/promotion.jl | 10 +++++++--- test/compiler/inference.jl | 6 ++++++ 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 9042e5f81e462..cef81d6925284 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -1650,13 +1650,15 @@ eltypeof(x::AbstractArray) = eltype(x) promote_eltypeof() = error() promote_eltypeof(v1) = eltypeof(v1) -promote_eltypeof(v1, vs...) = promote_type(eltypeof(v1), promote_eltypeof(vs...)) +promote_eltypeof(v1, v2) = promote_type(eltypeof(v1), eltypeof(v2)) +promote_eltypeof(v1, v2, vs...) = (@inline; afoldl(((::Type{T}, y) where {T}) -> promote_type(T, eltypeof(y)), promote_eltypeof(v1, v2), vs...)) promote_eltypeof(v1::T, vs::T...) where {T} = eltypeof(v1) promote_eltypeof(v1::AbstractArray{T}, vs::AbstractArray{T}...) where {T} = T promote_eltype() = error() promote_eltype(v1) = eltype(v1) -promote_eltype(v1, vs...) = promote_type(eltype(v1), promote_eltype(vs...)) +promote_eltype(v1, v2) = promote_type(eltype(v1), eltype(v2)) +promote_eltype(v1, v2, vs...) = (@inline; afoldl(((::Type{T}, y) where {T}) -> promote_type(T, eltype(y)), promote_eltype(v1, v2), vs...)) promote_eltype(v1::T, vs::T...) where {T} = eltype(T) promote_eltype(v1::AbstractArray{T}, vs::AbstractArray{T}...) where {T} = T diff --git a/base/promotion.jl b/base/promotion.jl index 1d4fea8c404eb..689a4e4be8f39 100644 --- a/base/promotion.jl +++ b/base/promotion.jl @@ -19,7 +19,8 @@ Number """ typejoin() = Bottom typejoin(@nospecialize(t)) = (@_nospecializeinfer_meta; t) -typejoin(@nospecialize(t), ts...) = (@_foldable_meta; @_nospecializeinfer_meta; typejoin(t, typejoin(ts...))) +typejoin(@nospecialize(t), @nospecialize(s), @nospecialize(u)) = (@_foldable_meta; @_nospecializeinfer_meta; typejoin(typejoin(t, s), u)) +typejoin(@nospecialize(t), @nospecialize(s), @nospecialize(u), ts...) = (@_foldable_meta; @_nospecializeinfer_meta; afoldl(typejoin, typejoin(t, s, u), ts...)) function typejoin(@nospecialize(a), @nospecialize(b)) @_foldable_meta @_nospecializeinfer_meta @@ -299,7 +300,8 @@ function promote_type end promote_type() = Bottom promote_type(T) = T -promote_type(T, S, U, V...) = (@inline; promote_type(T, promote_type(S, U, V...))) +promote_type(T, S, U) = (@inline; promote_type(promote_type(T, S), U)) +promote_type(T, S, U, V...) = (@inline; afoldl(promote_type, promote_type(T, S, U), V...)) promote_type(::Type{Bottom}, ::Type{Bottom}) = Bottom promote_type(::Type{T}, ::Type{T}) where {T} = T @@ -373,7 +375,9 @@ function _promote(x::T, y::S) where {T,S} return (convert(R, x), convert(R, y)) end promote_typeof(x) = typeof(x) -promote_typeof(x, xs...) = (@inline; promote_type(typeof(x), promote_typeof(xs...))) +promote_typeof(x, y) = (@inline; promote_type(typeof(x), typeof(y))) +promote_typeof(x, y, z) = (@inline; promote_type(typeof(x), typeof(y), typeof(z))) +promote_typeof(x, y, z, a...) = (@inline; afoldl(((::Type{T}, y) where {T}) -> promote_type(T, typeof(y)), promote_typeof(x, y, z), a...)) function _promote(x, y, z) @inline R = promote_typeof(x, y, z) diff --git a/test/compiler/inference.jl b/test/compiler/inference.jl index d6cd231dfdd58..30c5c306faa94 100644 --- a/test/compiler/inference.jl +++ b/test/compiler/inference.jl @@ -5639,3 +5639,9 @@ end @test issue53590(true, false) == Real @test issue53590(false, false) == Float64 @test issue53590(false, true) == Real + +# issue #53585 +let t = ntuple(i -> i % 8 == 1 ? Int64 : Float64, 4000) + @test only(Base.return_types(Base.promote_typeof, t)) == Type{Float64} + @test only(Base.return_types(vcat, t)) == Vector{Float64} +end