- 
                Notifications
    You must be signed in to change notification settings 
- Fork 13.9k
Fix bugs in Peekable and Flatten when using non-fused iterators #68915
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| The job  Click to expand the log.I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact  | 
| r? @Amanieu | 
| 
 I am concerned that the generated code is now substantially more complicated. Wouldn't it have been better to simply set  All the other changes look fine. | 
| Ping from triage: | 
| Sorry, yep, I'll address them soon. | 
| @Amanieu Thanks for taking a look! I assumed that the generated code for  | 
| @bors r+ | 
| 📌 Commit 8cf33b0 has been approved by  | 
Fix bugs in Peekable and Flatten when using non-fused iterators I fixed a couple of bugs with regard to the `Peekable` and `Flatten`/`FlatMap` iterators when the underlying iterator isn't fused. For testing, I also added a `NonFused` iterator wrapper that panics when `next` or `next_back` is called on an iterator that has returned `None` before, which will hopefully make it easier to spot these mistakes in the future. ### Peekable `Peekable::next_back` was implemented as ```rust self.iter.next_back().or_else(|| self.peeked.take().and_then(|x| x)) ``` which is incorrect because when the `peeked` field is `Some(None)`, then `None` has already been returned from the inner iterator and what it returns from `next_back` can no longer be relied upon. `test_peekable_non_fused` tests this. ### Flatten When a `FlattenCompat` instance only has a `backiter` remaining (i.e. `self.frontiter` is `None` and `self.iter` is empty), then `next` will call `self.iter.next()` every time, so the `iter` field needs to be fused. I fixed it by giving it the type `Fuse<I>` instead of `I`, I think this is the only way to fix it. `test_flatten_non_fused_outer` tests this. Furthermore, previously `FlattenCompat::next` did not set `self.frontiter` to `None` after it returned `None`, which is incorrect when the inner iterator type isn't fused. I just delegated it to `try_fold` because that already handles it correctly. `test_flatten_non_fused_inner` tests this. r? @scottmcm
| ☀️ Test successful - checks-azure | 
Tested on commit rust-lang/rust@d939f70. Direct link to PR: <rust-lang/rust#68915> 💔 rls on linux: test-pass → test-fail (cc @Xanewok).
I fixed a couple of bugs with regard to the
PeekableandFlatten/FlatMapiterators when the underlying iterator isn't fused. For testing, I also added aNonFusediterator wrapper that panics whennextornext_backis called on an iterator that has returnedNonebefore, which will hopefully make it easier to spot these mistakes in the future.Peekable
Peekable::next_backwas implemented aswhich is incorrect because when the
peekedfield isSome(None), thenNonehas already been returned from the inner iterator and what it returns fromnext_backcan no longer be relied upon.test_peekable_non_fusedtests this.Flatten
When a
FlattenCompatinstance only has abackiterremaining (i.e.self.frontiterisNoneandself.iteris empty), thennextwill callself.iter.next()every time, so theiterfield needs to be fused. I fixed it by giving it the typeFuse<I>instead ofI, I think this is the only way to fix it.test_flatten_non_fused_outertests this.Furthermore, previously
FlattenCompat::nextdid not setself.frontitertoNoneafter it returnedNone, which is incorrect when the inner iterator type isn't fused. I just delegated it totry_foldbecause that already handles it correctly.test_flatten_non_fused_innertests this.r? @scottmcm