about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/equatable_if_let.rs34
-rw-r--r--tests/ui/equatable_if_let.fixed36
-rw-r--r--tests/ui/equatable_if_let.rs36
-rw-r--r--tests/ui/equatable_if_let.stderr20
4 files changed, 124 insertions, 2 deletions
diff --git a/clippy_lints/src/equatable_if_let.rs b/clippy_lints/src/equatable_if_let.rs
index 3afb687040f..72f5eaf8a4b 100644
--- a/clippy_lints/src/equatable_if_let.rs
+++ b/clippy_lints/src/equatable_if_let.rs
@@ -68,6 +68,38 @@ fn is_structural_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: T
     }
 }
 
+/// Check if the pattern has any type mismatch that would prevent it from being used in an equality
+/// check. This can happen if the expr has a reference type and the corresponding pattern is a
+/// literal.
+fn contains_type_mismatch(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
+    let mut result = false;
+    pat.walk(|p| {
+        if result {
+            return false;
+        }
+
+        if p.span.in_external_macro(cx.sess().source_map()) {
+            return true;
+        }
+
+        let adjust_pat = match p.kind {
+            PatKind::Or([p, ..]) => p,
+            _ => p,
+        };
+
+        if let Some(adjustments) = cx.typeck_results().pat_adjustments().get(adjust_pat.hir_id)
+            && adjustments.first().is_some_and(|first| first.source.is_ref())
+        {
+            result = true;
+            return false;
+        }
+
+        true
+    });
+
+    result
+}
+
 impl<'tcx> LateLintPass<'tcx> for PatternEquality {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         if let ExprKind::Let(let_expr) = expr.kind
@@ -78,7 +110,7 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality {
             let pat_ty = cx.typeck_results().pat_ty(let_expr.pat);
             let mut applicability = Applicability::MachineApplicable;
 
-            if is_structural_partial_eq(cx, exp_ty, pat_ty) {
+            if is_structural_partial_eq(cx, exp_ty, pat_ty) && !contains_type_mismatch(cx, let_expr.pat) {
                 let pat_str = match let_expr.pat.kind {
                     PatKind::Struct(..) => format!(
                         "({})",
diff --git a/tests/ui/equatable_if_let.fixed b/tests/ui/equatable_if_let.fixed
index 166b1387ba2..ce8b67f9ca7 100644
--- a/tests/ui/equatable_if_let.fixed
+++ b/tests/ui/equatable_if_let.fixed
@@ -103,3 +103,39 @@ fn main() {
 
     external!({ if let 2 = $a {} });
 }
+
+mod issue8710 {
+    fn str_ref(cs: &[char]) {
+        if matches!(cs.iter().next(), Some('i')) {
+            //~^ equatable_if_let
+        } else {
+            todo!();
+        }
+    }
+
+    fn i32_ref(cs: &[i32]) {
+        if matches!(cs.iter().next(), Some(1)) {
+            //~^ equatable_if_let
+        } else {
+            todo!();
+        }
+    }
+
+    fn enum_ref() {
+        #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
+        enum MyEnum {
+            A(i32),
+            B,
+        }
+
+        fn get_enum() -> Option<&'static MyEnum> {
+            todo!()
+        }
+
+        if matches!(get_enum(), Some(MyEnum::B)) {
+            //~^ equatable_if_let
+        } else {
+            todo!();
+        }
+    }
+}
diff --git a/tests/ui/equatable_if_let.rs b/tests/ui/equatable_if_let.rs
index 09c2483ae6d..ff09533f265 100644
--- a/tests/ui/equatable_if_let.rs
+++ b/tests/ui/equatable_if_let.rs
@@ -103,3 +103,39 @@ fn main() {
 
     external!({ if let 2 = $a {} });
 }
+
+mod issue8710 {
+    fn str_ref(cs: &[char]) {
+        if let Some('i') = cs.iter().next() {
+            //~^ equatable_if_let
+        } else {
+            todo!();
+        }
+    }
+
+    fn i32_ref(cs: &[i32]) {
+        if let Some(1) = cs.iter().next() {
+            //~^ equatable_if_let
+        } else {
+            todo!();
+        }
+    }
+
+    fn enum_ref() {
+        #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
+        enum MyEnum {
+            A(i32),
+            B,
+        }
+
+        fn get_enum() -> Option<&'static MyEnum> {
+            todo!()
+        }
+
+        if let Some(MyEnum::B) = get_enum() {
+            //~^ equatable_if_let
+        } else {
+            todo!();
+        }
+    }
+}
diff --git a/tests/ui/equatable_if_let.stderr b/tests/ui/equatable_if_let.stderr
index 81e0e15a5c7..dd1832ad68b 100644
--- a/tests/ui/equatable_if_let.stderr
+++ b/tests/ui/equatable_if_let.stderr
@@ -85,5 +85,23 @@ error: this pattern matching can be expressed using equality
 LL |     if let inline!("abc") = "abc" {
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"abc" == inline!("abc")`
 
-error: aborting due to 14 previous errors
+error: this pattern matching can be expressed using `matches!`
+  --> tests/ui/equatable_if_let.rs:109:12
+   |
+LL |         if let Some('i') = cs.iter().next() {
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(cs.iter().next(), Some('i'))`
+
+error: this pattern matching can be expressed using `matches!`
+  --> tests/ui/equatable_if_let.rs:117:12
+   |
+LL |         if let Some(1) = cs.iter().next() {
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(cs.iter().next(), Some(1))`
+
+error: this pattern matching can be expressed using `matches!`
+  --> tests/ui/equatable_if_let.rs:135:12
+   |
+LL |         if let Some(MyEnum::B) = get_enum() {
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(get_enum(), Some(MyEnum::B))`
+
+error: aborting due to 17 previous errors