Skip to content

Commit

Permalink
use afoldl instead of tail recursion for tuples
Browse files Browse the repository at this point in the history
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
  • Loading branch information
vtjnash committed Mar 12, 2024
1 parent 2a72d65 commit 53de0c9
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 5 deletions.
6 changes: 4 additions & 2 deletions base/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
10 changes: 7 additions & 3 deletions base/promotion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
6 changes: 6 additions & 0 deletions test/compiler/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 53de0c9

Please sign in to comment.