-
Couldn't load subscription status.
- Fork 13.9k
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
FlattenCompatis 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?