From 422ad3bec2a9b41345cf1dd95a4ce4b4d9f159d8 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 30 Aug 2021 23:41:48 +0200 Subject: [PATCH 1/3] Upgrade array_into_iter lint to include Deref-to-array types. --- compiler/rustc_lint/src/array_into_iter.rs | 52 ++++++++++++---------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs index 21fad5f9af683..2e20f376766ba 100644 --- a/compiler/rustc_lint/src/array_into_iter.rs +++ b/compiler/rustc_lint/src/array_into_iter.rs @@ -74,39 +74,45 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter { _ => return, }; - // As this is a method call expression, we have at least one - // argument. + // As this is a method call expression, we have at least one argument. let receiver_arg = &args[0]; + let receiver_ty = cx.typeck_results().expr_ty(receiver_arg); + let adjustments = cx.typeck_results().expr_adjustments(receiver_arg); - // Peel all `Box<_>` layers. We have to special case `Box` here as - // `Box` is the only thing that values can be moved out of via - // method call. `Box::new([1]).into_iter()` should trigger this - // lint. - let mut recv_ty = cx.typeck_results().expr_ty(receiver_arg); - let mut num_box_derefs = 0; - while recv_ty.is_box() { - num_box_derefs += 1; - recv_ty = recv_ty.boxed_ty(); - } + let target = match adjustments.last() { + Some(Adjustment { kind: Adjust::Borrow(_), target }) => target, + _ => return, + }; - // Make sure we found an array after peeling the boxes. - if !matches!(recv_ty.kind(), ty::Array(..)) { - return; + let types = + std::iter::once(receiver_ty).chain(adjustments.iter().map(|adj| adj.target)); + + let mut found_array = false; + + for ty in types { + match ty.kind() { + // If we run into a &[T; N] or &[T] first, there's nothing to warn about. + // It'll resolve to the reference version. + ty::Ref(_, inner_ty, _) if inner_ty.is_array() => return, + ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Slice(..)) => return, + // Found an actual array type without matching a &[T; N] first. + // This is the problematic case. + ty::Array(..) => { + found_array = true; + break; + } + _ => {} + } } - // Make sure that there is an autoref coercion at the expected - // position. The first `num_box_derefs` adjustments are the derefs - // of the box. - match cx.typeck_results().expr_adjustments(receiver_arg).get(num_box_derefs) { - Some(Adjustment { kind: Adjust::Borrow(_), .. }) => {} - _ => return, + if !found_array { + return; } // Emit lint diagnostic. - let target = match *cx.typeck_results().expr_ty_adjusted(receiver_arg).kind() { + let target = match *target.kind() { ty::Ref(_, inner_ty, _) if inner_ty.is_array() => "[T; N]", ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Slice(..)) => "[T]", - // We know the original first argument type is an array type, // we know that the first adjustment was an autoref coercion // and we know that `IntoIterator` is the trait involved. The From 90080f47032b5b2d578b0940ee615a428680e884 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 30 Aug 2021 23:42:13 +0200 Subject: [PATCH 2/3] Don't give invalid suggestions in array_into_iter. --- compiler/rustc_lint/src/array_into_iter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs index 2e20f376766ba..5ac42c50c7240 100644 --- a/compiler/rustc_lint/src/array_into_iter.rs +++ b/compiler/rustc_lint/src/array_into_iter.rs @@ -141,7 +141,7 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter { String::new(), Applicability::MaybeIncorrect, ); - } else { + } else if receiver_ty.is_array() { diag.multipart_suggestion( "or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value", vec![ From 96d4666f23f71683965ded5844e78b3f4346406c Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 30 Aug 2021 23:42:48 +0200 Subject: [PATCH 3/3] Update tests for array_into_iter lint upgrade. --- .../ui/iterators/into-iter-on-arrays-2018.rs | 5 +- .../iterators/into-iter-on-arrays-2018.stderr | 28 ++++--- .../iterators/into-iter-on-arrays-lint.stderr | 80 ++----------------- 3 files changed, 31 insertions(+), 82 deletions(-) diff --git a/src/test/ui/iterators/into-iter-on-arrays-2018.rs b/src/test/ui/iterators/into-iter-on-arrays-2018.rs index e56c2956a697e..60995170a5164 100644 --- a/src/test/ui/iterators/into-iter-on-arrays-2018.rs +++ b/src/test/ui/iterators/into-iter-on-arrays-2018.rs @@ -19,9 +19,12 @@ fn main() { //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter` //~| WARNING this changes meaning - // The `array_into_iter` lint doesn't cover other wrappers that deref to an array. let _: Iter<'_, i32> = Rc::new(array).into_iter(); + //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter` + //~| WARNING this changes meaning let _: Iter<'_, i32> = Array(array).into_iter(); + //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter` + //~| WARNING this changes meaning // But you can always use the trait method explicitly as an array. let _: IntoIter = IntoIterator::into_iter(array); diff --git a/src/test/ui/iterators/into-iter-on-arrays-2018.stderr b/src/test/ui/iterators/into-iter-on-arrays-2018.stderr index e9780d9b165c7..bc08fdcafa08d 100644 --- a/src/test/ui/iterators/into-iter-on-arrays-2018.stderr +++ b/src/test/ui/iterators/into-iter-on-arrays-2018.stderr @@ -20,21 +20,31 @@ warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (du --> $DIR/into-iter-on-arrays-2018.rs:18:44 | LL | let _: Iter<'_, i32> = Box::new(array).into_iter(); - | ^^^^^^^^^ + | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` | = warning: this changes meaning in Rust 2021 = note: for more information, see -help: use `.iter()` instead of `.into_iter()` to avoid ambiguity + +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. + --> $DIR/into-iter-on-arrays-2018.rs:22:43 | -LL | let _: Iter<'_, i32> = Box::new(array).iter(); - | ~~~~ -help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value +LL | let _: Iter<'_, i32> = Rc::new(array).into_iter(); + | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` + | + = warning: this changes meaning in Rust 2021 + = note: for more information, see + +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. + --> $DIR/into-iter-on-arrays-2018.rs:25:41 | -LL | let _: Iter<'_, i32> = IntoIterator::into_iter(Box::new(array)); - | ++++++++++++++++++++++++ ~ +LL | let _: Iter<'_, i32> = Array(array).into_iter(); + | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` + | + = warning: this changes meaning in Rust 2021 + = note: for more information, see warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. - --> $DIR/into-iter-on-arrays-2018.rs:29:24 + --> $DIR/into-iter-on-arrays-2018.rs:32:24 | LL | for _ in [1, 2, 3].into_iter() {} | ^^^^^^^^^ @@ -51,5 +61,5 @@ LL - for _ in [1, 2, 3].into_iter() {} LL + for _ in [1, 2, 3] {} | -warning: 3 warnings emitted +warning: 5 warnings emitted diff --git a/src/test/ui/iterators/into-iter-on-arrays-lint.stderr b/src/test/ui/iterators/into-iter-on-arrays-lint.stderr index 138becc4ffe1e..2df1a06df20ab 100644 --- a/src/test/ui/iterators/into-iter-on-arrays-lint.stderr +++ b/src/test/ui/iterators/into-iter-on-arrays-lint.stderr @@ -71,137 +71,73 @@ warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (du --> $DIR/into-iter-on-arrays-lint.rs:23:21 | LL | Box::new(small).into_iter(); - | ^^^^^^^^^ + | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` | = warning: this changes meaning in Rust 2021 = note: for more information, see -help: use `.iter()` instead of `.into_iter()` to avoid ambiguity - | -LL | Box::new(small).iter(); - | ~~~~ -help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value - | -LL | IntoIterator::into_iter(Box::new(small)); - | ++++++++++++++++++++++++ ~ warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. --> $DIR/into-iter-on-arrays-lint.rs:26:22 | LL | Box::new([1, 2]).into_iter(); - | ^^^^^^^^^ + | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` | = warning: this changes meaning in Rust 2021 = note: for more information, see -help: use `.iter()` instead of `.into_iter()` to avoid ambiguity - | -LL | Box::new([1, 2]).iter(); - | ~~~~ -help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value - | -LL | IntoIterator::into_iter(Box::new([1, 2])); - | ++++++++++++++++++++++++ ~ warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. --> $DIR/into-iter-on-arrays-lint.rs:29:19 | LL | Box::new(big).into_iter(); - | ^^^^^^^^^ + | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` | = warning: this changes meaning in Rust 2021 = note: for more information, see -help: use `.iter()` instead of `.into_iter()` to avoid ambiguity - | -LL | Box::new(big).iter(); - | ~~~~ -help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value - | -LL | IntoIterator::into_iter(Box::new(big)); - | ++++++++++++++++++++++++ ~ warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. --> $DIR/into-iter-on-arrays-lint.rs:32:25 | LL | Box::new([0u8; 33]).into_iter(); - | ^^^^^^^^^ + | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` | = warning: this changes meaning in Rust 2021 = note: for more information, see -help: use `.iter()` instead of `.into_iter()` to avoid ambiguity - | -LL | Box::new([0u8; 33]).iter(); - | ~~~~ -help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value - | -LL | IntoIterator::into_iter(Box::new([0u8; 33])); - | ++++++++++++++++++++++++ ~ warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. --> $DIR/into-iter-on-arrays-lint.rs:36:31 | LL | Box::new(Box::new(small)).into_iter(); - | ^^^^^^^^^ + | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` | = warning: this changes meaning in Rust 2021 = note: for more information, see -help: use `.iter()` instead of `.into_iter()` to avoid ambiguity - | -LL | Box::new(Box::new(small)).iter(); - | ~~~~ -help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value - | -LL | IntoIterator::into_iter(Box::new(Box::new(small))); - | ++++++++++++++++++++++++ ~ warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. --> $DIR/into-iter-on-arrays-lint.rs:39:32 | LL | Box::new(Box::new([1, 2])).into_iter(); - | ^^^^^^^^^ + | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` | = warning: this changes meaning in Rust 2021 = note: for more information, see -help: use `.iter()` instead of `.into_iter()` to avoid ambiguity - | -LL | Box::new(Box::new([1, 2])).iter(); - | ~~~~ -help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value - | -LL | IntoIterator::into_iter(Box::new(Box::new([1, 2]))); - | ++++++++++++++++++++++++ ~ warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. --> $DIR/into-iter-on-arrays-lint.rs:42:29 | LL | Box::new(Box::new(big)).into_iter(); - | ^^^^^^^^^ + | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` | = warning: this changes meaning in Rust 2021 = note: for more information, see -help: use `.iter()` instead of `.into_iter()` to avoid ambiguity - | -LL | Box::new(Box::new(big)).iter(); - | ~~~~ -help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value - | -LL | IntoIterator::into_iter(Box::new(Box::new(big))); - | ++++++++++++++++++++++++ ~ warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. --> $DIR/into-iter-on-arrays-lint.rs:45:35 | LL | Box::new(Box::new([0u8; 33])).into_iter(); - | ^^^^^^^^^ + | ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter` | = warning: this changes meaning in Rust 2021 = note: for more information, see -help: use `.iter()` instead of `.into_iter()` to avoid ambiguity - | -LL | Box::new(Box::new([0u8; 33])).iter(); - | ~~~~ -help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value - | -LL | IntoIterator::into_iter(Box::new(Box::new([0u8; 33]))); - | ++++++++++++++++++++++++ ~ warning: 12 warnings emitted