Closed
Description
I would expect the following code to either not compile (because iter
shouldn't implement FusedIterator
) or to not panic (because it does, so its contract should guarantee that calling next after the first None
will always return None
), however it compiles and panics:
use core::iter::FusedIterator;
fn check_is_fused<T, I: Iterator<Item = T> + FusedIterator>(mut i: I) {
while let Some(_) = i.next() {}
assert!(i.next().is_none());
}
struct NonFusedIter(bool);
impl Iterator for NonFusedIter {
type Item = ();
fn next(&mut self) -> Option<Self::Item> {
self.0 = !self.0;
Some(()).filter(|_| !self.0)
}
}
impl DoubleEndedIterator for NonFusedIter {
fn next_back(&mut self) -> Option<Self::Item> {
self.0 = !self.0;
Some(()).filter(|_| !self.0)
}
}
fn main() {
let mut iter = vec![NonFusedIter(true)].into_iter().flatten();
iter.next_back();
check_is_fused(iter);
}
This is caused by the fact that the impl of FusedIterator
for Flatten
only requires the outer iterator to implement FusedIterator
, not the inner one, however the implementation doesn't actually fuse backiter
, which is what causes the assert to fail. The same problem is present for FlatMap
.
Possible solutions:
- Change how
FlattenCompat
is implemented to guarantee it to be fused even if the inner iterators are not fused. This would silently change its behavior, however it wouldn't be a breaking change. - Change the bounds for those impls. This would be a (minor?) breaking change.
Additionally I don't think there's anything that requires the outer iterator to always be manually fused in FlattenCompat
. Should we also change it in the process?