Skip to content

Commit c5a7696

Browse files
committed
Support tuples
1 parent 2e01e6b commit c5a7696

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;
@@ -201,20 +202,33 @@ fn pat_has_no_bindings(pat: &'_ Pat<'_>) -> bool {
201202

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

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)