Rollup merge of #99696 - WaffleLapkin:uplift, r=fee1-dead
Uplift `clippy::for_loops_over_fallibles` lint into rustc
This PR, as the title suggests, uplifts [`clippy::for_loops_over_fallibles`] lint into rustc. This lint warns for code like this:
```rust
for _ in Some(1) {}
for _ in Ok::<_, ()>(1) {}
```
i.e. directly iterating over `Option` and `Result` using `for` loop.
There are a number of suggestions that this PR adds (on top of what clippy suggested):
1. If the argument (? is there a better name for that expression) of a `for` loop is a `.next()` call, then we can suggest removing it (or rather replacing with `.by_ref()` to allow iterator being used later)
```rust
for _ in iter.next() {}
// turns into
for _ in iter.by_ref() {}
```
2. (otherwise) We can suggest using `while let`, this is useful for non-iterator, iterator-like things like [async] channels
```rust
for _ in rx.recv() {}
// turns into
while let Some(_) = rx.recv() {}
```
3. If the argument type is `Result<impl IntoIterator, _>` and the body has a `Result<_, _>` type, we can suggest using `?`
```rust
for _ in f() {}
// turns into
for _ in f()? {}
```
4. To preserve the original behavior and clear intent, we can suggest using `if let`
```rust
for _ in f() {}
// turns into
if let Some(_) = f() {}
```
(P.S. `Some` and `Ok` are interchangeable depending on the type)
I still feel that the lint wording/look is somewhat off, so I'll be happy to hear suggestions (on how to improve suggestions :D)!
Resolves #99272
[`clippy::for_loops_over_fallibles`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loops_over_fallibles
This commit is contained in:
commit
7e16f9f1ea
26 changed files with 381 additions and 366 deletions
|
|
@ -1017,7 +1017,7 @@ impl<'a> Children<'a> for HM<'a> {
|
|||
where C: Context + PrePost<Self>, Self: Sized
|
||||
{
|
||||
if let Some(ref hm) = self.contents.get() {
|
||||
for (k, v) in hm.iter().nth(index / 2) {
|
||||
if let Some((k, v)) = hm.iter().nth(index / 2) {
|
||||
[k, v][index % 2].descend_into_self(context);
|
||||
}
|
||||
}
|
||||
|
|
@ -1032,7 +1032,7 @@ impl<'a> Children<'a> for VD<'a> {
|
|||
where C: Context + PrePost<Self>, Self: Sized
|
||||
{
|
||||
if let Some(ref vd) = self.contents.get() {
|
||||
for r in vd.iter().nth(index) {
|
||||
if let Some(r) = vd.iter().nth(index) {
|
||||
r.descend_into_self(context);
|
||||
}
|
||||
}
|
||||
|
|
@ -1047,7 +1047,7 @@ impl<'a> Children<'a> for VM<'a> {
|
|||
where C: Context + PrePost<VM<'a>>
|
||||
{
|
||||
if let Some(ref vd) = self.contents.get() {
|
||||
for (_idx, r) in vd.iter().nth(index) {
|
||||
if let Some((_idx, r)) = vd.iter().nth(index) {
|
||||
r.descend_into_self(context);
|
||||
}
|
||||
}
|
||||
|
|
@ -1062,7 +1062,7 @@ impl<'a> Children<'a> for LL<'a> {
|
|||
where C: Context + PrePost<LL<'a>>
|
||||
{
|
||||
if let Some(ref ll) = self.contents.get() {
|
||||
for r in ll.iter().nth(index) {
|
||||
if let Some(r) = ll.iter().nth(index) {
|
||||
r.descend_into_self(context);
|
||||
}
|
||||
}
|
||||
|
|
@ -1077,7 +1077,7 @@ impl<'a> Children<'a> for BH<'a> {
|
|||
where C: Context + PrePost<BH<'a>>
|
||||
{
|
||||
if let Some(ref bh) = self.contents.get() {
|
||||
for r in bh.iter().nth(index) {
|
||||
if let Some(r) = bh.iter().nth(index) {
|
||||
r.descend_into_self(context);
|
||||
}
|
||||
}
|
||||
|
|
@ -1092,7 +1092,7 @@ impl<'a> Children<'a> for BTM<'a> {
|
|||
where C: Context + PrePost<BTM<'a>>
|
||||
{
|
||||
if let Some(ref bh) = self.contents.get() {
|
||||
for (k, v) in bh.iter().nth(index / 2) {
|
||||
if let Some((k, v)) = bh.iter().nth(index / 2) {
|
||||
[k, v][index % 2].descend_into_self(context);
|
||||
}
|
||||
}
|
||||
|
|
@ -1107,7 +1107,7 @@ impl<'a> Children<'a> for BTS<'a> {
|
|||
where C: Context + PrePost<BTS<'a>>
|
||||
{
|
||||
if let Some(ref bh) = self.contents.get() {
|
||||
for r in bh.iter().nth(index) {
|
||||
if let Some(r) = bh.iter().nth(index) {
|
||||
r.descend_into_self(context);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
// run-pass
|
||||
#![allow(unreachable_code)]
|
||||
#![allow(for_loops_over_fallibles)]
|
||||
#![deny(unused_variables)]
|
||||
|
||||
fn main() {
|
||||
|
|
|
|||
43
src/test/ui/lint/for_loop_over_fallibles.rs
Normal file
43
src/test/ui/lint/for_loop_over_fallibles.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// check-pass
|
||||
|
||||
fn main() {
|
||||
// Common
|
||||
for _ in Some(1) {}
|
||||
//~^ WARN for loop over an `Option`. This is more readably written as an `if let` statement
|
||||
//~| HELP to check pattern in a loop use `while let`
|
||||
//~| HELP consider using `if let` to clear intent
|
||||
for _ in Ok::<_, ()>(1) {}
|
||||
//~^ WARN for loop over a `Result`. This is more readably written as an `if let` statement
|
||||
//~| HELP to check pattern in a loop use `while let`
|
||||
//~| HELP consider using `if let` to clear intent
|
||||
|
||||
// `Iterator::next` specific
|
||||
for _ in [0; 0].iter().next() {}
|
||||
//~^ WARN for loop over an `Option`. This is more readably written as an `if let` statement
|
||||
//~| HELP to iterate over `[0; 0].iter()` remove the call to `next`
|
||||
//~| HELP consider using `if let` to clear intent
|
||||
|
||||
// `Result<impl Iterator, _>`, but function doesn't return `Result`
|
||||
for _ in Ok::<_, ()>([0; 0].iter()) {}
|
||||
//~^ WARN for loop over a `Result`. This is more readably written as an `if let` statement
|
||||
//~| HELP to check pattern in a loop use `while let`
|
||||
//~| HELP consider using `if let` to clear intent
|
||||
}
|
||||
|
||||
fn _returns_result() -> Result<(), ()> {
|
||||
// `Result<impl Iterator, _>`
|
||||
for _ in Ok::<_, ()>([0; 0].iter()) {}
|
||||
//~^ WARN for loop over a `Result`. This is more readably written as an `if let` statement
|
||||
//~| HELP to check pattern in a loop use `while let`
|
||||
//~| HELP consider unwrapping the `Result` with `?` to iterate over its contents
|
||||
//~| HELP consider using `if let` to clear intent
|
||||
|
||||
// `Result<impl IntoIterator>`
|
||||
for _ in Ok::<_, ()>([0; 0]) {}
|
||||
//~^ WARN for loop over a `Result`. This is more readably written as an `if let` statement
|
||||
//~| HELP to check pattern in a loop use `while let`
|
||||
//~| HELP consider unwrapping the `Result` with `?` to iterate over its contents
|
||||
//~| HELP consider using `if let` to clear intent
|
||||
|
||||
Ok(())
|
||||
}
|
||||
101
src/test/ui/lint/for_loop_over_fallibles.stderr
Normal file
101
src/test/ui/lint/for_loop_over_fallibles.stderr
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
warning: for loop over an `Option`. This is more readably written as an `if let` statement
|
||||
--> $DIR/for_loop_over_fallibles.rs:5:14
|
||||
|
|
||||
LL | for _ in Some(1) {}
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: `#[warn(for_loops_over_fallibles)]` on by default
|
||||
help: to check pattern in a loop use `while let`
|
||||
|
|
||||
LL | while let Some(_) = Some(1) {}
|
||||
| ~~~~~~~~~~~~~~~ ~~~
|
||||
help: consider using `if let` to clear intent
|
||||
|
|
||||
LL | if let Some(_) = Some(1) {}
|
||||
| ~~~~~~~~~~~~ ~~~
|
||||
|
||||
warning: for loop over a `Result`. This is more readably written as an `if let` statement
|
||||
--> $DIR/for_loop_over_fallibles.rs:9:14
|
||||
|
|
||||
LL | for _ in Ok::<_, ()>(1) {}
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
help: to check pattern in a loop use `while let`
|
||||
|
|
||||
LL | while let Ok(_) = Ok::<_, ()>(1) {}
|
||||
| ~~~~~~~~~~~~~ ~~~
|
||||
help: consider using `if let` to clear intent
|
||||
|
|
||||
LL | if let Ok(_) = Ok::<_, ()>(1) {}
|
||||
| ~~~~~~~~~~ ~~~
|
||||
|
||||
warning: for loop over an `Option`. This is more readably written as an `if let` statement
|
||||
--> $DIR/for_loop_over_fallibles.rs:15:14
|
||||
|
|
||||
LL | for _ in [0; 0].iter().next() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: to iterate over `[0; 0].iter()` remove the call to `next`
|
||||
|
|
||||
LL | for _ in [0; 0].iter().by_ref() {}
|
||||
| ~~~~~~~~~
|
||||
help: consider using `if let` to clear intent
|
||||
|
|
||||
LL | if let Some(_) = [0; 0].iter().next() {}
|
||||
| ~~~~~~~~~~~~ ~~~
|
||||
|
||||
warning: for loop over a `Result`. This is more readably written as an `if let` statement
|
||||
--> $DIR/for_loop_over_fallibles.rs:21:14
|
||||
|
|
||||
LL | for _ in Ok::<_, ()>([0; 0].iter()) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: to check pattern in a loop use `while let`
|
||||
|
|
||||
LL | while let Ok(_) = Ok::<_, ()>([0; 0].iter()) {}
|
||||
| ~~~~~~~~~~~~~ ~~~
|
||||
help: consider using `if let` to clear intent
|
||||
|
|
||||
LL | if let Ok(_) = Ok::<_, ()>([0; 0].iter()) {}
|
||||
| ~~~~~~~~~~ ~~~
|
||||
|
||||
warning: for loop over a `Result`. This is more readably written as an `if let` statement
|
||||
--> $DIR/for_loop_over_fallibles.rs:29:14
|
||||
|
|
||||
LL | for _ in Ok::<_, ()>([0; 0].iter()) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: to check pattern in a loop use `while let`
|
||||
|
|
||||
LL | while let Ok(_) = Ok::<_, ()>([0; 0].iter()) {}
|
||||
| ~~~~~~~~~~~~~ ~~~
|
||||
help: consider unwrapping the `Result` with `?` to iterate over its contents
|
||||
|
|
||||
LL | for _ in Ok::<_, ()>([0; 0].iter())? {}
|
||||
| +
|
||||
help: consider using `if let` to clear intent
|
||||
|
|
||||
LL | if let Ok(_) = Ok::<_, ()>([0; 0].iter()) {}
|
||||
| ~~~~~~~~~~ ~~~
|
||||
|
||||
warning: for loop over a `Result`. This is more readably written as an `if let` statement
|
||||
--> $DIR/for_loop_over_fallibles.rs:36:14
|
||||
|
|
||||
LL | for _ in Ok::<_, ()>([0; 0]) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: to check pattern in a loop use `while let`
|
||||
|
|
||||
LL | while let Ok(_) = Ok::<_, ()>([0; 0]) {}
|
||||
| ~~~~~~~~~~~~~ ~~~
|
||||
help: consider unwrapping the `Result` with `?` to iterate over its contents
|
||||
|
|
||||
LL | for _ in Ok::<_, ()>([0; 0])? {}
|
||||
| +
|
||||
help: consider using `if let` to clear intent
|
||||
|
|
||||
LL | if let Ok(_) = Ok::<_, ()>([0; 0]) {}
|
||||
| ~~~~~~~~~~ ~~~
|
||||
|
||||
warning: 6 warnings emitted
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue