Skip to content

Commit 2e32141

Browse files
committed
decrease method count for eltype for Tuple, decrease max_methods
The `eltype` function was one of the few functions in the sysimage with a `max_methods` value (the world-splitting threshold) greater than the default. This was a workaround for the unnecessarily large number of methods of `eltype(::Type{<:Tuple})`. The `max_methods` value was increased in PR #48322 to help effect inference. Reduce the number of `eltype(::Type{<:Tuple})` methods, which then also allows keeping the `max_methods` for `eltype` at the default value. The intent here is to guard against unnecessary invalidation of the sysimage or other precompiled code, which might require decreasing the `max_methods` value to the natural minimum for many interface functions, by which I mean "generic function meant to have methods added to it by package authors". I intend to approach this issue in following PRs. See also: PR #57884. Regarding future work: I consider the "natural minimum" value for interface functions taking types to be **two**, because the bottom type subtypes each type. If the interface function doesn't accept types, the natural minimum should be **one**.
1 parent 92bcc94 commit 2e32141

File tree

2 files changed

+12
-19
lines changed

2 files changed

+12
-19
lines changed

base/tuple.jl

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -268,10 +268,18 @@ first(t::Tuple) = t[1]
268268

269269
# eltype
270270

271-
eltype(::Type{Tuple{}}) = Bottom
272271
# the <: here makes the runtime a bit more complicated (needing to check isdefined), but really helps inference
273-
eltype(t::Type{<:Tuple{Vararg{E}}}) where {E} = @isdefined(E) ? (E isa Type ? E : Union{}) : _compute_eltype(t)
274-
eltype(t::Type{<:Tuple}) = _compute_eltype(t)
272+
_eltype_ntuple(t::Type{<:Tuple{Vararg{E}}}) where {E} = @isdefined(E) ? (E isa Type ? E : Union{}) : _compute_eltype(t)
273+
# We'd like to be able to infer eltype(::Tuple), so keep the number of eltype(::Type{<:Tuple}) methods at max_methods!
274+
function eltype(t::Type{<:Tuple})
275+
if t <: Tuple{}
276+
Bottom
277+
elseif t <: NTuple
278+
_eltype_ntuple(t)
279+
else
280+
_compute_eltype(t)
281+
end
282+
end
275283
function _compute_eltype(@nospecialize t)
276284
@_total_meta
277285
has_free_typevars(t) && return Any
@@ -296,21 +304,6 @@ function _compute_eltype(@nospecialize t)
296304
return r
297305
end
298306

299-
# We'd like to be able to infer eltype(::Tuple), which needs to be able to
300-
# look at these four methods:
301-
#
302-
# julia> methods(Base.eltype, Tuple{Type{<:Tuple}})
303-
# 4 methods for generic function "eltype" from Base:
304-
# [1] eltype(::Type{Union{}})
305-
# @ abstractarray.jl:234
306-
# [2] eltype(::Type{Tuple{}})
307-
# @ tuple.jl:199
308-
# [3] eltype(t::Type{<:Tuple{Vararg{E}}}) where E
309-
# @ tuple.jl:200
310-
# [4] eltype(t::Type{<:Tuple})
311-
# @ tuple.jl:209
312-
typeof(function eltype end).name.max_methods = UInt8(4)
313-
314307
# key/val types
315308
keytype(@nospecialize t::Tuple) = keytype(typeof(t))
316309
keytype(@nospecialize T::Type{<:Tuple}) = Int

test/ambiguous.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ end
349349
let need_to_handle_undef_sparam =
350350
Set{Method}(detect_unbound_args(Base; recursive=true, allowed_undefineds))
351351
pop!(need_to_handle_undef_sparam, which(Base._totuple, (Type{Tuple{Vararg{E}}} where E, Any, Any)))
352-
pop!(need_to_handle_undef_sparam, which(Base.eltype, Tuple{Type{Tuple{Any}}}))
352+
pop!(need_to_handle_undef_sparam, which(Base._eltype_ntuple, Tuple{Type{Tuple{Any}}}))
353353
pop!(need_to_handle_undef_sparam, first(methods(Base.same_names)))
354354
@test_broken isempty(need_to_handle_undef_sparam)
355355
pop!(need_to_handle_undef_sparam, which(Base._cat, Tuple{Any, AbstractArray}))

0 commit comments

Comments
 (0)