Skip to content

Commit bc1cee6

Browse files
committed
Support tuples
1 parent dfe1d3e commit bc1cee6

File tree

3 files changed

+52
-34
lines changed

3 files changed

+52
-34
lines changed

clippy_lints/src/manual_let_else.rs

+26-12
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use rustc_hir::{Expr, ExprKind, MatchSource, Pat, QPath, Stmt, StmtKind};
88
use rustc_lint::{LateContext, LateLintPass, LintContext};
99
use rustc_middle::lint::in_external_macro;
1010
use rustc_semver::RustcVersion;
11+
use rustc_data_structures::stable_set::FxHashSet;
1112
use rustc_session::{declare_tool_lint, impl_lint_pass};
1213
use rustc_span::Span;
1314

@@ -205,20 +206,33 @@ fn pat_has_no_bindings(pat: &'_ Pat<'_>) -> bool {
205206

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

tests/ui/manual_let_else.rs

+10-12
Original file line numberDiff line numberDiff line change
@@ -83,18 +83,20 @@ fn fire() {
8383
return;
8484
};
8585

86+
// Tuples supported for the identity block and pattern
87+
let v = if let (Some(v_some), w_some) = (g(), 0) {
88+
(w_some, v_some)
89+
} else {
90+
return;
91+
};
92+
8693
// entirely inside macro lints
8794
macro_rules! create_binding_if_some {
8895
($n:ident, $e:expr) => {
89-
let $n = if let Some(v) = $e {
90-
v
91-
} else {
92-
return
93-
};
96+
let $n = if let Some(v) = $e { v } else { return };
9497
};
9598
}
9699
create_binding_if_some!(w, g());
97-
98100
}
99101

100102
fn not_fire() {
@@ -164,11 +166,7 @@ fn not_fire() {
164166
// Macro boundary inside let
165167
macro_rules! some_or_return {
166168
($e:expr) => {
167-
if let Some(v) = $e {
168-
v
169-
} else {
170-
return
171-
}
169+
if let Some(v) = $e { v } else { return }
172170
};
173171
}
174172
let v = some_or_return!(g());
@@ -180,4 +178,4 @@ fn not_fire() {
180178
};
181179
}
182180
create_binding_if_some!(v, g());
183-
}
181+
}

tests/ui/manual_let_else.stderr

+16-10
Original file line numberDiff line numberDiff line change
@@ -101,19 +101,25 @@ LL | | };
101101
| |______^
102102

103103
error: this could be rewritten as `let else`
104-
--> $DIR/manual_let_else.rs:89:13
104+
--> $DIR/manual_let_else.rs:87:5
105105
|
106-
LL | / let $n = if let Some(v) = $e {
107-
LL | | v
108-
LL | | } else {
109-
LL | | return
110-
LL | | };
111-
| |______________^
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:96:13
115+
|
116+
LL | let $n = if let Some(v) = $e { v } else { return };
117+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
112118
...
113-
LL | create_binding_if_some!(w, g());
114-
| ------------------------------- in this macro invocation
119+
LL | create_binding_if_some!(w, g());
120+
| ------------------------------- in this macro invocation
115121
|
116122
= note: this error originates in the macro `create_binding_if_some` (in Nightly builds, run with -Z macro-backtrace for more info)
117123

118-
error: aborting due to 12 previous errors
124+
error: aborting due to 13 previous errors
119125

0 commit comments

Comments
 (0)