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.
This commit is contained in:
commit
4e2b5d1f54
@ -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_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_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
|
parse_compound_assignment_expression_in_let = can't reassign to an uninitialized variable
|
||||||
.suggestion = initialize the variable
|
.suggestion = initialize the variable
|
||||||
|
@ -337,7 +337,9 @@ pub(crate) struct IfExpressionMissingThenBlock {
|
|||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub if_span: Span,
|
pub if_span: Span,
|
||||||
#[subdiagnostic]
|
#[subdiagnostic]
|
||||||
pub sub: IfExpressionMissingThenBlockSub,
|
pub missing_then_block_sub: IfExpressionMissingThenBlockSub,
|
||||||
|
#[subdiagnostic]
|
||||||
|
pub let_else_sub: Option<IfExpressionLetSomeSub>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
@ -348,6 +350,13 @@ pub(crate) enum IfExpressionMissingThenBlockSub {
|
|||||||
AddThenBlock(#[primary_span] Span),
|
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)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(parse_if_expression_missing_condition)]
|
#[diag(parse_if_expression_missing_condition)]
|
||||||
pub(crate) struct IfExpressionMissingCondition {
|
pub(crate) struct IfExpressionMissingCondition {
|
||||||
|
@ -11,15 +11,15 @@ use crate::errors::{
|
|||||||
ComparisonOrShiftInterpretedAsGenericSugg, DoCatchSyntaxRemoved, DotDotDot, EqFieldInit,
|
ComparisonOrShiftInterpretedAsGenericSugg, DoCatchSyntaxRemoved, DotDotDot, EqFieldInit,
|
||||||
ExpectedElseBlock, ExpectedEqForLetExpr, ExpectedExpressionFoundLet,
|
ExpectedElseBlock, ExpectedEqForLetExpr, ExpectedExpressionFoundLet,
|
||||||
FieldExpressionWithGeneric, FloatLiteralRequiresIntegerPart, FoundExprWouldBeStmt,
|
FieldExpressionWithGeneric, FloatLiteralRequiresIntegerPart, FoundExprWouldBeStmt,
|
||||||
IfExpressionMissingCondition, IfExpressionMissingThenBlock, IfExpressionMissingThenBlockSub,
|
IfExpressionLetSomeSub, IfExpressionMissingCondition, IfExpressionMissingThenBlock,
|
||||||
InvalidBlockMacroSegment, InvalidComparisonOperator, InvalidComparisonOperatorSub,
|
IfExpressionMissingThenBlockSub, InvalidBlockMacroSegment, InvalidComparisonOperator,
|
||||||
InvalidInterpolatedExpression, InvalidLiteralSuffixOnTupleIndex, InvalidLogicalOperator,
|
InvalidComparisonOperatorSub, InvalidInterpolatedExpression, InvalidLiteralSuffixOnTupleIndex,
|
||||||
InvalidLogicalOperatorSub, LabeledLoopInBreak, LeadingPlusNotSupported, LeftArrowOperator,
|
InvalidLogicalOperator, InvalidLogicalOperatorSub, LabeledLoopInBreak, LeadingPlusNotSupported,
|
||||||
LifetimeInBorrowExpression, MacroInvocationWithQualifiedPath, MalformedLoopLabel,
|
LeftArrowOperator, LifetimeInBorrowExpression, MacroInvocationWithQualifiedPath,
|
||||||
MatchArmBodyWithoutBraces, MatchArmBodyWithoutBracesSugg, MissingCommaAfterMatchArm,
|
MalformedLoopLabel, MatchArmBodyWithoutBraces, MatchArmBodyWithoutBracesSugg,
|
||||||
MissingDotDot, MissingInInForLoop, MissingInInForLoopSub, MissingSemicolonBeforeArray,
|
MissingCommaAfterMatchArm, MissingDotDot, MissingInInForLoop, MissingInInForLoopSub,
|
||||||
NoFieldsForFnCall, NotAsNegationOperator, NotAsNegationOperatorSub,
|
MissingSemicolonBeforeArray, NoFieldsForFnCall, NotAsNegationOperator,
|
||||||
OuterAttributeNotAllowedOnIfElse, ParenthesesWithStructFields,
|
NotAsNegationOperatorSub, OuterAttributeNotAllowedOnIfElse, ParenthesesWithStructFields,
|
||||||
RequireColonAfterLabeledExpression, ShiftInterpretedAsGeneric, StructLiteralNotAllowedHere,
|
RequireColonAfterLabeledExpression, ShiftInterpretedAsGeneric, StructLiteralNotAllowedHere,
|
||||||
StructLiteralNotAllowedHereSugg, TildeAsUnaryOperator, UnexpectedIfWithIf,
|
StructLiteralNotAllowedHereSugg, TildeAsUnaryOperator, UnexpectedIfWithIf,
|
||||||
UnexpectedTokenAfterLabel, UnexpectedTokenAfterLabelSugg, WrapExpressionInParentheses,
|
UnexpectedTokenAfterLabel, UnexpectedTokenAfterLabelSugg, WrapExpressionInParentheses,
|
||||||
@ -2251,9 +2251,10 @@ impl<'a> Parser<'a> {
|
|||||||
if let ExprKind::Block(_, None) = right.kind => {
|
if let ExprKind::Block(_, None) = right.kind => {
|
||||||
self.sess.emit_err(IfExpressionMissingThenBlock {
|
self.sess.emit_err(IfExpressionMissingThenBlock {
|
||||||
if_span: lo,
|
if_span: lo,
|
||||||
sub: IfExpressionMissingThenBlockSub::UnfinishedCondition(
|
missing_then_block_sub:
|
||||||
cond_span.shrink_to_lo().to(*binop_span)
|
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()))
|
std::mem::replace(right, this.mk_expr_err(binop_span.shrink_to_hi()))
|
||||||
},
|
},
|
||||||
@ -2279,9 +2280,15 @@ impl<'a> Parser<'a> {
|
|||||||
if let Some(block) = recover_block_from_condition(self) {
|
if let Some(block) = recover_block_from_condition(self) {
|
||||||
block
|
block
|
||||||
} else {
|
} else {
|
||||||
|
let let_else_sub = matches!(cond.kind, ExprKind::Let(..))
|
||||||
|
.then(|| IfExpressionLetSomeSub { if_span: lo });
|
||||||
|
|
||||||
self.sess.emit_err(IfExpressionMissingThenBlock {
|
self.sess.emit_err(IfExpressionMissingThenBlock {
|
||||||
if_span: lo,
|
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())
|
self.mk_block_err(cond_span.shrink_to_hi())
|
||||||
}
|
}
|
||||||
|
6
tests/ui/let-else/accidental-if.rs
Normal file
6
tests/ui/let-else/accidental-if.rs
Normal file
@ -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
tests/ui/let-else/accidental-if.stderr
Normal file
19
tests/ui/let-else/accidental-if.stderr
Normal file
@ -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
|
||||||
|
|
@ -37,6 +37,11 @@ help: add a block here
|
|||||||
|
|
|
|
||||||
LL | if let Some(n) = opt else {
|
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
|
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
|
--> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:28:5
|
||||||
|
Loading…
x
Reference in New Issue
Block a user