about summary refs log tree commit diff
diff options
context:
space:
mode:
authorest31 <MTest31@outlook.com>2022-02-18 05:43:48 +0100
committerest31 <MTest31@outlook.com>2022-10-24 22:05:39 +0200
commitc5a7696231ef60e77fdeb5068c729d63c0393547 (patch)
tree7f4407fa76a3894ca37cd80e2c3dc8c9e9a7e906
parent2e01e6b4c2d5a84723738575df788823c608dce7 (diff)
downloadrust-c5a7696231ef60e77fdeb5068c729d63c0393547.tar.gz
rust-c5a7696231ef60e77fdeb5068c729d63c0393547.zip
Support tuples
-rw-r--r--clippy_lints/src/manual_let_else.rs38
-rw-r--r--tests/ui/manual_let_else.rs7
-rw-r--r--tests/ui/manual_let_else.stderr14
3 files changed, 45 insertions, 14 deletions
diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs
index 98510ee9acd..5e46abee42d 100644
--- a/clippy_lints/src/manual_let_else.rs
+++ b/clippy_lints/src/manual_let_else.rs
@@ -3,6 +3,7 @@ use clippy_utils::higher::IfLetOrMatch;
 use clippy_utils::visitors::{for_each_expr, Descend};
 use clippy_utils::{meets_msrv, msrvs, peel_blocks};
 use if_chain::if_chain;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::{Expr, ExprKind, MatchSource, Pat, QPath, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
@@ -201,20 +202,33 @@ fn pat_has_no_bindings(pat: &'_ Pat<'_>) -> bool {
 
 /// Checks if the passed block is a simple identity referring to bindings created by the pattern
 fn expr_is_simple_identity(pat: &'_ Pat<'_>, expr: &'_ Expr<'_>) -> bool {
-    // TODO support patterns with multiple bindings and tuples, like:
+    // We support patterns with multiple bindings and tuples, like:
     //   let ... = if let (Some(foo), bar) = g() { (foo, bar) } else { ... }
-    if_chain! {
-        if let ExprKind::Path(QPath::Resolved(_ty, path)) = &peel_blocks(expr).kind;
-        if let [path_seg] = path.segments;
-        then {
-            let mut pat_bindings = Vec::new();
-            pat.each_binding_or_first(&mut |_ann, _hir_id, _sp, ident| {
-                pat_bindings.push(ident);
-            });
-            if let [binding] = &pat_bindings[..] {
-                return path_seg.ident == *binding;
+    let peeled = peel_blocks(expr);
+    let paths = match peeled.kind {
+        ExprKind::Tup(exprs) | ExprKind::Array(exprs) => exprs,
+        ExprKind::Path(_) => std::slice::from_ref(peeled),
+        _ => return false,
+    };
+    let mut pat_bindings = FxHashSet::default();
+    pat.each_binding_or_first(&mut |_ann, _hir_id, _sp, ident| {
+        pat_bindings.insert(ident);
+    });
+    if pat_bindings.len() < paths.len() {
+        return false;
+    }
+    for path in paths {
+        if_chain! {
+            if let ExprKind::Path(QPath::Resolved(_ty, path)) = path.kind;
+            if let [path_seg] = path.segments;
+            then {
+                if !pat_bindings.remove(&path_seg.ident) {
+                    return false;
+                }
+            } else {
+                return false;
             }
         }
     }
-    false
+    true
 }
diff --git a/tests/ui/manual_let_else.rs b/tests/ui/manual_let_else.rs
index 782f9f394fe..d69e580ff8f 100644
--- a/tests/ui/manual_let_else.rs
+++ b/tests/ui/manual_let_else.rs
@@ -88,6 +88,13 @@ fn fire() {
         return;
     };
 
+    // Tuples supported for the identity block and pattern
+    let v = if let (Some(v_some), w_some) = (g(), 0) {
+        (w_some, v_some)
+    } else {
+        return;
+    };
+
     // entirely inside macro lints
     macro_rules! create_binding_if_some {
         ($n:ident, $e:expr) => {
diff --git a/tests/ui/manual_let_else.stderr b/tests/ui/manual_let_else.stderr
index 9a2c548c5aa..97e6420d705 100644
--- a/tests/ui/manual_let_else.stderr
+++ b/tests/ui/manual_let_else.stderr
@@ -101,7 +101,17 @@ LL | |     };
    | |______^
 
 error: this could be rewritten as `let else`
-  --> $DIR/manual_let_else.rs:94:13
+  --> $DIR/manual_let_else.rs:92:5
+   |
+LL | /     let v = if let (Some(v_some), w_some) = (g(), 0) {
+LL | |         (w_some, v_some)
+LL | |     } else {
+LL | |         return;
+LL | |     };
+   | |______^
+
+error: this could be rewritten as `let else`
+  --> $DIR/manual_let_else.rs:101:13
    |
 LL |             let $n = if let Some(v) = $e { v } else { return };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -111,5 +121,5 @@ LL |     create_binding_if_some!(w, g());
    |
    = note: this error originates in the macro `create_binding_if_some` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 12 previous errors
+error: aborting due to 13 previous errors