It does this on v1.8.5 too, and it used to infer Some on v1.4.1 (but not Some{Int}).
It seems the difference starts at _collect(c, itr, ::EltypeUnknown, isz::Union{HasLength,HasShape}) in array.jl.
The _similar_for calls are relevant to empty vectors, and the method signatures are different too.
But the root difference seems to be Base.@default_eltype(Base.Generator(Some,Int[])), which is Any on v1.8.5 but Some on v1.4.1. It used to return Some by accessing the .f field of the Generator, but now it computes Base.promote_typejoin_union(Some) to Any.
promote_typejoin_union(::Type{T}) where T in promotion.jl has many branches but there’s 2 of note there. If T isa DataType, it just returns T, but if T isa UnionAll, it returns Any. Some is not a concrete type, but an iterated union Some{T} where T. I’m not sure why it was decided to remove that type information instead of returning T, but it actually is commented # TODO: compute more precise bounds so that may change eventually.
Aside: I have no idea what Some is for, I read the docs before and didn’t know why there needed to be a distinction between nothing and Some{nothing}. It doesn’t seem necessary for Base.something to find the first argument that isn’t nothing.
macro default_eltype(itr)
I = esc(itr)
return quote
if $I isa Generator && ($I).f isa Type
T = ($I).f
else
T = Core.Compiler.return_type(_iterator_upper_bound, Tuple{typeof($I)})
end
promote_typejoin_union(T)
end
end
we end up in the if branch. This gives Some , which is later promoted to Any. Wouldn’t the problem disappear if ($I).f isa Type were replaced by isconcretetype(($I).f)?
(For concrete types this would still use the assumption that a constructor for a type T returns an element of type T. Maybe this could be fixed by removing the if branch completely.)