Skip to content

Commit a8b77cf

Browse files
committed
Add suggestion to remove if in let...else block
Adds an additional hint to failures where we encounter an else keyword while we're parsing an if-let block. This is likely that the user has accidentally mixed if-let and let...else together.
1 parent c8e6a9e commit a8b77cf

File tree

6 files changed

+61
-14
lines changed

6 files changed

+61
-14
lines changed

compiler/rustc_error_messages/locales/en-US/parse.ftl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ parse_const_let_mutually_exclusive = `const` and `let` are mutually exclusive
238238
239239
parse_invalid_expression_in_let_else = a `{$operator}` expression cannot be directly assigned in `let...else`
240240
parse_invalid_curly_in_let_else = right curly brace `{"}"}` before `else` in a `let...else` statement not allowed
241+
parse_extra_if_in_let_else = remove the `if` if you meant to write a `let...else` statement
241242
242243
parse_compound_assignment_expression_in_let = can't reassign to an uninitialized variable
243244
.suggestion = initialize the variable

compiler/rustc_parse/src/errors.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,9 @@ pub(crate) struct IfExpressionMissingThenBlock {
337337
#[primary_span]
338338
pub if_span: Span,
339339
#[subdiagnostic]
340-
pub sub: IfExpressionMissingThenBlockSub,
340+
pub missing_then_block_sub: IfExpressionMissingThenBlockSub,
341+
#[subdiagnostic]
342+
pub let_else_sub: Option<IfExpressionLetSomeSub>,
341343
}
342344

