Skip to content

Commit

Permalink
Rollup merge of rust-lang#107213 - edward-shen:edward-shen/fix-accide…
Browse files Browse the repository at this point in the history
…ntal-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 rust-lang#103791.
  • Loading branch information
Dylan-DPC authored Jan 24, 2023
2 parents 2103027 + a8b77cf commit ec1ac0e
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 14 deletions.
1 change: 1 addition & 0 deletions compiler/rustc_error_messages/locales/en-US/parse.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ parse_const_let_mutually_exclusive = `const` and `let` are mutually exclusive
parse_invalid_expression_in_let_else = a `{$operator}` expression cannot be directly assigned in `let...else`
parse_invalid_curly_in_let_else = right curly brace `{"}"}` before `else` in a `let...else` statement not allowed
parse_extra_if_in_let_else = remove the `if` if you meant to write a `let...else` statement
parse_compound_assignment_expression_in_let = can't reassign to an uninitialized variable
.suggestion = initialize the variable
Expand Down
11 changes: 10 additions & 1 deletion compiler/rustc_parse/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,9 @@ pub(crate) struct IfExpressionMissingThenBlock {
#[primary_span]
pub if_span: Span,
#[subdiagnostic]
pub sub: IfExpressionMissingThenBlockSub,
pub missing_then_block_sub: IfExpressionMissingThenBlockSub,
#[subdiagnostic]
pub let_else_sub: Option<IfExpressionLetSomeSub>,
}

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

#[derive(Subdiagnostic)]
#[help(parse_extra_if_in_let_else)]
pub(crate) struct IfExpressionLetSomeSub {
#[primary_span]
pub if_span: Span,
}

#[derive(Diagnostic)]
#[diag(parse_if_expression_missing_condition)]
pub(crate) struct IfExpressionMissingCondition {
Expand Down
33 changes: 20 additions & 13 deletions compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ use crate::errors::{
ComparisonOrShiftInterpretedAsGenericSugg, DoCatchSyntaxRemoved, DotDotDot, EqFieldInit,
ExpectedElseBlock, ExpectedEqForLetExpr, ExpectedExpressionFoundLet,
FieldExpressionWithGeneric, FloatLiteralRequiresIntegerPart, FoundExprWouldBeStmt,
IfExpressionMissingCondition, IfExpressionMissingThenBlock, IfExpressionMissingThenBlockSub,
InvalidBlockMacroSegment, InvalidComparisonOperator, InvalidComparisonOperatorSub,
InvalidInterpolatedExpression, InvalidLiteralSuffixOnTupleIndex, InvalidLogicalOperator,
InvalidLogicalOperatorSub, LabeledLoopInBreak, LeadingPlusNotSupported, LeftArrowOperator,
LifetimeInBorrowExpression, MacroInvocationWithQualifiedPath, MalformedLoopLabel,
MatchArmBodyWithoutBraces, MatchArmBodyWithoutBracesSugg, MissingCommaAfterMatchArm,
MissingDotDot, MissingInInForLoop, MissingInInForLoopSub, MissingSemicolonBeforeArray,
NoFieldsForFnCall, NotAsNegationOperator, NotAsNegationOperatorSub,
OuterAttributeNotAllowedOnIfElse, ParenthesesWithStructFields,
IfExpressionLetSomeSub, IfExpressionMissingCondition, IfExpressionMissingThenBlock,
IfExpressionMissingThenBlockSub, InvalidBlockMacroSegment, InvalidComparisonOperator,
InvalidComparisonOperatorSub, InvalidInterpolatedExpression, InvalidLiteralSuffixOnTupleIndex,
InvalidLogicalOperator, InvalidLogicalOperatorSub, LabeledLoopInBreak, LeadingPlusNotSupported,
LeftArrowOperator, LifetimeInBorrowExpression, MacroInvocationWithQualifiedPath,
MalformedLoopLabel, MatchArmBodyWithoutBraces, MatchArmBodyWithoutBracesSugg,
MissingCommaAfterMatchArm, MissingDotDot, MissingInInForLoop, MissingInInForLoopSub,
MissingSemicolonBeforeArray, NoFieldsForFnCall, NotAsNegationOperator,
NotAsNegationOperatorSub, OuterAttributeNotAllowedOnIfElse, ParenthesesWithStructFields,
RequireColonAfterLabeledExpression, ShiftInterpretedAsGeneric, StructLiteralNotAllowedHere,
StructLiteralNotAllowedHereSugg, TildeAsUnaryOperator, UnexpectedIfWithIf,
UnexpectedTokenAfterLabel, UnexpectedTokenAfterLabelSugg, WrapExpressionInParentheses,
Expand Down Expand Up @@ -2251,9 +2251,10 @@ impl<'a> Parser<'a> {
if let ExprKind::Block(_, None) = right.kind => {
self.sess.emit_err(IfExpressionMissingThenBlock {
if_span: lo,
sub: IfExpressionMissingThenBlockSub::UnfinishedCondition(
cond_span.shrink_to_lo().to(*binop_span)
),
missing_then_block_sub:
IfExpressionMissingThenBlockSub::UnfinishedCondition(cond_span.shrink_to_lo().to(*binop_span)),
let_else_sub: None,

});
std::mem::replace(right, this.mk_expr_err(binop_span.shrink_to_hi()))
},
Expand All @@ -2279,9 +2280,15 @@ impl<'a> Parser<'a> {
if let Some(block) = recover_block_from_condition(self) {
block
} else {
let let_else_sub = matches!(cond.kind, ExprKind::Let(..))
.then(|| IfExpressionLetSomeSub { if_span: lo });

self.sess.emit_err(IfExpressionMissingThenBlock {
if_span: lo,
sub: IfExpressionMissingThenBlockSub::AddThenBlock(cond_span.shrink_to_hi()),
missing_then_block_sub: IfExpressionMissingThenBlockSub::AddThenBlock(
cond_span.shrink_to_hi(),
),
let_else_sub,
});
self.mk_block_err(cond_span.shrink_to_hi())
}
Expand Down
6 changes: 6 additions & 0 deletions tests/ui/let-else/accidental-if.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
fn main() {
let x = Some(123);
if let Some(y) = x else { //~ ERROR this `if` expression is missing a block
return;
};
}
19 changes: 19 additions & 0 deletions tests/ui/let-else/accidental-if.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
error: this `if` expression is missing a block after the condition
--> $DIR/accidental-if.rs:3:5
|
LL | if let Some(y) = x else {
| ^^
|
help: add a block here
--> $DIR/accidental-if.rs:3:23
|
LL | if let Some(y) = x else {
| ^
help: remove the `if` if you meant to write a `let...else` statement
--> $DIR/accidental-if.rs:3:5
|
LL | if let Some(y) = x else {
| ^^

error: aborting due to previous error

Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ help: add a block here
|
LL | if let Some(n) = opt else {
| ^
help: remove the `if` if you meant to write a `let...else` statement
--> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:24:5
|
LL | if let Some(n) = opt else {
| ^^

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

0 comments on commit ec1ac0e

Please sign in to comment.