Skip to content

Commit 8a9b79a

Browse files
committed
Support tuples
1 parent 05b5261 commit 8a9b79a

File tree

3 files changed

+45
-14
lines changed

3 files changed

+45
-14
lines changed

clippy_lints/src/manual_let_else.rs

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use clippy_utils::higher::IfLetOrMatch;
33
use clippy_utils::visitors::{for_each_expr, Descend};
44
use clippy_utils::{meets_msrv, msrvs, peel_blocks};
55
use if_chain::if_chain;
6+
use rustc_data_structures::fx::FxHashSet;
67
use rustc_hir::{Expr, ExprKind, MatchSource, Pat, QPath, Stmt, StmtKind};
78
use rustc_lint::{LateContext, LateLintPass, LintContext};
89
use rustc_middle::lint::in_external_macro;
@@ -206,20 +207,33 @@ fn pat_has_no_bindings(pat: &'_ Pat<'_>) -> bool {
206207

207208
/// Checks if the passed block is a simple identity referring to bindings created by the pattern
208209
fn expr_is_simple_identity(pat: &'_ Pat<'_>, expr: &'_ Expr<'_>) -> bool {
209-
// TODO support patterns with multiple bindings and tuples, like:
210+
// We support patterns with multiple bindings and tuples, like:
210211
// let ... = if let (Some(foo), bar) = g() { (foo, bar) } else { ... }
211-
if_chain! {
212-
if let ExprKind::Path(QPath::Resolved(_ty, path)) = &peel_blocks(expr).kind;
213-
if let [path_seg] = path.segments;
214-
then {
215-
let mut pat_bindings = Vec::new();
216-
pat.each_binding_or_first(&mut |_ann, _hir_id, _sp, ident| {
217-
pat_bindings.push(ident);
218-
});
219-
if let [binding] = &pat_bindings[..] {
220-
return path_seg.ident == *binding;
212+
let peeled = peel_blocks(expr);
213+
let paths = match peeled.kind {
214+
ExprKind::Tup(exprs) | ExprKind::Array(exprs) => exprs,
215+
ExprKind::Path(_) => std::slice::from_ref(peeled),
216+
_ => return false,
217+
};
218+
let mut pat_bindings = FxHashSet::default();
219+
pat.each_binding_or_first(&mut |_ann, _hir_id, _sp, ident| {
220+
pat_bindings.insert(ident);
221+
});
222+
if pat_bindings.len() < paths.len() {
223+
return false;
224+
}
225+
for path in paths {
226+
if_chain! {
227+
if let ExprKind::Path(QPath::Resolved(_ty, path)) = path.kind;
228+
if let [path_seg] = path.segments;
229+
then {
230+
if !pat_bindings.remove(&path_seg.ident) {
231+
return false;
232+
}
233+
} else {
234+
return false;
221235
}
222236
}
223237
}
224-
false
238+
true
225239
}

tests/ui/manual_let_else.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,13 @@ fn fire() {
8888
return;
8989
};
9090

91+
// Tuples supported for the identity block and pattern
92+
let v = if let (Some(v_some), w_some) = (g(), 0) {
93+
(w_some, v_some)
94+
} else {
95+
return;
96+
};
97+
9198
// entirely inside macro lints
9299
macro_rules! create_binding_if_some {
93100
($n:ident, $e:expr) => {

tests/ui/manual_let_else.stderr

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,17 @@ LL | | };
101101
| |______^
102102

103103
error: this could be rewritten as `let else`
104-
--> $DIR/manual_let_else.rs:94:13
104+
--> $DIR/manual_let_else.rs:92:5
105+
|
106+
LL | / let v = if let (Some(v_some), w_some) = (g(), 0) {
107+
LL | | (w_some, v_some)
108+
LL | | } else {
109+
LL | | return;
110+
LL | | };
111+
| |______^
112+
113+
error: this could be rewritten as `let else`
114+
--> $DIR/manual_let_else.rs:101:13
105115
|
106116
LL | let $n = if let Some(v) = $e { v } else { return };
107117
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -111,5 +121,5 @@ LL | create_binding_if_some!(w, g());
111121
|
112122
= note: this error originates in the macro `create_binding_if_some` (in Nightly builds, run with -Z macro-backtrace for more info)
113123

114-
error: aborting due to 12 previous errors
124+
error: aborting due to 13 previous errors
115125

0 commit comments

Comments
 (0)