about summary refs log tree commit diff
diff options
context:
space:
mode:
authory21 <30553356+y21@users.noreply.github.com>2023-11-11 13:48:26 +0100
committery21 <30553356+y21@users.noreply.github.com>2023-11-11 13:48:26 +0100
commitb2cf8f7a24d33914a51fcb0048bfaba11868f471 (patch)
tree8714081635bdc12cf72d5a02c41f0932e4c62f1a
parent34b7d1559f03f4a35316ed2a5261a87b591834bb (diff)
downloadrust-b2cf8f7a24d33914a51fcb0048bfaba11868f471.tar.gz
rust-b2cf8f7a24d33914a51fcb0048bfaba11868f471.zip
[`map_identity`]: respect match ergonomics
-rw-r--r--clippy_utils/src/lib.rs12
-rw-r--r--tests/ui/map_identity.fixed42
-rw-r--r--tests/ui/map_identity.rs42
-rw-r--r--tests/ui/map_identity.stderr32
4 files changed, 85 insertions, 43 deletions
diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs
index 1181dfc0ef9..51184b75088 100644
--- a/clippy_utils/src/lib.rs
+++ b/clippy_utils/src/lib.rs
@@ -2034,6 +2034,18 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 /// Consider calling [`is_expr_untyped_identity_function`] or [`is_expr_identity_function`] instead.
 fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
     fn check_pat(cx: &LateContext<'_>, pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
+        if cx
+            .typeck_results()
+            .pat_binding_modes()
+            .get(pat.hir_id)
+            .is_some_and(|mode| matches!(mode, BindingMode::BindByReference(_)))
+        {
+            // If a tuple `(x, y)` is of type `&(i32, i32)`, then due to match ergonomics,
+            // the inner patterns become references. Don't consider this the identity function
+            // as that changes types.
+            return false;
+        }
+
         match (pat.kind, expr.kind) {
             (PatKind::Binding(_, id, _, _), _) => {
                 path_to_local_id(expr, id) && cx.typeck_results().expr_adjustments(expr).is_empty()
diff --git a/tests/ui/map_identity.fixed b/tests/ui/map_identity.fixed
index 62b0ba01860..53ebfb40ba0 100644
--- a/tests/ui/map_identity.fixed
+++ b/tests/ui/map_identity.fixed
@@ -24,28 +24,40 @@ fn main() {
 
 fn issue7189() {
     // should lint
-    let x = [(1, 2), (3, 4)];
-    let _ = x.iter();
-    let _ = x.iter();
-    let _ = x.iter();
+    let x = [(1, 2), (3, 4)].iter().copied();
+    let _ = x.clone();
+    let _ = x.clone();
+    let _ = x.clone();
 
-    let y = [(1, 2, (3, (4,))), (5, 6, (7, (8,)))];
-    let _ = y.iter();
+    let y = [(1, 2, (3, (4,))), (5, 6, (7, (8,)))].iter().copied();
+    let _ = y.clone();
 
     // should not lint
-    let _ = x.iter().map(|(x, y)| (x, y, y));
-    let _ = x.iter().map(|(x, _y)| (x,));
-    let _ = x.iter().map(|(x, _)| (x,));
-    let _ = x.iter().map(|(x, ..)| (x,));
-    let _ = y.iter().map(|(x, y, (z, _))| (x, y, (z, z)));
+    let _ = x.clone().map(|(x, y)| (x, y, y));
+    let _ = x.clone().map(|(x, _y)| (x,));
+    let _ = x.clone().map(|(x, _)| (x,));
+    let _ = x.clone().map(|(x, ..)| (x,));
+    let _ = y.clone().map(|(x, y, (z, _))| (x, y, (z, z)));
     let _ = y
-        .iter()
-        .map(|(x, y, (z, _)): &(i32, i32, (i32, (i32,)))| (x, y, (z, z)));
+        .clone()
+        .map(|(x, y, (z, _)): (i32, i32, (i32, (i32,)))| (x, y, (z, z)));
     let _ = y
-        .iter()
-        .map(|(x, y, (z, (w,))): &(i32, i32, (i32, (i32,)))| (x, y, (z, (w,))));
+        .clone()
+        .map(|(x, y, (z, (w,))): (i32, i32, (i32, (i32,)))| (x, y, (z, (w,))));
 }
 
 fn not_identity(x: &u16) -> u16 {
     *x
 }
+
+fn issue11764() {
+    let x = [(1, 2), (3, 4)];
+    // don't lint: this is an `Iterator<Item = &(i32, i32)>`
+    // match ergonomics makes the binding patterns into references
+    // so that its type changes to `Iterator<Item = (&i32, &i32)>`
+    let _ = x.iter().map(|(x, y)| (x, y));
+    let _ = x.iter().map(|x| (x.0,)).map(|(x,)| x);
+
+    // no match ergonomics for `(i32, i32)`
+    let _ = x.iter().copied();
+}
diff --git a/tests/ui/map_identity.rs b/tests/ui/map_identity.rs
index b7f4c99f273..c646c056859 100644
--- a/tests/ui/map_identity.rs
+++ b/tests/ui/map_identity.rs
@@ -26,30 +26,42 @@ fn main() {
 
 fn issue7189() {
     // should lint
-    let x = [(1, 2), (3, 4)];
-    let _ = x.iter().map(|(x, y)| (x, y));
-    let _ = x.iter().map(|(x, y)| {
+    let x = [(1, 2), (3, 4)].iter().copied();
+    let _ = x.clone().map(|(x, y)| (x, y));
+    let _ = x.clone().map(|(x, y)| {
         return (x, y);
     });
-    let _ = x.iter().map(|(x, y)| return (x, y));
+    let _ = x.clone().map(|(x, y)| return (x, y));
 
-    let y = [(1, 2, (3, (4,))), (5, 6, (7, (8,)))];
-    let _ = y.iter().map(|(x, y, (z, (w,)))| (x, y, (z, (w,))));
+    let y = [(1, 2, (3, (4,))), (5, 6, (7, (8,)))].iter().copied();
+    let _ = y.clone().map(|(x, y, (z, (w,)))| (x, y, (z, (w,))));
 
     // should not lint
-    let _ = x.iter().map(|(x, y)| (x, y, y));
-    let _ = x.iter().map(|(x, _y)| (x,));
-    let _ = x.iter().map(|(x, _)| (x,));
-    let _ = x.iter().map(|(x, ..)| (x,));
-    let _ = y.iter().map(|(x, y, (z, _))| (x, y, (z, z)));
+    let _ = x.clone().map(|(x, y)| (x, y, y));
+    let _ = x.clone().map(|(x, _y)| (x,));
+    let _ = x.clone().map(|(x, _)| (x,));
+    let _ = x.clone().map(|(x, ..)| (x,));
+    let _ = y.clone().map(|(x, y, (z, _))| (x, y, (z, z)));
     let _ = y
-        .iter()
-        .map(|(x, y, (z, _)): &(i32, i32, (i32, (i32,)))| (x, y, (z, z)));
+        .clone()
+        .map(|(x, y, (z, _)): (i32, i32, (i32, (i32,)))| (x, y, (z, z)));
     let _ = y
-        .iter()
-        .map(|(x, y, (z, (w,))): &(i32, i32, (i32, (i32,)))| (x, y, (z, (w,))));
+        .clone()
+        .map(|(x, y, (z, (w,))): (i32, i32, (i32, (i32,)))| (x, y, (z, (w,))));
 }
 
 fn not_identity(x: &u16) -> u16 {
     *x
 }
+
+fn issue11764() {
+    let x = [(1, 2), (3, 4)];
+    // don't lint: this is an `Iterator<Item = &(i32, i32)>`
+    // match ergonomics makes the binding patterns into references
+    // so that its type changes to `Iterator<Item = (&i32, &i32)>`
+    let _ = x.iter().map(|(x, y)| (x, y));
+    let _ = x.iter().map(|x| (x.0,)).map(|(x,)| x);
+
+    // no match ergonomics for `(i32, i32)`
+    let _ = x.iter().copied().map(|(x, y)| (x, y));
+}
diff --git a/tests/ui/map_identity.stderr b/tests/ui/map_identity.stderr
index 4ca24b0b04c..ea077d66d64 100644
--- a/tests/ui/map_identity.stderr
+++ b/tests/ui/map_identity.stderr
@@ -41,31 +41,37 @@ LL |     let _: Result<u32, u32> = Ok(1).map_err(|a| a);
    |                                    ^^^^^^^^^^^^^^^ help: remove the call to `map_err`
 
 error: unnecessary map of the identity function
-  --> $DIR/map_identity.rs:30:21
+  --> $DIR/map_identity.rs:30:22
    |
-LL |     let _ = x.iter().map(|(x, y)| (x, y));
-   |                     ^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
+LL |     let _ = x.clone().map(|(x, y)| (x, y));
+   |                      ^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
 
 error: unnecessary map of the identity function
-  --> $DIR/map_identity.rs:31:21
+  --> $DIR/map_identity.rs:31:22
    |
-LL |       let _ = x.iter().map(|(x, y)| {
-   |  _____________________^
+LL |       let _ = x.clone().map(|(x, y)| {
+   |  ______________________^
 LL | |         return (x, y);
 LL | |     });
    | |______^ help: remove the call to `map`
 
 error: unnecessary map of the identity function
-  --> $DIR/map_identity.rs:34:21
+  --> $DIR/map_identity.rs:34:22
    |
-LL |     let _ = x.iter().map(|(x, y)| return (x, y));
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
+LL |     let _ = x.clone().map(|(x, y)| return (x, y));
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
 
 error: unnecessary map of the identity function
-  --> $DIR/map_identity.rs:37:21
+  --> $DIR/map_identity.rs:37:22
    |
-LL |     let _ = y.iter().map(|(x, y, (z, (w,)))| (x, y, (z, (w,))));
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
+LL |     let _ = y.clone().map(|(x, y, (z, (w,)))| (x, y, (z, (w,))));
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
 
-error: aborting due to 10 previous errors
+error: unnecessary map of the identity function
+  --> $DIR/map_identity.rs:66:30
+   |
+LL |     let _ = x.iter().copied().map(|(x, y)| (x, y));
+   |                              ^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
+
+error: aborting due to 11 previous errors