diff --git a/compiler/rustc_macros/src/diagnostics/mod.rs b/compiler/rustc_macros/src/diagnostics/mod.rs index bd84681cbb4..a536eb3b04e 100644 --- a/compiler/rustc_macros/src/diagnostics/mod.rs +++ b/compiler/rustc_macros/src/diagnostics/mod.rs @@ -140,7 +140,7 @@ pub fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream { /// ```fluent /// parser_expected_identifier = expected identifier /// -/// parser_expected_identifier-found = expected identifier, found {$found} +/// parser_expected_identifier_found = expected identifier, found {$found} /// /// parser_raw_identifier = escape `{$ident}` to use it as an identifier /// ``` diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 36883bd2172..e8f47346fa7 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -399,6 +399,23 @@ pub(super) fn expected_ident_found( } } } + // we suggest add the missing `let` before the identifier + // `a: Ty = 1` -> `let a: Ty = 1` + if self.token == token::Colon { + let prev_span = self.prev_token.span.shrink_to_lo(); + let snapshot = self.create_snapshot_for_diagnostic(); + self.bump(); + let res = self.parse_ty(); + if res.is_ok() && self.token == token::Eq { + err.span_suggestion_verbose( + prev_span, + "you might have meant to introduce a new binding", + "let ".to_string(), + Applicability::MaybeIncorrect, + ); + } + self.restore_snapshot(snapshot); + } if let Some(recovered_ident) = recovered_ident && recover { err.emit(); diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 1c17de337e8..ab04219b177 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -555,7 +555,6 @@ pub(crate) fn parse_block_tail( if self.token == token::Colon { // if next token is following a colon, it's likely a path // and we can suggest a path separator - let ident_span = self.prev_token.span; self.bump(); if self.token.span.lo() == self.prev_token.span.hi() { err.span_suggestion_verbose( @@ -565,14 +564,6 @@ pub(crate) fn parse_block_tail( Applicability::MaybeIncorrect, ); } - if self.look_ahead(1, |token| token == &token::Eq) { - err.span_suggestion_verbose( - ident_span.shrink_to_lo(), - "you might have meant to introduce a new binding", - "let ", - Applicability::MaybeIncorrect, - ); - } if self.sess.unstable_features.is_nightly_build() { // FIXME(Nilstrieb): Remove this again after a few months. err.note("type ascription syntax has been removed, see issue #101728 "); diff --git a/tests/ui/suggestions/type-ascription-instead-of-let.fixed b/tests/ui/suggestions/type-ascription-instead-of-let.fixed new file mode 100644 index 00000000000..e3d03b6f22a --- /dev/null +++ b/tests/ui/suggestions/type-ascription-instead-of-let.fixed @@ -0,0 +1,11 @@ +// run-rustfix + +fn fun(x: i32) -> i32 { x } + +fn main() { + let _closure_annotated = |value: i32| -> i32 { + let temp: i32 = fun(5i32); + //~^ ERROR expected identifier, found `:` + temp + value + 1 + }; +} diff --git a/tests/ui/suggestions/type-ascription-instead-of-let.rs b/tests/ui/suggestions/type-ascription-instead-of-let.rs index 5ad60243298..6e1c86f9671 100644 --- a/tests/ui/suggestions/type-ascription-instead-of-let.rs +++ b/tests/ui/suggestions/type-ascription-instead-of-let.rs @@ -1,7 +1,9 @@ +// run-rustfix + fn fun(x: i32) -> i32 { x } fn main() { - let closure_annotated = |value: i32| -> i32 { + let _closure_annotated = |value: i32| -> i32 { temp: i32 = fun(5i32); //~^ ERROR expected identifier, found `:` temp + value + 1 diff --git a/tests/ui/suggestions/type-ascription-instead-of-let.stderr b/tests/ui/suggestions/type-ascription-instead-of-let.stderr index fb697b0ccfd..065b1f4d353 100644 --- a/tests/ui/suggestions/type-ascription-instead-of-let.stderr +++ b/tests/ui/suggestions/type-ascription-instead-of-let.stderr @@ -1,8 +1,13 @@ error: expected identifier, found `:` - --> $DIR/type-ascription-instead-of-let.rs:5:13 + --> $DIR/type-ascription-instead-of-let.rs:7:13 | LL | temp: i32 = fun(5i32); | ^ expected identifier + | +help: you might have meant to introduce a new binding + | +LL | let temp: i32 = fun(5i32); + | +++ error: aborting due to previous error diff --git a/tests/ui/type/missing-let-in-binding-2.fixed b/tests/ui/type/missing-let-in-binding-2.fixed new file mode 100644 index 00000000000..d64013c8c83 --- /dev/null +++ b/tests/ui/type/missing-let-in-binding-2.fixed @@ -0,0 +1,5 @@ +// run-rustfix + +fn main() { + let _v: Vec = vec![1, 2, 3]; //~ ERROR expected identifier, found `:` +} diff --git a/tests/ui/type/missing-let-in-binding-2.rs b/tests/ui/type/missing-let-in-binding-2.rs new file mode 100644 index 00000000000..f95f7bef215 --- /dev/null +++ b/tests/ui/type/missing-let-in-binding-2.rs @@ -0,0 +1,5 @@ +// run-rustfix + +fn main() { + _v: Vec = vec![1, 2, 3]; //~ ERROR expected identifier, found `:` +} diff --git a/tests/ui/type/missing-let-in-binding-2.stderr b/tests/ui/type/missing-let-in-binding-2.stderr new file mode 100644 index 00000000000..2e10125943e --- /dev/null +++ b/tests/ui/type/missing-let-in-binding-2.stderr @@ -0,0 +1,13 @@ +error: expected identifier, found `:` + --> $DIR/missing-let-in-binding-2.rs:4:7 + | +LL | _v: Vec = vec![1, 2, 3]; + | ^ expected identifier + | +help: you might have meant to introduce a new binding + | +LL | let _v: Vec = vec![1, 2, 3]; + | +++ + +error: aborting due to previous error +