diff --git a/base/tuple.jl b/base/tuple.jl index ac42c667269e6..62a07f7ecf6a2 100644 --- a/base/tuple.jl +++ b/base/tuple.jl @@ -269,10 +269,18 @@ first(t::Tuple) = t[1] # eltype -eltype(::Type{Tuple{}}) = Bottom # the <: here makes the runtime a bit more complicated (needing to check isdefined), but really helps inference -eltype(t::Type{<:Tuple{Vararg{E}}}) where {E} = @isdefined(E) ? (E isa Type ? E : Union{}) : _compute_eltype(t) -eltype(t::Type{<:Tuple}) = _compute_eltype(t) +_eltype_ntuple(t::Type{<:Tuple{Vararg{E}}}) where {E} = @isdefined(E) ? (E isa Type ? E : Union{}) : _compute_eltype(t) +# We'd like to be able to infer eltype(::Tuple), so keep the number of eltype(::Type{<:Tuple}) methods at max_methods! +function eltype(t::Type{<:Tuple}) + if t <: Tuple{} + Bottom + elseif t <: NTuple + _eltype_ntuple(t) + else + _compute_eltype(t) + end +end function _compute_eltype(@nospecialize t) @_total_meta has_free_typevars(t) && return Any @@ -297,21 +305,6 @@ function _compute_eltype(@nospecialize t) return r end -# We'd like to be able to infer eltype(::Tuple), which needs to be able to -# look at these four methods: -# -# julia> methods(Base.eltype, Tuple{Type{<:Tuple}}) -# 4 methods for generic function "eltype" from Base: -# [1] eltype(::Type{Union{}}) -# @ abstractarray.jl:234 -# [2] eltype(::Type{Tuple{}}) -# @ tuple.jl:199 -# [3] eltype(t::Type{<:Tuple{Vararg{E}}}) where E -# @ tuple.jl:200 -# [4] eltype(t::Type{<:Tuple}) -# @ tuple.jl:209 -typeof(function eltype end).name.max_methods = UInt8(4) - # key/val types keytype(@nospecialize t::Tuple) = keytype(typeof(t)) keytype(@nospecialize T::Type{<:Tuple}) = Int diff --git a/test/ambiguous.jl b/test/ambiguous.jl index 0f29817e74dd5..1ba06b3b13ffc 100644 --- a/test/ambiguous.jl +++ b/test/ambiguous.jl @@ -349,7 +349,7 @@ end let need_to_handle_undef_sparam = Set{Method}(detect_unbound_args(Base; recursive=true, allowed_undefineds)) pop!(need_to_handle_undef_sparam, which(Base._totuple, (Type{Tuple{Vararg{E}}} where E, Any, Any))) - pop!(need_to_handle_undef_sparam, which(Base.eltype, Tuple{Type{Tuple{Any}}})) + pop!(need_to_handle_undef_sparam, which(Base._eltype_ntuple, Tuple{Type{Tuple{Any}}})) pop!(need_to_handle_undef_sparam, first(methods(Base.same_names))) @test_broken isempty(need_to_handle_undef_sparam) pop!(need_to_handle_undef_sparam, which(Base._cat, Tuple{Any, AbstractArray}))