@jyn514 showed an interesting bug:
for x in rx.recv().await {
// ...
}
The sneaky bug is that rx.recv().await returns an Option and Option implements IntoIterator. So instead of calling rx.recv().await repeatedly until it returns None (intended usage), this calls it once and executes the loop body if it's Some(x).
This can easily be written by a newcomer or even an experienced user, it compiles and does an unexpected thing. This is especially easy to write with async code since we don't have async version of for loop and while let is commonly used instead. Option: IntoIterator is useful in generic code or with iterator combinators (e.g. .chain(opt)), but I think using it in a for loop is never intended.
Clippy has a lint for that: for_loops_over_fallibles which, in my opinion, should be uplifted to rustc.
Clippy currently only suggests using if let Some (i.e. preserving code behavior), but we could also suggest using while let Some (i.e. changing code behavior, in recv case to the good) and, in case of for x in i.next() we can suggest for x in i (iterator specific fix).
I'm willing to work on this, but want to first get a signoff that we indeed want to uplift the lint :)
@rustbot label +A-lint +T-compiler +D-newcomer-roadblock
@jyn514 showed an interesting bug:
The sneaky bug is that
rx.recv().awaitreturns anOptionandOptionimplementsIntoIterator. So instead of callingrx.recv().awaitrepeatedly until it returnsNone(intended usage), this calls it once and executes the loop body if it'sSome(x).This can easily be written by a newcomer or even an experienced user, it compiles and does an unexpected thing. This is especially easy to write with
asynccode since we don't haveasyncversion offorloop andwhile letis commonly used instead.Option: IntoIteratoris useful in generic code or with iterator combinators (e.g..chain(opt)), but I think using it in aforloop is never intended.Clippy has a lint for that:
for_loops_over_fallibleswhich, in my opinion, should be uplifted torustc.Clippy currently only suggests using
if let Some(i.e. preserving code behavior), but we could also suggest usingwhile let Some(i.e. changing code behavior, inrecvcase to the good) and, in case offor x in i.next()we can suggestfor x in i(iterator specific fix).I'm willing to work on this, but want to first get a signoff that we indeed want to uplift the lint :)
@rustbot label +A-lint +T-compiler +D-newcomer-roadblock