Skip to content

Commit 4a2e08a

Browse files
committed
Don't lint irrefutable_let_patterns on leading patterns if else if let-chains.
1 parent 982c6f8 commit 4a2e08a

File tree

3 files changed

+57
-8
lines changed

3 files changed

+57
-8
lines changed

Diff for: compiler/rustc_mir_build/src/thir/pattern/check_match.rs

+18-7
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ enum LetSource {
7979
IfLetGuard,
8080
LetElse,
8181
WhileLet,
82+
Else,
83+
ElseIfLet,
8284
}
8385

8486
struct MatchVisitor<'p, 'tcx> {
@@ -129,15 +131,20 @@ impl<'p, 'tcx> Visitor<'p, 'tcx> for MatchVisitor<'p, 'tcx> {
129131
// Give a specific `let_source` for the condition.
130132
let let_source = match ex.span.desugaring_kind() {
131133
Some(DesugaringKind::WhileLoop) => LetSource::WhileLet,
132-
_ => LetSource::IfLet,
134+
_ => match self.let_source {
135+
LetSource::Else => LetSource::ElseIfLet,
136+
_ => LetSource::IfLet,
137+
},
133138
};
134139
self.with_let_source(let_source, |this| this.visit_expr(&self.thir[cond]));
135140
self.with_let_source(LetSource::None, |this| {
136141
this.visit_expr(&this.thir[then]);
137-
if let Some(else_) = else_opt {
138-
this.visit_expr(&this.thir[else_]);
139-
}
140142
});
143+
if let Some(else_) = else_opt {
144+
self.with_let_source(LetSource::Else, |this| {
145+
this.visit_expr(&this.thir[else_])
146+
});
147+
}
141148
return;
142149
}
143150
ExprKind::Match { scrutinee, scrutinee_hir_id: _, box ref arms, match_source } => {
@@ -569,9 +576,13 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
569576
// and we shouldn't lint.
570577
// For let guards inside a match, prefixes might use bindings of the match pattern,
571578
// so can't always be moved out.
579+
// For `else if let`, an extra indentation level would be required to move the bindings.
572580
// FIXME: Add checking whether the bindings are actually used in the prefix,
573581
// and lint if they are not.
574-
if !matches!(self.let_source, LetSource::WhileLet | LetSource::IfLetGuard) {
582+
if !matches!(
583+
self.let_source,
584+
LetSource::WhileLet | LetSource::IfLetGuard | LetSource::ElseIfLet
585+
) {
575586
// Emit the lint
576587
let prefix = &chain_refutabilities[..until];
577588
let span_start = prefix[0].unwrap().0;
@@ -902,8 +913,8 @@ fn report_irrefutable_let_patterns(
902913
}
903914

904915
match source {
905-
LetSource::None | LetSource::PlainLet => bug!(),
906-
LetSource::IfLet => emit_diag!(IrrefutableLetPatternsIfLet),
916+
LetSource::None | LetSource::PlainLet | LetSource::Else => bug!(),
917+
LetSource::IfLet | LetSource::ElseIfLet => emit_diag!(IrrefutableLetPatternsIfLet),
907918
LetSource::IfLetGuard => emit_diag!(IrrefutableLetPatternsIfLetGuard),
908919
LetSource::LetElse => emit_diag!(IrrefutableLetPatternsLetElse),
909920
LetSource::WhileLet => emit_diag!(IrrefutableLetPatternsWhileLet),

Diff for: tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr

+19-1
Original file line numberDiff line numberDiff line change
@@ -111,5 +111,23 @@ LL | while let Some(ref first) = opt && let second = first && let _third = s
111111
= note: these patterns will always match
112112
= help: consider moving them into the body
113113

114-
error: aborting due to 12 previous errors
114+
error: trailing irrefutable pattern in let chain
115+
--> $DIR/irrefutable-lets.rs:87:12
116+
|
117+
LL | && let x = &opt
118+
| ^^^^^^^^^^^^
119+
|
120+
= note: this pattern will always match
121+
= help: consider moving it into the body
122+
123+
error: leading irrefutable pattern in let chain
124+
--> $DIR/irrefutable-lets.rs:93:12
125+
|
126+
LL | if let x = opt.clone().map(|_| 1)
127+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
128+
|
129+
= note: this pattern will always match
130+
= help: consider moving it outside of the construct
131+
132+
error: aborting due to 14 previous errors
115133

Diff for: tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs

+20
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,24 @@ fn main() {
7575
&& let Range { start: local_start, end: _ } = first
7676
&& let None = local_start {
7777
}
78+
79+
// No error. An extra nesting level would be required for the `else if`.
80+
if opt == Some(None..None) {
81+
} else if let x = opt.clone().map(|_| 1)
82+
&& x == Some(1)
83+
{}
84+
85+
if opt == Some(None..None) {
86+
} else if opt.is_some()
87+
&& let x = &opt
88+
//[disallowed]~^ ERROR trailing irrefutable pattern in let chain
89+
{}
90+
91+
if opt == Some(None..None) {
92+
} else {
93+
if let x = opt.clone().map(|_| 1)
94+
//[disallowed]~^ ERROR leading irrefutable pattern in let chain
95+
&& x == Some(1)
96+
{}
97+
}
7898
}

0 commit comments

Comments
 (0)