Skip to content

Commit b9dce52

Browse files
committed
matches: Peel subpatterns in bindings
1 parent cd3857a commit b9dce52

File tree

4 files changed

+49
-15
lines changed

4 files changed

+49
-15
lines changed

clippy_lints/src/matches.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -862,8 +862,17 @@ fn contains_only_known_enums(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
862862
}
863863
}
864864

865+
fn peel_subpatterns<'a>(pat: &'a Pat<'a>) -> &'a Pat<'a> {
866+
if let PatKind::Binding(.., Some(sub)) = pat.kind {
867+
return peel_subpatterns(sub);
868+
}
869+
pat
870+
}
871+
865872
/// Returns true if the patterns exhaustively match an enum.
866873
fn check_exhaustive<'a>(cx: &LateContext<'a>, left: &Pat<'_>, right: &Pat<'_>, ty: Ty<'a>) -> bool {
874+
let left = peel_subpatterns(left);
875+
let right = peel_subpatterns(right);
867876
match (&left.kind, &right.kind) {
868877
(PatKind::Wild, _) | (_, PatKind::Wild) => true,
869878
(PatKind::Tuple(left_in, left_pos), PatKind::Tuple(right_in, right_pos)) => {
@@ -876,17 +885,13 @@ fn check_exhaustive<'a>(cx: &LateContext<'a>, left: &Pat<'_>, right: &Pat<'_>, t
876885
let are_structs_with_the_same_name =
877886
|| -> bool { cx.qpath_res(left_qpath, left.hir_id) == cx.qpath_res(right_qpath, right.hir_id) };
878887
let are_known_enums =
879-
|| -> bool { contains_only_known_enums(cx, left) && contains_only_known_enums(cx, right) };
888+
|| -> bool { contains_only_known_enums(cx, &left) && contains_only_known_enums(cx, &right) };
880889
if are_structs_with_the_same_name() || are_known_enums() {
881890
return check_exhaustive_tuples(cx, left_in, left_pos, right_in, right_pos);
882891
}
883892
false
884893
},
885-
(PatKind::Binding(.., None) | PatKind::Path(_), _)
886-
if contains_only_wilds(right) =>
887-
{
888-
is_known_enum(cx, ty)
889-
},
894+
(PatKind::Binding(.., None) | PatKind::Path(_), _) if contains_only_wilds(&right) => is_known_enum(cx, ty),
890895
_ => false,
891896
}
892897
}
@@ -959,7 +964,7 @@ fn contains_only_wilds(pat: &Pat<'_>) -> bool {
959964

960965
fn contains_single_binding(pat: &Pat<'_>) -> bool {
961966
match pat.kind {
962-
PatKind::Binding(BindingAnnotation::Unannotated, .., None) => true,
967+
PatKind::Binding(.., None) => true,
963968
PatKind::TupleStruct(_, inner, ..) => inner.iter().all(contains_single_binding),
964969
_ => false,
965970
}

tests/ui/patterns.stderr

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,16 @@ error: the `x @ _` pattern can be written as just `x`
1818
LL | ref x @ _ => println!("vec: {:?}", x),
1919
| ^^^^^^^^^ help: try: `ref x`
2020

21-
error: aborting due to 3 previous errors
21+
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
22+
--> $DIR/patterns.rs:8:5
23+
|
24+
LL | / match v {
25+
LL | | Some(x) => (),
26+
LL | | y @ _ => (),
27+
LL | | }
28+
| |_____^ help: try this: `if let Some(x) = v { () }`
29+
|
30+
= note: `-D clippy::single-match` implied by `-D warnings`
31+
32+
error: aborting due to 4 previous errors
2233

tests/ui/single_match.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -203,22 +203,31 @@ fn annotated_bindings() {
203203

204204
match Some(S(1i32)) {
205205
Some(a) => {},
206-
_ => ()
206+
_ => (),
207207
}
208208

209209
match x {
210210
Some(ref a) => {},
211-
_ => ()
211+
_ => (),
212212
}
213213

214214
match x {
215215
Some(mut a) => {},
216-
_ => ()
216+
_ => (),
217217
}
218218

219219
match Some(S(1i32)) {
220220
Some(ref mut a) => {},
221-
_ => ()
221+
_ => (),
222+
}
223+
}
224+
225+
fn binding_subpatterns() {
226+
struct S(i32);
227+
let x = S(1);
228+
match x {
229+
S(aa @ 42) => {},
230+
S(_) => {},
222231
}
223232
}
224233

tests/ui/single_match.stderr

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,16 @@ LL | | }
183183
| |_____^ help: try this: `if let Some(ref mut a) = Some(S(1i32)) {}`
184184

185185
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
186-
--> $DIR/single_match.rs:230:5
186+
--> $DIR/single_match.rs:228:5
187+
|
188+
LL | / match x {
189+
LL | | S(aa @ 42) => {},
190+
LL | | S(_) => {},
191+
LL | | }
192+
| |_____^ help: try this: `if let S(aa @ 42) = x {}`
193+
194+
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
195+
--> $DIR/single_match.rs:239:5
187196
|
188197
LL | / match s {
189198
LL | | S(42, _a) => {},
@@ -192,13 +201,13 @@ LL | | }
192201
| |_____^ help: try this: `if let S(42, _a) = s {}`
193202

194203
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
195-
--> $DIR/single_match.rs:236:5
204+
--> $DIR/single_match.rs:245:5
196205
|
197206
LL | / match s {
198207
LL | | S(42, _a) => {},
199208
LL | | S(..) => {},
200209
LL | | }
201210
| |_____^ help: try this: `if let S(42, _a) = s {}`
202211

203-
error: aborting due to 21 previous errors
212+
error: aborting due to 22 previous errors
204213

0 commit comments

Comments
 (0)