| #![warn(clippy::while_let_on_iterator)] | |
| #![expect( | |
| clippy::redundant_closure_call, | |
| clippy::single_range_in_vec_init, | |
| clippy::useless_vec | |
| )] | |
| fn base() { | |
| let mut iter = 1..20; | |
| while let Option::Some(x) = iter.next() { | |
| //~^ while_let_on_iterator | |
| println!("{}", x); | |
| } | |
| let mut iter = 1..20; | |
| while let Some(x) = iter.next() { | |
| //~^ while_let_on_iterator | |
| println!("{}", x); | |
| } | |
| let mut iter = 1..20; | |
| while let Some(_) = iter.next() {} | |
| //~^ while_let_on_iterator | |
| let mut iter = 1..20; | |
| while let None = iter.next() {} // this is fine (if nonsensical) | |
| let mut iter = 1..20; | |
| if let Some(x) = iter.next() { | |
| // also fine | |
| println!("{}", x) | |
| } | |
| // the following shouldn't warn because it can't be written with a for loop | |
| let mut iter = 1u32..20; | |
| while let Some(_) = iter.next() { | |
| println!("next: {:?}", iter.next()) | |
| } | |
| // neither can this | |
| let mut iter = 1u32..20; | |
| while let Some(_) = iter.next() { | |
| println!("next: {:?}", iter.next()); | |
| } | |
| // or this | |
| let mut iter = 1u32..20; | |
| while let Some(_) = iter.next() { | |
| iter = 1..20; | |
| } | |
| } | |
| // Issue #1188 | |
| fn refutable() { | |
| let a = [42, 1337]; | |
| let mut b = a.iter(); | |
| // consume all the 42s | |
| while let Some(&42) = b.next() {} | |
| let a = [(1, 2, 3)]; | |
| let mut b = a.iter(); | |
| while let Some(&(1, 2, 3)) = b.next() {} | |
| let a = [Some(42)]; | |
| let mut b = a.iter(); | |
| while let Some(&None) = b.next() {} | |
| /* This gives “refutable pattern in `for` loop binding: `&_` not covered” | |
| for &42 in b {} | |
| for &(1, 2, 3) in b {} | |
| for &Option::None in b.next() {} | |
| // */ | |
| } | |
| fn refutable2() { | |
| // Issue 3780 | |
| { | |
| let v = vec![1, 2, 3]; | |
| let mut it = v.windows(2); | |
| while let Some([x, y]) = it.next() { | |
| println!("x: {}", x); | |
| println!("y: {}", y); | |
| } | |
| let mut it = v.windows(2); | |
| while let Some([x, ..]) = it.next() { | |
| println!("x: {}", x); | |
| } | |
| let mut it = v.windows(2); | |
| while let Some([.., y]) = it.next() { | |
| println!("y: {}", y); | |
| } | |
| let mut it = v.windows(2); | |
| while let Some([..]) = it.next() {} | |
| //~^ while_let_on_iterator | |
| let v = vec![[1], [2], [3]]; | |
| let mut it = v.iter(); | |
| while let Some([1]) = it.next() {} | |
| let mut it = v.iter(); | |
| while let Some([_x]) = it.next() {} | |
| //~^ while_let_on_iterator | |
| } | |
| // binding | |
| { | |
| let v = vec![1, 2, 3]; | |
| let mut it = v.iter(); | |
| while let Some(x @ 1) = it.next() { | |
| println!("{}", x); | |
| } | |
| let v = vec![[1], [2], [3]]; | |
| let mut it = v.iter(); | |
| while let Some(x @ [_]) = it.next() { | |
| //~^ while_let_on_iterator | |
| println!("{:?}", x); | |
| } | |
| } | |
| // false negative | |
| { | |
| let v = vec![1, 2, 3]; | |
| let mut it = v.iter().map(Some); | |
| while let Some(Some(_) | None) = it.next() { | |
| println!("1"); | |
| } | |
| } | |
| } | |
| fn nested_loops() { | |
| let a = [42, 1337]; | |
| loop { | |
| let mut y = a.iter(); | |
| while let Some(_) = y.next() { | |
| //~^ while_let_on_iterator | |
| // use a for loop here | |
| } | |
| } | |
| } | |
| fn issue1121() { | |
| use std::collections::HashSet; | |
| let mut values = HashSet::new(); | |
| values.insert(1); | |
| while let Some(&value) = values.iter().next() { | |
| values.remove(&value); | |
| } | |
| } | |
| fn issue2965() { | |
| // This should not cause an ICE | |
| use std::collections::HashSet; | |
| let mut values = HashSet::new(); | |
| values.insert(1); | |
| while let Some(..) = values.iter().next() {} | |
| } | |
| fn issue3670() { | |
| let array = [Some(0), None, Some(1)]; | |
| let mut iter = array.iter(); | |
| while let Some(elem) = iter.next() { | |
| let _ = elem.or_else(|| *iter.next()?); | |
| } | |
| } | |
| fn issue1654() { | |
| // should not lint if the iterator is generated on every iteration | |
| use std::collections::HashSet; | |
| let mut values = HashSet::new(); | |
| values.insert(1); | |
| while let Some(..) = values.iter().next() { | |
| values.remove(&1); | |
| } | |
| while let Some(..) = values.iter().map(|x| x + 1).next() {} | |
| let chars = "Hello, World!".char_indices(); | |
| while let Some((i, ch)) = chars.clone().next() { | |
| println!("{}: {}", i, ch); | |
| } | |
| } | |
| fn issue6491() { | |
| // Used in outer loop, needs &mut | |
| let mut it = 1..40; | |
| while let Some(n) = it.next() { | |
| while let Some(m) = it.next() { | |
| //~^ while_let_on_iterator | |
| if m % 10 == 0 { | |
| break; | |
| } | |
| println!("doing something with m: {}", m); | |
| } | |
| println!("n still is {}", n); | |
| } | |
| // This is fine, inner loop uses a new iterator. | |
| let mut it = 1..40; | |
| while let Some(n) = it.next() { | |
| //~^ while_let_on_iterator | |
| let mut it = 1..40; | |
| while let Some(m) = it.next() { | |
| //~^ while_let_on_iterator | |
| if m % 10 == 0 { | |
| break; | |
| } | |
| println!("doing something with m: {}", m); | |
| } | |
| // Weird binding shouldn't change anything. | |
| let (mut it, _) = (1..40, 0); | |
| while let Some(m) = it.next() { | |
| //~^ while_let_on_iterator | |
| if m % 10 == 0 { | |
| break; | |
| } | |
| println!("doing something with m: {}", m); | |
| } | |
| // Used after the loop, needs &mut. | |
| let mut it = 1..40; | |
| while let Some(m) = it.next() { | |
| //~^ while_let_on_iterator | |
| if m % 10 == 0 { | |
| break; | |
| } | |
| println!("doing something with m: {}", m); | |
| } | |
| println!("next item {}", it.next().unwrap()); | |
| println!("n still is {}", n); | |
| } | |
| } | |
| fn issue6231() { | |
| // Closure in the outer loop, needs &mut | |
| let mut it = 1..40; | |
| let mut opt = Some(0); | |
| while let Some(n) = opt.take().or_else(|| it.next()) { | |
| while let Some(m) = it.next() { | |
| //~^ while_let_on_iterator | |
| if n % 10 == 0 { | |
| break; | |
| } | |
| println!("doing something with m: {}", m); | |
| } | |
| println!("n still is {}", n); | |
| } | |
| } | |
| fn issue1924() { | |
| struct S<T>(T); | |
| impl<T: Iterator<Item = u32>> S<T> { | |
| fn f(&mut self) -> Option<u32> { | |
| // Used as a field. | |
| while let Some(i) = self.0.next() { | |
| //~^ while_let_on_iterator | |
| if !(3..8).contains(&i) { | |
| return Some(i); | |
| } | |
| } | |
| None | |
| } | |
| fn f2(&mut self) -> Option<u32> { | |
| // Don't lint, self borrowed inside the loop | |
| while let Some(i) = self.0.next() { | |
| if i == 1 { | |
| return self.f(); | |
| } | |
| } | |
| None | |
| } | |
| } | |
| impl<T: Iterator<Item = u32>> S<(S<T>, Option<u32>)> { | |
| fn f3(&mut self) -> Option<u32> { | |
| // Don't lint, self borrowed inside the loop | |
| while let Some(i) = self.0.0.0.next() { | |
| if i == 1 { | |
| return self.0.0.f(); | |
| } | |
| } | |
| while let Some(i) = self.0.0.0.next() { | |
| if i == 1 { | |
| return self.f3(); | |
| } | |
| } | |
| // This one is fine, a different field is borrowed | |
| while let Some(i) = self.0.0.0.next() { | |
| //~^ while_let_on_iterator | |
| if i == 1 { | |
| return self.0.1.take(); | |
| } else { | |
| self.0.1 = Some(i); | |
| } | |
| } | |
| None | |
| } | |
| } | |
| struct S2<T>(T, u32); | |
| impl<T: Iterator<Item = u32>> Iterator for S2<T> { | |
| type Item = u32; | |
| fn next(&mut self) -> Option<u32> { | |
| self.0.next() | |
| } | |
| } | |
| // Don't lint, field of the iterator is accessed in the loop | |
| let mut it = S2(1..40, 0); | |
| while let Some(n) = it.next() { | |
| if n == it.1 { | |
| break; | |
| } | |
| } | |
| // Needs &mut, field of the iterator is accessed after the loop | |
| let mut it = S2(1..40, 0); | |
| while let Some(n) = it.next() { | |
| //~^ while_let_on_iterator | |
| if n == 0 { | |
| break; | |
| } | |
| } | |
| println!("iterator field {}", it.1); | |
| } | |
| fn issue7249() { | |
| let mut it = 0..10; | |
| let mut x = || { | |
| // Needs &mut, the closure can be called multiple times | |
| while let Some(x) = it.next() { | |
| //~^ while_let_on_iterator | |
| if x % 2 == 0 { | |
| break; | |
| } | |
| } | |
| }; | |
| x(); | |
| x(); | |
| } | |
| fn issue7510() { | |
| let mut it = 0..10; | |
| let it = &mut it; | |
| // Needs to reborrow `it` as the binding isn't mutable | |
| while let Some(x) = it.next() { | |
| //~^ while_let_on_iterator | |
| if x % 2 == 0 { | |
| break; | |
| } | |
| } | |
| println!("{}", it.next().unwrap()); | |
| struct S<T>(T); | |
| let mut it = 0..10; | |
| let it = S(&mut it); | |
| // Needs to reborrow `it.0` as the binding isn't mutable | |
| while let Some(x) = it.0.next() { | |
| //~^ while_let_on_iterator | |
| if x % 2 == 0 { | |
| break; | |
| } | |
| } | |
| println!("{}", it.0.next().unwrap()); | |
| } | |
| fn exact_match_with_single_field() { | |
| struct S<T>(T); | |
| let mut s = S(0..10); | |
| // Don't lint. `s.0` is used inside the loop. | |
| while let Some(_) = s.0.next() { | |
| let _ = &mut s.0; | |
| } | |
| } | |
| fn custom_deref() { | |
| struct S1<T> { | |
| x: T, | |
| } | |
| struct S2<T>(S1<T>); | |
| impl<T> core::ops::Deref for S2<T> { | |
| type Target = S1<T>; | |
| fn deref(&self) -> &Self::Target { | |
| &self.0 | |
| } | |
| } | |
| impl<T> core::ops::DerefMut for S2<T> { | |
| fn deref_mut(&mut self) -> &mut Self::Target { | |
| &mut self.0 | |
| } | |
| } | |
| let mut s = S2(S1 { x: 0..10 }); | |
| while let Some(x) = s.x.next() { | |
| //~^ while_let_on_iterator | |
| println!("{}", x); | |
| } | |
| } | |
| fn issue_8113() { | |
| let mut x = [0..10]; | |
| while let Some(x) = x[0].next() { | |
| //~^ while_let_on_iterator | |
| println!("{}", x); | |
| } | |
| } | |
| fn fn_once_closure() { | |
| let mut it = 0..10; | |
| (|| { | |
| while let Some(x) = it.next() { | |
| //~^ while_let_on_iterator | |
| if x % 2 == 0 { | |
| break; | |
| } | |
| } | |
| })(); | |
| fn f(_: impl FnOnce()) {} | |
| let mut it = 0..10; | |
| f(|| { | |
| while let Some(x) = it.next() { | |
| //~^ while_let_on_iterator | |
| if x % 2 == 0 { | |
| break; | |
| } | |
| } | |
| }); | |
| fn f2(_: impl FnMut()) {} | |
| let mut it = 0..10; | |
| f2(|| { | |
| while let Some(x) = it.next() { | |
| //~^ while_let_on_iterator | |
| if x % 2 == 0 { | |
| break; | |
| } | |
| } | |
| }); | |
| fn f3(_: fn()) {} | |
| f3(|| { | |
| let mut it = 0..10; | |
| while let Some(x) = it.next() { | |
| //~^ while_let_on_iterator | |
| if x % 2 == 0 { | |
| break; | |
| } | |
| } | |
| }); | |
| trait MySpecialFnMut: FnOnce() {} | |
| impl<T: FnOnce()> MySpecialFnMut for T {} | |
| fn f4(_: impl MySpecialFnMut) {} | |
| let mut it = 0..10; | |
| f4(|| { | |
| while let Some(x) = it.next() { | |
| //~^ while_let_on_iterator | |
| if x % 2 == 0 { | |
| break; | |
| } | |
| } | |
| }); | |
| } | |
| fn issue13123() { | |
| let mut it = 0..20; | |
| 'label: while let Some(n) = it.next() { | |
| //~^ while_let_on_iterator | |
| if n % 25 == 0 { | |
| break 'label; | |
| } | |
| } | |
| } | |
| fn issue16089() { | |
| trait CertainTrait: Iterator<Item = u8> { | |
| fn iter_over_self(&mut self) { | |
| let mut a = 0; | |
| while let Some(r) = self.next() { | |
| //~^ while_let_on_iterator | |
| a = r; | |
| } | |
| self.use_after_iter() | |
| } | |
| fn use_after_iter(&mut self) {} | |
| } | |
| } | |
| fn issue16089_sized_trait_not_reborrowed() { | |
| trait CertainTrait: Iterator<Item = u8> + Sized { | |
| fn iter_over_self(&mut self) { | |
| let mut a = 0; | |
| // Check that the suggestion is just "self", since the trait is sized. | |
| while let Some(r) = self.next() { | |
| //~^ while_let_on_iterator | |
| a = r; | |
| } | |
| self.use_after_iter() | |
| } | |
| fn use_after_iter(&mut self) {} | |
| } | |
| } | |
| fn issue16089_nested_derefs() { | |
| struct S<T>(T); | |
| impl<T> core::ops::Deref for S<T> { | |
| type Target = T; | |
| fn deref(&self) -> &Self::Target { | |
| &self.0 | |
| } | |
| } | |
| impl<T> core::ops::DerefMut for S<T> { | |
| fn deref_mut(&mut self) -> &mut Self::Target { | |
| &mut self.0 | |
| } | |
| } | |
| fn f(mut x: S<S<&mut dyn Iterator<Item = u32>>>) { | |
| while let Some(_) = x.next() {} | |
| //~^ while_let_on_iterator | |
| } | |
| } | |
| fn issue16089_nested_derefs_last_not_sized() { | |
| struct WithSize<T>(T); | |
| impl<T> core::ops::Deref for WithSize<T> { | |
| type Target = T; | |
| fn deref(&self) -> &Self::Target { | |
| &self.0 | |
| } | |
| } | |
| impl<T> core::ops::DerefMut for WithSize<T> { | |
| fn deref_mut(&mut self) -> &mut Self::Target { | |
| &mut self.0 | |
| } | |
| } | |
| // The suggestion must use `&mut **x`. Using `x.by_ref()` doesn't work in this | |
| // case, since the last type adjustment for `x` in the expression `x.next()` is | |
| // to dereference a `?Sized` trait. | |
| fn f(mut x: WithSize<&mut dyn Iterator<Item = u32>>) { | |
| while let Some(_) = x.next() {} | |
| //~^ while_let_on_iterator | |
| } | |
| } | |
| fn issue16089_nested_derefs_last_sized() { | |
| struct NoSize<T: ?Sized>(T); | |
| impl<T: ?Sized> core::ops::Deref for NoSize<T> { | |
| type Target = T; | |
| fn deref(&self) -> &Self::Target { | |
| &self.0 | |
| } | |
| } | |
| impl<T: ?Sized> core::ops::DerefMut for NoSize<T> { | |
| fn deref_mut(&mut self) -> &mut Self::Target { | |
| &mut self.0 | |
| } | |
| } | |
| struct SizedIter {} | |
| impl Iterator for SizedIter { | |
| type Item = u32; | |
| fn next(&mut self) -> Option<u32> { | |
| Some(0) | |
| } | |
| } | |
| // We want the suggestion to be `x.by_ref()`. It works in this case since the last type | |
| // adjustment for `x` in the expression `x.next()` is to dereference a Sized type. | |
| fn f(mut x: NoSize<NoSize<SizedIter>>) { | |
| while let Some(_) = x.next() {} | |
| //~^ while_let_on_iterator | |
| } | |
| } | |
| fn main() { | |
| let mut it = 0..20; | |
| while let Some(..) = it.next() { | |
| //~^ while_let_on_iterator | |
| println!("test"); | |
| } | |
| } |