Skip to content

Commit 4e2b5d1

Browse files
authored
Rollup merge of #107213 - edward-shen:edward-shen/fix-accidental-let-else, r=compiler-errors
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 expression. This is likely that the user has accidentally mixed if-let and let..else together. Fixes #103791.
2 parents a788ce2 + a8b77cf commit 4e2b5d1

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

+1
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

+10-1
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

+20-13
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

+6
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+
}
+19
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

+5
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)