Skip to content

Commit 7cf09c5

Browse files
authored
Rollup merge of #103031 - est31:match_guard_irrefutable_let, r=oli-obk
Suppress irrefutable let patterns lint for prefixes in match guards In match guards, irrefutable prefixes might use the bindings created by the match pattern. Ideally, we check for this, but we can do the next best thing and just not lint for irrefutable prefixes in match guards. Fixes #98361
2 parents 587b9c1 + eab41a1 commit 7cf09c5

File tree

3 files changed

+36
-19
lines changed

3 files changed

+36
-19
lines changed

compiler/rustc_mir_build/src/thir/pattern/check_match.rs

+13-5
Original file line numberDiff line numberDiff line change
@@ -370,8 +370,12 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
370370

371371
// Check if the let source is while, for there is no alternative place to put a prefix,
372372
// and we shouldn't lint.
373+
// For let guards inside a match, prefixes might use bindings of the match pattern,
374+
// so can't always be moved out.
375+
// FIXME: Add checking whether the bindings are actually used in the prefix,
376+
// and lint if they are not.
373377
let let_source = let_source_parent(self.tcx, top, None);
374-
if !matches!(let_source, LetSource::WhileLet) {
378+
if !matches!(let_source, LetSource::WhileLet | LetSource::IfLetGuard) {
375379
// Emit the lint
376380
let prefix = &chain_refutabilities[..until];
377381
lint_affix(prefix, "leading", "outside of the construct");
@@ -1151,10 +1155,14 @@ fn let_source_parent(tcx: TyCtxt<'_>, parent: HirId, pat_id: Option<HirId>) -> L
11511155

11521156
let parent_parent = hir.get_parent_node(parent);
11531157
let parent_parent_node = hir.get(parent_parent);
1154-
if let hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(_), span, .. }) =
1155-
parent_parent_node
1156-
{
1157-
return LetSource::LetElse(*span);
1158+
match parent_parent_node {
1159+
hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(_), span, .. }) => {
1160+
return LetSource::LetElse(*span);
1161+
}
1162+
hir::Node::Arm(hir::Arm { guard: Some(hir::Guard::If(_)), .. }) => {
1163+
return LetSource::IfLetGuard;
1164+
}
1165+
_ => {}
11581166
}
11591167

11601168
let parent_parent_parent = hir.get_parent_node(parent_parent);

src/test/ui/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr

+11-11
Original file line numberDiff line numberDiff line change
@@ -75,26 +75,26 @@ LL | if let first = &opt && let None = Some(1) {}
7575
= note: this pattern will always match
7676
= help: consider moving it outside of the construct
7777

78-
error: irrefutable `let` patterns
78+
error: irrefutable `if let` guard patterns
7979
--> $DIR/irrefutable-lets.rs:44:28
8080
|
8181
LL | Some(ref first) if let second = first && let _third = second && let v = 4 + 4 => {},
8282
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8383
|
84-
= note: these patterns will always match, so the `let` is useless
85-
= help: consider removing `let`
84+
= note: these patterns will always match, so the guard is useless
85+
= help: consider removing the guard and adding a `let` inside the match arm
8686

87-
error: leading irrefutable pattern in let chain
88-
--> $DIR/irrefutable-lets.rs:50:28
87+
error: trailing irrefutable patterns in let chain
88+
--> $DIR/irrefutable-lets.rs:59:16
8989
|
90-
LL | Some(ref first) if let Range { start: local_start, end: _ } = first
91-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
90+
LL | && let v = local_end && let w = v => {},
91+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
9292
|
93-
= note: this pattern will always match
94-
= help: consider moving it outside of the construct
93+
= note: these patterns will always match
94+
= help: consider moving them into the body
9595

9696
error: irrefutable `while let` patterns
97-
--> $DIR/irrefutable-lets.rs:59:11
97+
--> $DIR/irrefutable-lets.rs:68:11
9898
|
9999
LL | while let first = &opt && let (a, b) = (1, 2) {}
100100
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -103,7 +103,7 @@ LL | while let first = &opt && let (a, b) = (1, 2) {}
103103
= help: consider instead using a `loop { ... }` with a `let` inside it
104104

105105
error: trailing irrefutable patterns in let chain
106-
--> $DIR/irrefutable-lets.rs:62:40
106+
--> $DIR/irrefutable-lets.rs:71:40
107107
|
108108
LL | while let Some(ref first) = opt && let second = first && let _third = second {}
109109
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

src/test/ui/rfc-2497-if-let-chains/irrefutable-lets.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -42,18 +42,27 @@ fn main() {
4242

4343
match opt {
4444
Some(ref first) if let second = first && let _third = second && let v = 4 + 4 => {},
45-
//[disallowed]~^ ERROR irrefutable `let` patterns
45+
//[disallowed]~^ ERROR irrefutable `if let` guard patterns
4646
_ => {}
4747
}
4848

49+
// No error about leading irrefutable patterns: the expr on the rhs might
50+
// use the bindings created by the match.
4951
match opt {
5052
Some(ref first) if let Range { start: local_start, end: _ } = first
51-
//[disallowed]~^ ERROR leading irrefutable pattern in let chain
5253
&& let None = local_start => {},
5354
_ => {}
5455
}
5556

56-
// No error, despite the prefix being irrefutable
57+
match opt {
58+
Some(ref first) if let Range { start: Some(_), end: local_end } = first
59+
&& let v = local_end && let w = v => {},
60+
//[disallowed]~^ ERROR trailing irrefutable patterns in let chain
61+
_ => {}
62+
}
63+
64+
// No error, despite the prefix being irrefutable: moving out could change the behaviour,
65+
// due to possible side effects of the operation.
5766
while let first = &opt && let Some(ref second) = first && let None = second.start {}
5867

5968
while let first = &opt && let (a, b) = (1, 2) {}

0 commit comments

Comments
 (0)