diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 491dd4c494ab3..db9a0a4490f0d 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -788,6 +788,10 @@ parse_unexpected_expr_in_pat_create_guard_sugg = check the value in an arm guard parse_unexpected_expr_in_pat_inline_const_sugg = wrap the expression in a inline const (requires `{"#"}![feature(inline_const_pat)]`) +parse_unexpected_expr_in_pat_remove_let_sugg = remove this `let` + +parse_unexpected_expr_in_pat_replace_let_else_with_if_sugg = use an `if` + parse_unexpected_expr_in_pat_update_guard_sugg = check the value in the arm guard parse_unexpected_if_with_if = unexpected `if` in the condition expression diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 385347999a6ae..498ecca0f5c30 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2492,6 +2492,28 @@ pub(crate) struct UnexpectedExpressionInPatternInlineConstSugg { pub end_span: Span, } +#[derive(Subdiagnostic)] +#[multipart_suggestion( + parse_unexpected_expr_in_pat_remove_let_sugg, + applicability = "maybe-incorrect" +)] +pub(crate) struct UnexpectedExpressionInPatternRemoveLetSugg { + #[suggestion_part(code = "")] + pub span: Span, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + parse_unexpected_expr_in_pat_replace_let_else_with_if_sugg, + applicability = "maybe-incorrect" +)] +pub(crate) struct UnexpectedExpressionInPatternReplaceLetElseWithIfSugg { + #[suggestion_part(code = "if {init} != {pat}")] + pub span: Span, + pub init: String, + pub pat: String, +} + #[derive(Diagnostic)] #[diag(parse_unexpected_paren_in_range_pat)] pub(crate) struct UnexpectedParenInRangePat { diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 196bcfd4840a5..27e0422538310 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -8,7 +8,9 @@ use crate::errors::{ TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg, TrailingVertNotAllowed, UnexpectedExpressionInPattern, UnexpectedExpressionInPatternArmSugg, UnexpectedExpressionInPatternConstSugg, UnexpectedExpressionInPatternInlineConstSugg, - UnexpectedLifetimeInPattern, UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg, + UnexpectedExpressionInPatternRemoveLetSugg, + UnexpectedExpressionInPatternReplaceLetElseWithIfSugg, UnexpectedLifetimeInPattern, + UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, }; use crate::parser::expr::{could_be_unclosed_char_literal, DestructuredFloat, LhsExpr}; @@ -26,7 +28,7 @@ use rustc_errors::{Applicability, Diag, PResult, StashKey}; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::{ErrorGuaranteed, Span}; +use rustc_span::{BytePos, ErrorGuaranteed, Span}; use thin_vec::{thin_vec, ThinVec}; #[derive(PartialEq, Copy, Clone)] @@ -497,15 +499,38 @@ impl<'a> Parser<'a> { err.span.replace(stash_span, expr_span); if let StmtKind::Let(local) = &stmt.kind { - // If we have an `ExprInPat`, the user tried to assign a value to another value, - // which doesn't makes much sense. match &local.kind { - LocalKind::Decl => {} - LocalKind::Init(_) => {} - LocalKind::InitElse(_, _) => {} + // help: remove this `let` + LocalKind::Decl | LocalKind::Init(_) => { + err.subdiagnostic( + UnexpectedExpressionInPatternRemoveLetSugg { + // HACK: retrieves `let`'s span + span: local + .span + .shrink_to_lo() + .with_hi(local.span.lo() + BytePos(3)), + }, + ); + } + // help: replace the `let` with an `if` + LocalKind::InitElse(init, els) => { + err.subdiagnostic( + UnexpectedExpressionInPatternReplaceLetElseWithIfSugg { + span: local.span.shrink_to_lo().until(els.span), + init: self + .parser + .span_to_snippet(init.span) + .unwrap(), + pat: self + .parser + .span_to_snippet(local.pat.span) + .unwrap(), + }, + ); + } } } else { - // help: use an arm guard `if val == expr` + // help: check the value in an arm guard if let Some(arm) = &self.arm { let (ident, ident_span) = match self.field { Some(field) => ( diff --git a/tests/ui/parser/bad-name.stderr b/tests/ui/parser/bad-name.stderr index 44f6c6c620ce5..74c8d231bac4f 100644 --- a/tests/ui/parser/bad-name.stderr +++ b/tests/ui/parser/bad-name.stderr @@ -8,7 +8,9 @@ error: expected a pattern, found an expression --> $DIR/bad-name.rs:4:7 | LL | let x.y::.z foo; - | ^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | --- ^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | | + | help: remove this `let` error: expected one of `(`, `.`, `::`, `:`, `;`, `=`, `?`, `|`, or an operator, found `foo` --> $DIR/bad-name.rs:4:22 diff --git a/tests/ui/parser/issues/issue-24197.stderr b/tests/ui/parser/issues/issue-24197.stderr index 7ebbf4ac370d7..219f852d1d422 100644 --- a/tests/ui/parser/issues/issue-24197.stderr +++ b/tests/ui/parser/issues/issue-24197.stderr @@ -2,7 +2,9 @@ error: expected a pattern, found an expression --> $DIR/issue-24197.rs:2:9 | LL | let buf[0] = 0; - | ^^^^^^ arbitrary expressions are not allowed in patterns + | --- ^^^^^^ arbitrary expressions are not allowed in patterns + | | + | help: remove this `let` error: aborting due to 1 previous error diff --git a/tests/ui/parser/pat-lt-bracket-5.stderr b/tests/ui/parser/pat-lt-bracket-5.stderr index 18cf2df028216..050f3648d6379 100644 --- a/tests/ui/parser/pat-lt-bracket-5.stderr +++ b/tests/ui/parser/pat-lt-bracket-5.stderr @@ -2,7 +2,9 @@ error: expected a pattern, found an expression --> $DIR/pat-lt-bracket-5.rs:2:9 | LL | let v[0] = v[1]; - | ^^^^ arbitrary expressions are not allowed in patterns + | --- ^^^^ arbitrary expressions are not allowed in patterns + | | + | help: remove this `let` error[E0425]: cannot find value `v` in this scope --> $DIR/pat-lt-bracket-5.rs:2:16 diff --git a/tests/ui/parser/pat-lt-bracket-6.stderr b/tests/ui/parser/pat-lt-bracket-6.stderr index 892883c4aedca..25caed7324c02 100644 --- a/tests/ui/parser/pat-lt-bracket-6.stderr +++ b/tests/ui/parser/pat-lt-bracket-6.stderr @@ -2,7 +2,9 @@ error: expected a pattern, found an expression --> $DIR/pat-lt-bracket-6.rs:5:14 | LL | let Test(&desc[..]) = x; - | ^^^^^^^^^ arbitrary expressions are not allowed in patterns + | --- ^^^^^^^^^ arbitrary expressions are not allowed in patterns + | | + | help: remove this `let` error[E0308]: mismatched types --> $DIR/pat-lt-bracket-6.rs:10:30 diff --git a/tests/ui/parser/pat-ranges-3.stderr b/tests/ui/parser/pat-ranges-3.stderr index 5e1f35d1b6f9a..1ff20f2177cae 100644 --- a/tests/ui/parser/pat-ranges-3.stderr +++ b/tests/ui/parser/pat-ranges-3.stderr @@ -2,13 +2,17 @@ error: expected a pattern range bound, found an expression --> $DIR/pat-ranges-3.rs:4:16 | LL | let 10 ..= 10 + 3 = 12; - | ^^^^^^ arbitrary expressions are not allowed in patterns + | --- ^^^^^^ arbitrary expressions are not allowed in patterns + | | + | help: remove this `let` error: expected a pattern range bound, found an expression --> $DIR/pat-ranges-3.rs:7:9 | LL | let 10 - 3 ..= 10 = 8; - | ^^^^^^ arbitrary expressions are not allowed in patterns + | --- ^^^^^^ arbitrary expressions are not allowed in patterns + | | + | help: remove this `let` error: aborting due to 2 previous errors diff --git a/tests/ui/parser/recover/recover-pat-exprs.stderr b/tests/ui/parser/recover/recover-pat-exprs.stderr index 3ed99771cbdf7..c1562d94e51c3 100644 --- a/tests/ui/parser/recover/recover-pat-exprs.stderr +++ b/tests/ui/parser/recover/recover-pat-exprs.stderr @@ -554,7 +554,9 @@ error: expected a pattern, found an expression --> $DIR/recover-pat-exprs.rs:71:9 | LL | let 1 + 1 = 2; - | ^^^^^ arbitrary expressions are not allowed in patterns + | --- ^^^^^ arbitrary expressions are not allowed in patterns + | | + | help: remove this `let` error: expected one of `)`, `,`, `@`, or `|`, found `*` --> $DIR/recover-pat-exprs.rs:74:28 diff --git a/tests/ui/parser/recover/recover-pat-lets.rs b/tests/ui/parser/recover/recover-pat-lets.rs new file mode 100644 index 0000000000000..d2b1effca2c07 --- /dev/null +++ b/tests/ui/parser/recover/recover-pat-lets.rs @@ -0,0 +1,7 @@ +fn main() { + let x = Some(2); + + let Some(1 + 1) = x else { //~ error: expected a pattern, found an expression + return; + }; +} diff --git a/tests/ui/parser/recover/recover-pat-lets.stderr b/tests/ui/parser/recover/recover-pat-lets.stderr new file mode 100644 index 0000000000000..99636db818f91 --- /dev/null +++ b/tests/ui/parser/recover/recover-pat-lets.stderr @@ -0,0 +1,11 @@ +error: expected a pattern, found an expression + --> $DIR/recover-pat-lets.rs:4:14 + | +LL | let Some(1 + 1) = x else { + | ---------^^^^^----------- + | | | + | | arbitrary expressions are not allowed in patterns + | help: use an `if`: `if x != Some(1 + 1)` + +error: aborting due to 1 previous error + diff --git a/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr index fc431eb14127f..18a92b892b18d 100644 --- a/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr +++ b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr @@ -2,7 +2,9 @@ error: expected a pattern, found an expression --> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:31 | LL | let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes; - | ^^^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | --- ^^^^^^^^^^^^^^^^^^ arbitrary expressions are not allowed in patterns + | | + | help: remove this `let` error[E0412]: cannot find type `T` in this scope --> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:55