rustc_parse: improve the error diagnostic for "missing let"
Signed-off-by: Usman Akinyemi <usmanakinyemi202@gmail.com>
This commit is contained in:
parent
8c5605e130
commit
85ca098f55
4 changed files with 102 additions and 3 deletions
|
|
@ -573,6 +573,24 @@ pub(crate) struct ExpectedExpressionFoundLet {
|
|||
pub comparison: Option<MaybeComparison>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("let-chain with missing `let`")]
|
||||
pub(crate) struct LetChainMissingLet {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[label("expected `let` expression, found assignment")]
|
||||
pub label_span: Span,
|
||||
#[label("let expression later in the condition")]
|
||||
pub rhs_span: Span,
|
||||
#[suggestion(
|
||||
"add `let` before the expression",
|
||||
applicability = "maybe-incorrect",
|
||||
code = "let ",
|
||||
style = "verbose"
|
||||
)]
|
||||
pub sug_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`||` operators are not supported in let chain conditions")]
|
||||
pub(crate) struct OrInLetChain {
|
||||
|
|
|
|||
|
|
@ -4282,7 +4282,52 @@ impl MutVisitor for CondChecker<'_> {
|
|||
mut_visit::walk_expr(self, e);
|
||||
self.forbid_let_reason = forbid_let_reason;
|
||||
}
|
||||
ExprKind::Assign(ref lhs, _, span) => {
|
||||
ExprKind::Assign(ref lhs, ref rhs, span) => {
|
||||
if let ExprKind::Call(_, _) = &lhs.kind {
|
||||
fn get_path_from_rhs(e: &Expr) -> Option<(u32, &Path)> {
|
||||
fn inner(e: &Expr, depth: u32) -> Option<(u32, &Path)> {
|
||||
match &e.kind {
|
||||
ExprKind::Binary(_, lhs, _) => inner(lhs, depth + 1),
|
||||
ExprKind::Path(_, path) => Some((depth, path)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
inner(e, 0)
|
||||
}
|
||||
|
||||
if let Some((depth, path)) = get_path_from_rhs(rhs) {
|
||||
// For cases like if Some(_) = x && let Some(_) = y && let Some(_) = z
|
||||
// This return let Some(_) = y expression
|
||||
fn find_let_some(expr: &Expr) -> Option<&Expr> {
|
||||
match &expr.kind {
|
||||
ExprKind::Let(..) => Some(expr),
|
||||
|
||||
ExprKind::Binary(op, lhs, rhs) if op.node == BinOpKind::And => {
|
||||
find_let_some(lhs).or_else(|| find_let_some(rhs))
|
||||
}
|
||||
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
let expr_span = lhs.span.to(path.span);
|
||||
|
||||
if let Some(later_rhs) = find_let_some(rhs)
|
||||
&& depth > 0
|
||||
{
|
||||
let guar = self.parser.dcx().emit_err(errors::LetChainMissingLet {
|
||||
span: lhs.span,
|
||||
label_span: expr_span,
|
||||
rhs_span: later_rhs.span,
|
||||
sug_span: lhs.span.shrink_to_lo(),
|
||||
});
|
||||
|
||||
self.found_incorrect_let_chain = Some(guar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let forbid_let_reason = self.forbid_let_reason;
|
||||
self.forbid_let_reason = Some(errors::ForbiddenLetReason::OtherForbidden);
|
||||
let missing_let = self.missing_let;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,18 @@
|
|||
fn main() {
|
||||
let x = Some(42);
|
||||
let y = Some(42);
|
||||
let z = Some(42);
|
||||
if let Some(_) = x
|
||||
&& Some(x) = x //~^ ERROR expected expression, found `let` statement
|
||||
//~| NOTE: only supported directly in conditions of `if` and `while` expressions
|
||||
{}
|
||||
|
||||
if Some(_) = y &&
|
||||
//~^ NOTE expected `let` expression, found assignment
|
||||
//~| ERROR let-chain with missing `let`
|
||||
let Some(_) = z
|
||||
//~^ ERROR: expected expression, found `let` statement
|
||||
//~| NOTE: let expression later in the condition
|
||||
//~| NOTE: only supported directly in conditions of `if` and `while` expressions
|
||||
{}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error: expected expression, found `let` statement
|
||||
--> $DIR/missing-let.rs:3:8
|
||||
--> $DIR/missing-let.rs:5:8
|
||||
|
|
||||
LL | if let Some(_) = x
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
@ -14,5 +14,29 @@ help: you might have meant to compare for equality
|
|||
LL | && Some(x) == x
|
||||
| +
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
error: expected expression, found `let` statement
|
||||
--> $DIR/missing-let.rs:13:9
|
||||
|
|
||||
LL | let Some(_) = z
|
||||
| ^^^
|
||||
|
|
||||
= note: only supported directly in conditions of `if` and `while` expressions
|
||||
|
||||
error: let-chain with missing `let`
|
||||
--> $DIR/missing-let.rs:10:8
|
||||
|
|
||||
LL | if Some(_) = y &&
|
||||
| ^^^^^^^----
|
||||
| |
|
||||
| expected `let` expression, found assignment
|
||||
...
|
||||
LL | let Some(_) = z
|
||||
| --------------- let expression later in the condition
|
||||
|
|
||||
help: add `let` before the expression
|
||||
|
|
||||
LL | if let Some(_) = y &&
|
||||
| +++
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue