about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMara Bos <m-ou.se@m-ou.se>2021-08-30 23:41:48 +0200
committerMara Bos <m-ou.se@m-ou.se>2021-08-30 23:43:38 +0200
commit422ad3bec2a9b41345cf1dd95a4ce4b4d9f159d8 (patch)
treefad689a1a010fc960d15f2ba95e66f7e33a266d8
parent13edc17f65bcad7fe9046720a16fc192e810970e (diff)
downloadrust-422ad3bec2a9b41345cf1dd95a4ce4b4d9f159d8.tar.gz
rust-422ad3bec2a9b41345cf1dd95a4ce4b4d9f159d8.zip
Upgrade array_into_iter lint to include Deref-to-array types.
-rw-r--r--compiler/rustc_lint/src/array_into_iter.rs52
1 files 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 21fad5f9af6..2e20f376766 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