diff --git a/NEWS.md b/NEWS.md index 01eebbdef9a66..3075be411973e 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1147,6 +1147,9 @@ Deprecated or removed * `signif` has been deprecated in favor of the `sigdigits` keyword argument to `round`. + * The fallback definition of `eltype` that returned `Any` for any type is deprecated. + Code should be restructured to avoid calling `eltype` on types that might not support it ([#26852]). + Command-line option changes --------------------------- diff --git a/base/abstractdict.jl b/base/abstractdict.jl index 040b6e07d5ac4..c0723b1bed0b9 100644 --- a/base/abstractdict.jl +++ b/base/abstractdict.jl @@ -586,7 +586,7 @@ end function IdDict(kv) try - dict_with_eltype((K, V) -> IdDict{K, V}, kv, eltype(kv)) + dict_with_eltype((K, V) -> IdDict{K, V}, kv, IteratorEltype(typeof(kv)) isa HasEltype ? eltype(kv) : Any) catch e if !applicable(start, kv) || !all(x->isa(x,Union{Tuple,Pair}),kv) throw(ArgumentError( diff --git a/base/array.jl b/base/array.jl index b5c652c3c8ba6..18169368c3086 100644 --- a/base/array.jl +++ b/base/array.jl @@ -84,7 +84,12 @@ julia> eltype(fill(0x1, (2,2))) UInt8 ``` """ -eltype(::Type) = Any +function eltype(t::Type) + # TODO: change post-0.7 + #throw(MethodError(eltype, (t,))) + depwarn("The fallback definition of `eltype` is deprecated; either define it for your type or avoid calling it on types that might not support it.", :eltype) + return Any +end eltype(::Type{Bottom}) = throw(ArgumentError("Union{} does not have elements")) eltype(x) = eltype(typeof(x)) diff --git a/base/asyncmap.jl b/base/asyncmap.jl index c8fec713bdb2f..cc9ea1d02ed4c 100644 --- a/base/asyncmap.jl +++ b/base/asyncmap.jl @@ -401,7 +401,8 @@ end # pass-through iterator traits to the iterable # on which the mapping function is being applied -IteratorSize(itr::AsyncGenerator) = SizeUnknown() +IteratorSize(::Type{AsyncGenerator}) = SizeUnknown() +IteratorEltype(::Type{AsyncGenerator}) = EltypeUnknown() size(itr::AsyncGenerator) = size(itr.collector.enumerator) length(itr::AsyncGenerator) = length(itr.collector.enumerator) diff --git a/base/compiler/abstractinterpretation.jl b/base/compiler/abstractinterpretation.jl index 68299eb5385cb..c1ac38d46097d 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/base/compiler/abstractinterpretation.jl @@ -350,7 +350,7 @@ function precise_container_type(@nospecialize(arg), @nospecialize(typ), vtypes:: else return Any[ p for p in tti0.parameters ] end - elseif tti0 <: Array + elseif tti0 isa Type{<:Array{T}} where T return Any[Vararg{eltype(tti0)}] else return Any[abstract_iteration(typ, vtypes, sv)] diff --git a/base/dict.jl b/base/dict.jl index 61bc06a2f90de..3a4925c149213 100644 --- a/base/dict.jl +++ b/base/dict.jl @@ -134,7 +134,7 @@ Dict(ps::Pair...) = Dict(ps) function Dict(kv) try - dict_with_eltype((K, V) -> Dict{K, V}, kv, eltype(kv)) + dict_with_eltype((K, V) -> Dict{K, V}, kv, IteratorEltype(typeof(kv)) isa HasEltype ? eltype(kv) : Any) catch e if !applicable(start, kv) || !all(x->isa(x,Union{Tuple,Pair}),kv) throw(ArgumentError("Dict(kv): kv needs to be an iterator of tuples or pairs")) diff --git a/base/error.jl b/base/error.jl index 35cde7fc8afa9..fa117f6fc016f 100644 --- a/base/error.jl +++ b/base/error.jl @@ -176,6 +176,7 @@ function next(ebo::ExponentialBackOff, state) end done(ebo::ExponentialBackOff, state) = state[1]<1 length(ebo::ExponentialBackOff) = ebo.n +eltype(::Type{ExponentialBackOff}) = Float64 """ retry(f::Function; delays=ExponentialBackOff(), check=nothing) -> Function diff --git a/base/essentials.jl b/base/essentials.jl index b09df65a0e52e..e23bd5e9155ed 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -533,6 +533,7 @@ lastindex(v::SimpleVector) = length(v) start(v::SimpleVector) = 1 next(v::SimpleVector,i) = (v[i],i+1) done(v::SimpleVector,i) = (length(v) < i) +eltype(::Type{SimpleVector}) = Any keys(v::SimpleVector) = OneTo(length(v)) isempty(v::SimpleVector) = (length(v) == 0) axes(v::SimpleVector) = (OneTo(length(v)),) diff --git a/base/iterators.jl b/base/iterators.jl index 59fa36816cbac..32443352a81b9 100644 --- a/base/iterators.jl +++ b/base/iterators.jl @@ -233,10 +233,8 @@ size(v::Pairs) = size(v.itr) end @inline done(v::Pairs, state) = done(v.itr, state) -eltype(::Type{Pairs{K, V}}) where {K, V} = Pair{K, V} - -IteratorSize(::Type{Pairs{<:Any, <:Any, I}}) where {I} = IteratorSize(I) -IteratorEltype(::Type{Pairs{<:Any, <:Any, I}}) where {I} = IteratorEltype(I) +IteratorSize(::Type{<:Pairs{<:Any, <:Any, I}}) where {I} = IteratorSize(I) +IteratorEltype(::Type{<:Pairs{<:Any, <:Any, I}}) where {I} = IteratorEltype(I) reverse(v::Pairs) = Pairs(v.data, reverse(v.itr)) @@ -472,11 +470,11 @@ start(i::Rest) = i.st @propagate_inbounds next(i::Rest, st) = next(i.itr, st) done(i::Rest, st) = done(i.itr, st) -eltype(::Type{Rest{I}}) where {I} = eltype(I) -IteratorEltype(::Type{Rest{I,S}}) where {I,S} = IteratorEltype(I) +eltype(::Type{<:Rest{I}}) where {I} = eltype(I) +IteratorEltype(::Type{<:Rest{I}}) where {I} = IteratorEltype(I) rest_iteratorsize(a) = SizeUnknown() rest_iteratorsize(::IsInfinite) = IsInfinite() -IteratorSize(::Type{Rest{I,S}}) where {I,S} = rest_iteratorsize(IteratorSize(I)) +IteratorSize(::Type{<:Rest{I}}) where {I} = rest_iteratorsize(IteratorSize(I)) # Count -- infinite counting @@ -897,7 +895,10 @@ flatten_iteratorsize(::Union{HasShape, HasLength}, ::Type{<:Tuple}) = SizeUnknow flatten_iteratorsize(::Union{HasShape, HasLength}, ::Type{<:Number}) = HasLength() flatten_iteratorsize(a, b) = SizeUnknown() -IteratorSize(::Type{Flatten{I}}) where {I} = flatten_iteratorsize(IteratorSize(I), eltype(I)) +_flatten_iteratorsize(sz, ::EltypeUnknown, I) = SizeUnknown() +_flatten_iteratorsize(sz, ::HasEltype, I) = flatten_iteratorsize(sz, eltype(I)) + +IteratorSize(::Type{Flatten{I}}) where {I} = _flatten_iteratorsize(IteratorSize(I), IteratorEltype(I), I) function flatten_length(f, T::Type{<:NTuple{N,Any}}) where {N} fieldcount(T)*length(f.it) @@ -968,6 +969,8 @@ function IteratorSize(::Type{PartitionIterator{T}}) where {T} partition_iteratorsize(IteratorSize(T)) end +IteratorEltype(::Type{<:PartitionIterator{T}}) where {T} = IteratorEltype(T) + function length(itr::PartitionIterator) l = length(itr.c) return div(l, itr.n) + ((mod(l, itr.n) > 0) ? 1 : 0) diff --git a/base/reflection.jl b/base/reflection.jl index 18e675a25d130..4697cd2452a8a 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -684,6 +684,7 @@ isempty(m::MethodList) = isempty(m.ms) start(m::MethodList) = start(m.ms) done(m::MethodList, s) = done(m.ms, s) next(m::MethodList, s) = next(m.ms, s) +eltype(::Type{MethodList}) = Method function MethodList(mt::Core.MethodTable) ms = Method[] diff --git a/base/reshapedarray.jl b/base/reshapedarray.jl index 3ac1c7cac616f..aebf17bb120e7 100644 --- a/base/reshapedarray.jl +++ b/base/reshapedarray.jl @@ -35,6 +35,7 @@ start(R::ReshapedArrayIterator) = start(R.iter) ReshapedIndex(item), inext end length(R::ReshapedArrayIterator) = length(R.iter) +eltype(::Type{<:ReshapedArrayIterator{I}}) where {I} = @isdefined(I) ? ReshapedIndex{eltype(I)} : Any """ reshape(A, dims...) -> R diff --git a/base/task.jl b/base/task.jl index 9c89a78165c3a..e46f3426049c0 100644 --- a/base/task.jl +++ b/base/task.jl @@ -37,6 +37,7 @@ isempty(c::CompositeException) = isempty(c.exceptions) start(c::CompositeException) = start(c.exceptions) next(c::CompositeException, state) = next(c.exceptions, state) done(c::CompositeException, state) = done(c.exceptions, state) +eltype(::Type{CompositeException}) = Any function showerror(io::IO, ex::CompositeException) if !isempty(ex) diff --git a/base/weakkeydict.jl b/base/weakkeydict.jl index fb153d500d96e..23626c15cdf0d 100644 --- a/base/weakkeydict.jl +++ b/base/weakkeydict.jl @@ -58,7 +58,7 @@ WeakKeyDict(ps::Pair...) = WeakKeyDict{Any,Any}(ps) function WeakKeyDict(kv) try - Base.dict_with_eltype((K, V) -> WeakKeyDict{K, V}, kv, eltype(kv)) + Base.dict_with_eltype((K, V) -> WeakKeyDict{K, V}, kv, IteratorEltype(typeof(kv)) isa HasEltype ? eltype(kv) : Any) catch e if !applicable(start, kv) || !all(x->isa(x,Union{Tuple,Pair}),kv) throw(ArgumentError("WeakKeyDict(kv): kv needs to be an iterator of tuples or pairs")) diff --git a/stdlib/Distributed/src/cluster.jl b/stdlib/Distributed/src/cluster.jl index 4d47d5fcfc2c3..110a6e02f4827 100644 --- a/stdlib/Distributed/src/cluster.jl +++ b/stdlib/Distributed/src/cluster.jl @@ -42,8 +42,7 @@ mutable struct WorkerConfig function WorkerConfig() wc = new() - for n in 1:length(WorkerConfig.types) - T = eltype(fieldtype(WorkerConfig, n)) + for n in 1:fieldcount(WorkerConfig) setfield!(wc, n, nothing) end wc diff --git a/stdlib/Random/src/Random.jl b/stdlib/Random/src/Random.jl index ef79ef62e3138..cc84bb55ae226 100644 --- a/stdlib/Random/src/Random.jl +++ b/stdlib/Random/src/Random.jl @@ -132,7 +132,7 @@ struct SamplerTrivial{T,E} <: Sampler{E} self::T end -SamplerTrivial(x::T) where {T} = SamplerTrivial{T,eltype(T)}(x) +SamplerTrivial(x::T) where {T} = SamplerTrivial{T,Any}(x) Sampler(::AbstractRNG, x, ::Repetition) = SamplerTrivial(x) @@ -144,14 +144,14 @@ struct SamplerSimple{T,S,E} <: Sampler{E} data::S end -SamplerSimple(x::T, data::S) where {T,S} = SamplerSimple{T,S,eltype(T)}(x, data) +SamplerSimple(x::T, data::S) where {T,S} = SamplerSimple{T,S,Any}(x, data) Base.getindex(sp::SamplerSimple) = sp.self # simple sampler carrying a (type) tag T and data struct SamplerTag{T,S,E} <: Sampler{E} data::S - SamplerTag{T}(s::S) where {T,S} = new{T,S,eltype(T)}(s) + SamplerTag{T}(s::S) where {T,S} = new{T,S,Any}(s) end diff --git a/test/iterators.jl b/test/iterators.jl index 801d666e8a105..224211ec1a679 100644 --- a/test/iterators.jl +++ b/test/iterators.jl @@ -66,7 +66,9 @@ end # ---- let s = "hello" _, st = next(s, start(s)) - @test collect(rest(s, st)) == ['e','l','l','o'] + c = collect(rest(s, st)) + @test c == ['e','l','l','o'] + @test c isa Vector{Char} end @test_throws MethodError collect(rest(countfrom(1), 5)) @@ -452,6 +454,7 @@ end @test values(d) == A @test Base.IteratorSize(d) == Base.HasLength() @test Base.IteratorEltype(d) == Base.HasEltype() + @test Base.IteratorSize(pairs([1 2;3 4])) isa Base.HasShape{2} @test isempty(d) || haskey(d, first(keys(d))) @test collect(v for (k, v) in d) == vec(collect(A)) if A isa NamedTuple diff --git a/test/missing.jl b/test/missing.jl index 6825c07bbe74b..7685134272272 100644 --- a/test/missing.jl +++ b/test/missing.jl @@ -358,7 +358,8 @@ end @test collect(x) isa Vector{Int} x = skipmissing(v for v in [missing, 1, missing, 2, 4]) - @test eltype(x) === Any + # TODO: enable in v0.7 + #@test_throws MethodError eltype(x) @test collect(x) == [1, 2, 4] @test collect(x) isa Vector{Int} end