343345
#[derive(Subdiagnostic)]
@@ -348,6 +350,13 @@ pub(crate) enum IfExpressionMissingThenBlockSub {
348350
AddThenBlock(#[primary_span] Span),
349351
}
350352

353+
#[derive(Subdiagnostic)]
354+
#[help(parse_extra_if_in_let_else)]
355+
pub(crate) struct IfExpressionLetSomeSub {
356+
#[primary_span]
357+
pub if_span: Span,
358+
}
359+
351360
#[derive(Diagnostic)]
352361
#[diag(parse_if_expression_missing_condition)]
353362
pub(crate) struct IfExpressionMissingCondition {

compiler/rustc_parse/src/parser/expr.rs

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ use crate::errors::{
1111
ComparisonOrShiftInterpretedAsGenericSugg, DoCatchSyntaxRemoved, DotDotDot, EqFieldInit,
1212
ExpectedElseBlock, ExpectedEqForLetExpr, ExpectedExpressionFoundLet,
1313
FieldExpressionWithGeneric, FloatLiteralRequiresIntegerPart, FoundExprWouldBeStmt,
14-
IfExpressionMissingCondition, IfExpressionMissingThenBlock, IfExpressionMissingThenBlockSub,
15-
InvalidBlockMacroSegment, InvalidComparisonOperator, InvalidComparisonOperatorSub,
16-
InvalidInterpolatedExpression, InvalidLiteralSuffixOnTupleIndex, InvalidLogicalOperator,
17-
InvalidLogicalOperatorSub, LabeledLoopInBreak, LeadingPlusNotSupported, LeftArrowOperator,
18-
LifetimeInBorrowExpression, MacroInvocationWithQualifiedPath, MalformedLoopLabel,
19-
MatchArmBodyWithoutBraces, MatchArmBodyWithoutBracesSugg, MissingCommaAfterMatchArm,
20-
MissingDotDot, MissingInInForLoop, MissingInInForLoopSub, MissingSemicolonBeforeArray,
21-
NoFieldsForFnCall, NotAsNegationOperator, NotAsNegationOperatorSub,
22-
OuterAttributeNotAllowedOnIfElse, ParenthesesWithStructFields,
14+
IfExpressionLetSomeSub, IfExpressionMissingCondition, IfExpressionMissingThenBlock,
15+
IfExpressionMissingThenBlockSub, InvalidBlockMacroSegment, InvalidComparisonOperator,
16+
InvalidComparisonOperatorSub, InvalidInterpolatedExpression, InvalidLiteralSuffixOnTupleIndex,
17+
InvalidLogicalOperator, InvalidLogicalOperatorSub, LabeledLoopInBreak, LeadingPlusNotSupported,
18+
LeftArrowOperator, LifetimeInBorrowExpression, MacroInvocationWithQualifiedPath,
19+
MalformedLoopLabel, MatchArmBodyWithoutBraces, MatchArmBodyWithoutBracesSugg,
20+
MissingCommaAfterMatchArm, MissingDotDot, MissingInInForLoop, MissingInInForLoopSub,
21+
MissingSemicolonBeforeArray, NoFieldsForFnCall, NotAsNegationOperator,
22+
NotAsNegationOperatorSub, OuterAttributeNotAllowedOnIfElse, ParenthesesWithStructFields,
2323
RequireColonAfterLabeledExpression, ShiftInterpretedAsGeneric, StructLiteralNotAllowedHere,
2424
StructLiteralNotAllowedHereSugg, TildeAsUnaryOperator, UnexpectedIfWithIf,
2525
UnexpectedTokenAfterLabel, UnexpectedTokenAfterLabelSugg, WrapExpressionInParentheses,
@@ -2251,9 +2251,10 @@ impl<'a> Parser<'a> {
22512251
if let ExprKind::Block(_, None) = right.kind => {
22522252
self.sess.emit_err(IfExpressionMissingThenBlock {
22532253
if_span: lo,
2254-
sub: IfExpressionMissingThenBlockSub::UnfinishedCondition(
2255-
cond_span.shrink_to_lo().to(*binop_span)
2256-
),
2254+
missing_then_block_sub:
2255+
IfExpressionMissingThenBlockSub::UnfinishedCondition(cond_span.shrink_to_lo().to(*binop_span)),
2256+
let_else_sub: None,
2257+
22572258
});
22582259
std::mem::replace(right, this.mk_expr_err(binop_span.shrink_to_hi()))
22592260
},
@@ -2279,9 +2280,15 @@ impl<'a> Parser<'a> {
22792280
if let Some(block) = recover_block_from_condition(self) {
22802281
block
22812282
} else {
2283+
let let_else_sub = matches!(cond.kind, ExprKind::Let(..))
2284+
.then(|| IfExpressionLetSomeSub { if_span: lo });
2285+
22822286
self.sess.emit_err(IfExpressionMissingThenBlock {
22832287
if_span: lo,
2284-
sub: IfExpressionMissingThenBlockSub::AddThenBlock(cond_span.shrink_to_hi()),
2288+
missing_then_block_sub: IfExpressionMissingThenBlockSub::AddThenBlock(
2289+
cond_span.shrink_to_hi(),
2290+
),
2291+
let_else_sub,
22852292
});
22862293
self.mk_block_err(cond_span.shrink_to_hi())
22872294
}

tests/ui/let-else/accidental-if.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
fn main() {
2+
let x = Some(123);
3+
if let Some(y) = x else { //~ ERROR this `if` expression is missing a block
4+
return;
5+
};
6+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error: this `if` expression is missing a block after the condition
2+
--> $DIR/accidental-if.rs:3:5
3+
|
4+
LL | if let Some(y) = x else {
5+
| ^^
6+
|
7+
help: add a block here
8+
--> $DIR/accidental-if.rs:3:23
9+
|
10+
LL | if let Some(y) = x else {
11+
| ^
12+
help: remove the `if` if you meant to write a `let...else` statement
13+
--> $DIR/accidental-if.rs:3:5
14+
|
15+
LL | if let Some(y) = x else {
16+
| ^^
17+
18+
error: aborting due to previous error
19+

tests/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.stderr

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ help: add a block here
3737
|
3838
LL | if let Some(n) = opt else {
3939
| ^
40+
help: remove the `if` if you meant to write a `let...else` statement
41+
--> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:24:5
42+
|
43+
LL | if let Some(n) = opt else {
44+
| ^^
4045

4146
error: this `if` expression is missing a block after the condition
4247
--> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:28:5

0 commit comments

Comments
 (0)