From 16518cae3cb7fdef28bc06bba58bdf1c4722b214 Mon Sep 17 00:00:00 2001 From: Veera Date: Mon, 2 Sep 2024 12:43:35 -0400 Subject: [PATCH] Add Suggestions for Misspelled Keywords This PR detects misspelled keywords using two heuristics: 1. Lowercasing the unexpected identifier. 2. Using edit distance to find a keyword similar to the unexpected identifier. However, it does not detect each and every misspelled keyword to minimize false positives and ambiguities. More details about the implementation can be found in the comments. --- compiler/rustc_parse/messages.ftl | 6 ++ .../rustc_parse/src/parser/diagnostics.rs | 85 ++++++++++++++++++- compiler/rustc_span/src/symbol.rs | 42 ++++++++- .../extern-crate-unexpected-token.stderr | 5 ++ ...9-resolve-after-recovered-self-ctor.stderr | 33 +++++-- .../misspelled-keywords/assoc-type.stderr | 5 ++ .../misspelled-keywords/async-move.stderr | 5 ++ .../misspelled-keywords/const-fn.stderr | 5 ++ .../misspelled-keywords/const-generics.stderr | 5 ++ .../parser/misspelled-keywords/const.stderr | 5 ++ .../misspelled-keywords/for-loop.stderr | 5 ++ .../ui/parser/misspelled-keywords/hrdt.stderr | 5 ++ .../misspelled-keywords/impl-block.stderr | 5 ++ .../misspelled-keywords/impl-return.stderr | 5 ++ .../misspelled-keywords/impl-trait-for.stderr | 5 ++ .../misspelled-keywords/impl-trait.stderr | 4 + .../misspelled-keywords/let-else.stderr | 5 ++ .../parser/misspelled-keywords/let-mut.stderr | 5 ++ .../ui/parser/misspelled-keywords/let.stderr | 10 +++ .../parser/misspelled-keywords/match.stderr | 5 ++ .../ui/parser/misspelled-keywords/mod.stderr | 5 ++ .../parser/misspelled-keywords/pub-fn.stderr | 5 ++ .../ui/parser/misspelled-keywords/ref.stderr | 13 ++- .../parser/misspelled-keywords/return.stderr | 5 ++ .../misspelled-keywords/static-mut.stderr | 5 ++ .../parser/misspelled-keywords/static.stderr | 5 ++ .../parser/misspelled-keywords/struct.stderr | 5 ++ .../misspelled-keywords/unsafe-fn.stderr | 5 ++ .../ui/parser/misspelled-keywords/use.stderr | 5 ++ .../misspelled-keywords/where-clause.stderr | 5 ++ .../parser/misspelled-keywords/while-loop.rs | 2 - .../misspelled-keywords/while-loop.stderr | 5 ++ 32 files changed, 298 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 8e8d91ce4d038..ec9a676ea3135 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -381,6 +381,7 @@ parse_invalid_char_in_escape_msg = invalid character in {$is_hex -> *[false] unicode } escape + parse_invalid_comparison_operator = invalid comparison operator `{$invalid}` .use_instead = `{$invalid}` is not a valid comparison operator, use `{$correct}` .spaceship_operator_invalid = `<=>` is not a valid comparison operator, use `std::cmp::Ordering` @@ -581,6 +582,11 @@ parse_missing_trait_in_trait_impl = missing trait in a trait impl .suggestion_add_trait = add a trait here .suggestion_remove_for = for an inherent impl, drop this `for` +parse_misspelled_kw = {$is_incorrect_case -> + [true] write keyword `{$similar_kw}` in lowercase + *[false] there is a keyword `{$similar_kw}` with a similar name +} + parse_modifier_lifetime = `{$modifier}` may only modify trait bounds, not lifetime bounds .suggestion = remove the `{$modifier}` diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index fcdc10c0837e5..e261a5c0da142 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -19,8 +19,9 @@ use rustc_errors::{ Subdiagnostic, }; use rustc_session::errors::ExprParenthesesNeeded; +use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::source_map::Spanned; -use rustc_span::symbol::{kw, sym, Ident}; +use rustc_span::symbol::{kw, sym, AllKeywords, Ident}; use rustc_span::{BytePos, Span, SpanSnippetError, Symbol, DUMMY_SP}; use thin_vec::{thin_vec, ThinVec}; use tracing::{debug, trace}; @@ -203,6 +204,37 @@ impl std::fmt::Display for UnaryFixity { } } +#[derive(Debug, rustc_macros::Subdiagnostic)] +#[suggestion( + parse_misspelled_kw, + applicability = "machine-applicable", + code = "{similar_kw}", + style = "verbose" +)] +struct MisspelledKw { + similar_kw: String, + #[primary_span] + span: Span, + is_incorrect_case: bool, +} + +/// Checks if the given `lookup` identifier is similar to any keyword symbol in `candidates`. +fn find_similar_kw(lookup: Ident, candidates: &[Symbol]) -> Option { + let lowercase = lookup.name.as_str().to_lowercase(); + let lowercase_sym = Symbol::intern(&lowercase); + if candidates.contains(&lowercase_sym) { + Some(MisspelledKw { similar_kw: lowercase, span: lookup.span, is_incorrect_case: true }) + } else if let Some(similar_sym) = find_best_match_for_name(candidates, lookup.name, None) { + Some(MisspelledKw { + similar_kw: similar_sym.to_string(), + span: lookup.span, + is_incorrect_case: false, + }) + } else { + None + } +} + struct MultiSugg { msg: String, patches: Vec<(Span, String)>, @@ -638,9 +670,9 @@ impl<'a> Parser<'a> { let concat = Symbol::intern(&format!("{prev}{cur}")); let ident = Ident::new(concat, DUMMY_SP); if ident.is_used_keyword() || ident.is_reserved() || ident.is_raw_guess() { - let span = self.prev_token.span.to(self.token.span); + let concat_span = self.prev_token.span.to(self.token.span); err.span_suggestion_verbose( - span, + concat_span, format!("consider removing the space to spell keyword `{concat}`"), concat, Applicability::MachineApplicable, @@ -741,9 +773,55 @@ impl<'a> Parser<'a> { err.span_label(sp, label_exp); err.span_label(self.token.span, "unexpected token"); } + + // Check for misspelled keywords if there are no suggestions added to the diagnostic. + if err.suggestions.as_ref().is_ok_and(|code_suggestions| code_suggestions.is_empty()) { + self.check_for_misspelled_kw(&mut err, &expected); + } Err(err) } + /// Checks if the current token or the previous token are misspelled keywords + /// and adds a helpful suggestion. + fn check_for_misspelled_kw(&self, err: &mut Diag<'_>, expected: &[TokenType]) { + let Some((curr_ident, _)) = self.token.ident() else { + return; + }; + let expected_tokens: &[TokenType] = + expected.len().checked_sub(10).map_or(&expected, |index| &expected[index..]); + let expected_keywords: Vec = expected_tokens + .iter() + .filter_map(|token| if let TokenType::Keyword(kw) = token { Some(*kw) } else { None }) + .collect(); + + // When there a few keywords in the last ten elements of `self.expected_tokens` and the current + // token is an identifier, it's probably a misspelled keyword. + // This handles code like `async Move {}`, misspelled `if` in match guard, misspelled `else` in `if`-`else` + // and mispelled `where` in a where clause. + if !expected_keywords.is_empty() + && !curr_ident.is_used_keyword() + && let Some(misspelled_kw) = find_similar_kw(curr_ident, &expected_keywords) + { + err.subdiagnostic(misspelled_kw); + } else if let Some((prev_ident, _)) = self.prev_token.ident() + && !prev_ident.is_used_keyword() + { + // We generate a list of all keywords at runtime rather than at compile time + // so that it gets generated only when the diagnostic needs it. + // Also, it is unlikely that this list is generated multiple times because the + // parser halts after execution hits this path. + let all_keywords = AllKeywords::new().collect_used(|| prev_ident.span.edition()); + + // Otherwise, check the previous token with all the keywords as possible candidates. + // This handles code like `Struct Human;` and `While a < b {}`. + // We check the previous token only when the current token is an identifier to avoid false + // positives like suggesting keyword `for` for `extern crate foo {}`. + if let Some(misspelled_kw) = find_similar_kw(prev_ident, &all_keywords) { + err.subdiagnostic(misspelled_kw); + } + } + } + /// The user has written `#[attr] expr` which is unsupported. (#106020) pub(super) fn attr_on_non_tail_expr(&self, expr: &Expr) -> ErrorGuaranteed { // Missing semicolon typo error. @@ -846,6 +924,7 @@ impl<'a> Parser<'a> { ); } } + err.emit() } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 3476520960585..cabbdb0209222 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -20,7 +20,8 @@ mod tests; // The proc macro code for this is in `compiler/rustc_macros/src/symbols.rs`. symbols! { - // If you modify this list, adjust `is_special` and `is_used_keyword`/`is_unused_keyword`. + // If you modify this list, adjust `is_special`, `is_used_keyword`/`is_unused_keyword` + // and `AllKeywords`. // But this should rarely be necessary if the keywords are kept in alphabetic order. Keywords { // Special reserved identifiers used internally for elided lifetimes, @@ -2577,3 +2578,42 @@ impl Ident { self.name.can_be_raw() && self.is_reserved() } } + +/// An iterator over all the keywords in Rust. +#[derive(Copy, Clone)] +pub struct AllKeywords { + curr_idx: u32, + end_idx: u32, +} + +impl AllKeywords { + /// Initialize a new iterator over all the keywords. + /// + /// *Note:* Please update this if a new keyword is added beyond the current + /// range. + pub fn new() -> Self { + AllKeywords { curr_idx: kw::Empty.as_u32(), end_idx: kw::Yeet.as_u32() } + } + + /// Collect all the keywords in a given edition into a vector. + pub fn collect_used(&self, edition: impl Copy + FnOnce() -> Edition) -> Vec { + self.filter(|&keyword| { + keyword.is_used_keyword_always() || keyword.is_used_keyword_conditional(edition) + }) + .collect() + } +} + +impl Iterator for AllKeywords { + type Item = Symbol; + + fn next(&mut self) -> Option { + if self.curr_idx <= self.end_idx { + let keyword = Symbol::new(self.curr_idx); + self.curr_idx += 1; + Some(keyword) + } else { + None + } + } +} diff --git a/tests/ui/parser/extern-crate-unexpected-token.stderr b/tests/ui/parser/extern-crate-unexpected-token.stderr index f83bb3e3e35ae..951b0274b0d46 100644 --- a/tests/ui/parser/extern-crate-unexpected-token.stderr +++ b/tests/ui/parser/extern-crate-unexpected-token.stderr @@ -3,6 +3,11 @@ error: expected one of `crate` or `{`, found `crte` | LL | extern crte foo; | ^^^^ expected one of `crate` or `{` + | +help: there is a keyword `crate` with a similar name + | +LL | extern crate foo; + | ~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-70549-resolve-after-recovered-self-ctor.stderr b/tests/ui/parser/issues/issue-70549-resolve-after-recovered-self-ctor.stderr index 79c574ead61c3..00f372bc0082c 100644 --- a/tests/ui/parser/issues/issue-70549-resolve-after-recovered-self-ctor.stderr +++ b/tests/ui/parser/issues/issue-70549-resolve-after-recovered-self-ctor.stderr @@ -8,10 +8,16 @@ error: expected one of `:`, `@`, or `|`, found keyword `Self` --> $DIR/issue-70549-resolve-after-recovered-self-ctor.rs:4:17 | LL | fn foo(&mur Self) {} - | -----^^^^ - | | | - | | expected one of `:`, `@`, or `|` - | help: declare the type after the parameter binding: `: ` + | ^^^^ expected one of `:`, `@`, or `|` + | +help: there is a keyword `mut` with a similar name + | +LL | fn foo(&mut Self) {} + | ~~~ +help: declare the type after the parameter binding + | +LL | fn foo(: ) {} + | ~~~~~~~~~~~~~~~~~~~~ error: unexpected lifetime `'static` in pattern --> $DIR/issue-70549-resolve-after-recovered-self-ctor.rs:8:13 @@ -35,16 +41,27 @@ error: expected one of `:`, `@`, or `|`, found keyword `Self` --> $DIR/issue-70549-resolve-after-recovered-self-ctor.rs:8:25 | LL | fn bar(&'static mur Self) {} - | -------------^^^^ - | | | - | | expected one of `:`, `@`, or `|` - | help: declare the type after the parameter binding: `: ` + | ^^^^ expected one of `:`, `@`, or `|` + | +help: there is a keyword `mut` with a similar name + | +LL | fn bar(&'static mut Self) {} + | ~~~ +help: declare the type after the parameter binding + | +LL | fn bar(: ) {} + | ~~~~~~~~~~~~~~~~~~~~ error: expected one of `:`, `@`, or `|`, found keyword `Self` --> $DIR/issue-70549-resolve-after-recovered-self-ctor.rs:14:17 | LL | fn baz(&mur Self @ _) {} | ^^^^ expected one of `:`, `@`, or `|` + | +help: there is a keyword `mut` with a similar name + | +LL | fn baz(&mut Self @ _) {} + | ~~~ error[E0533]: expected unit struct, found self constructor `Self` --> $DIR/issue-70549-resolve-after-recovered-self-ctor.rs:4:17 diff --git a/tests/ui/parser/misspelled-keywords/assoc-type.stderr b/tests/ui/parser/misspelled-keywords/assoc-type.stderr index 1318bee3da83d..677da53e3400d 100644 --- a/tests/ui/parser/misspelled-keywords/assoc-type.stderr +++ b/tests/ui/parser/misspelled-keywords/assoc-type.stderr @@ -8,6 +8,11 @@ LL | Type Result = u8; LL | LL | } | - the item list ends here + | +help: write keyword `type` in lowercase + | +LL | type Result = u8; + | ~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/misspelled-keywords/async-move.stderr b/tests/ui/parser/misspelled-keywords/async-move.stderr index a98bb23f5d65e..4be4b56e5056a 100644 --- a/tests/ui/parser/misspelled-keywords/async-move.stderr +++ b/tests/ui/parser/misspelled-keywords/async-move.stderr @@ -3,6 +3,11 @@ error: expected one of `move`, `|`, or `||`, found `Move` | LL | async Move {} | ^^^^ expected one of `move`, `|`, or `||` + | +help: write keyword `move` in lowercase + | +LL | async move {} + | ~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/misspelled-keywords/const-fn.stderr b/tests/ui/parser/misspelled-keywords/const-fn.stderr index bdca2657ef39b..5646b26143c40 100644 --- a/tests/ui/parser/misspelled-keywords/const-fn.stderr +++ b/tests/ui/parser/misspelled-keywords/const-fn.stderr @@ -3,6 +3,11 @@ error: expected one of `!` or `::`, found keyword `fn` | LL | cnst fn code() {} | ^^ expected one of `!` or `::` + | +help: there is a keyword `const` with a similar name + | +LL | const fn code() {} + | ~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/misspelled-keywords/const-generics.stderr b/tests/ui/parser/misspelled-keywords/const-generics.stderr index f52544ac45ce2..fd59999ab635f 100644 --- a/tests/ui/parser/misspelled-keywords/const-generics.stderr +++ b/tests/ui/parser/misspelled-keywords/const-generics.stderr @@ -3,6 +3,11 @@ error: expected one of `,`, `:`, `=`, or `>`, found `N` | LL | fn foo(_arr: [i32; N]) {} | ^ expected one of `,`, `:`, `=`, or `>` + | +help: there is a keyword `const` with a similar name + | +LL | fn foo(_arr: [i32; N]) {} + | ~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/misspelled-keywords/const.stderr b/tests/ui/parser/misspelled-keywords/const.stderr index de1ad9d2bf76d..35e4d731db768 100644 --- a/tests/ui/parser/misspelled-keywords/const.stderr +++ b/tests/ui/parser/misspelled-keywords/const.stderr @@ -3,6 +3,11 @@ error: expected one of `!` or `::`, found `A` | LL | cons A: u8 = 10; | ^ expected one of `!` or `::` + | +help: there is a keyword `const` with a similar name + | +LL | const A: u8 = 10; + | ~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/misspelled-keywords/for-loop.stderr b/tests/ui/parser/misspelled-keywords/for-loop.stderr index cbf3b43fa585b..d2236ab074da7 100644 --- a/tests/ui/parser/misspelled-keywords/for-loop.stderr +++ b/tests/ui/parser/misspelled-keywords/for-loop.stderr @@ -3,6 +3,11 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found | LL | form i in 1..10 {} | ^ expected one of 8 possible tokens + | +help: there is a keyword `for` with a similar name + | +LL | for i in 1..10 {} + | ~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/misspelled-keywords/hrdt.stderr b/tests/ui/parser/misspelled-keywords/hrdt.stderr index 102ce7014e470..5393a730506d9 100644 --- a/tests/ui/parser/misspelled-keywords/hrdt.stderr +++ b/tests/ui/parser/misspelled-keywords/hrdt.stderr @@ -3,6 +3,11 @@ error: expected one of `!`, `(`, `+`, `::`, `<`, `where`, or `{`, found keyword | LL | Where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8, | ^^^ expected one of 7 possible tokens + | +help: write keyword `where` in lowercase (notice the capitalization difference) + | +LL | where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8, + | ~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/misspelled-keywords/impl-block.stderr b/tests/ui/parser/misspelled-keywords/impl-block.stderr index e0f0f8ed18f91..d86ae326ce2e3 100644 --- a/tests/ui/parser/misspelled-keywords/impl-block.stderr +++ b/tests/ui/parser/misspelled-keywords/impl-block.stderr @@ -3,6 +3,11 @@ error: expected one of `!` or `::`, found `Human` | LL | ipml Human {} | ^^^^^ expected one of `!` or `::` + | +help: there is a keyword `impl` with a similar name + | +LL | impl Human {} + | ~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/misspelled-keywords/impl-return.stderr b/tests/ui/parser/misspelled-keywords/impl-return.stderr index bdcf831a88a39..883f5cea73eff 100644 --- a/tests/ui/parser/misspelled-keywords/impl-return.stderr +++ b/tests/ui/parser/misspelled-keywords/impl-return.stderr @@ -3,6 +3,11 @@ error: expected one of `!`, `(`, `+`, `::`, `<`, `where`, or `{`, found `Display | LL | fn code() -> Impl Display {} | ^^^^^^^ expected one of 7 possible tokens + | +help: write keyword `impl` in lowercase (notice the capitalization difference) + | +LL | fn code() -> impl Display {} + | ~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/misspelled-keywords/impl-trait-for.stderr b/tests/ui/parser/misspelled-keywords/impl-trait-for.stderr index 64ca66794adba..8dd5a4645f362 100644 --- a/tests/ui/parser/misspelled-keywords/impl-trait-for.stderr +++ b/tests/ui/parser/misspelled-keywords/impl-trait-for.stderr @@ -3,6 +3,11 @@ error: expected one of `!`, `(`, `+`, `::`, `<`, `where`, or `{`, found `Human` | LL | impl Debug form Human {} | ^^^^^ expected one of 7 possible tokens + | +help: there is a keyword `for` with a similar name + | +LL | impl Debug for Human {} + | ~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/misspelled-keywords/impl-trait.stderr b/tests/ui/parser/misspelled-keywords/impl-trait.stderr index ca0918e820f87..15a8f99b8b10d 100644 --- a/tests/ui/parser/misspelled-keywords/impl-trait.stderr +++ b/tests/ui/parser/misspelled-keywords/impl-trait.stderr @@ -4,6 +4,10 @@ error: expected one of `(`, `+`, `,`, `::`, `<`, `=`, or `>`, found `Debug` LL | fn code() -> u8 {} | ^^^^^ expected one of 7 possible tokens | +help: there is a keyword `impl` with a similar name + | +LL | fn code() -> u8 {} + | ~~~~ help: you might have meant to end the type parameters here | LL | fn code Debug>() -> u8 {} diff --git a/tests/ui/parser/misspelled-keywords/let-else.stderr b/tests/ui/parser/misspelled-keywords/let-else.stderr index 826e7de4b11a5..6f41a0d99dba9 100644 --- a/tests/ui/parser/misspelled-keywords/let-else.stderr +++ b/tests/ui/parser/misspelled-keywords/let-else.stderr @@ -3,6 +3,11 @@ error: expected one of `.`, `;`, `?`, `else`, or an operator, found `elze` | LL | let Some(a) = Some(10) elze {} | ^^^^ expected one of `.`, `;`, `?`, `else`, or an operator + | +help: there is a keyword `else` with a similar name + | +LL | let Some(a) = Some(10) else {} + | ~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/misspelled-keywords/let-mut.stderr b/tests/ui/parser/misspelled-keywords/let-mut.stderr index 449f0133d6536..766d2a049090b 100644 --- a/tests/ui/parser/misspelled-keywords/let-mut.stderr +++ b/tests/ui/parser/misspelled-keywords/let-mut.stderr @@ -3,6 +3,11 @@ error: expected one of `:`, `;`, `=`, `@`, or `|`, found `a` | LL | let muta a = 10; | ^ expected one of `:`, `;`, `=`, `@`, or `|` + | +help: there is a keyword `mut` with a similar name + | +LL | let mut a = 10; + | ~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/misspelled-keywords/let.stderr b/tests/ui/parser/misspelled-keywords/let.stderr index 77aeb21369c13..c2dcdef541d81 100644 --- a/tests/ui/parser/misspelled-keywords/let.stderr +++ b/tests/ui/parser/misspelled-keywords/let.stderr @@ -3,12 +3,22 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found | LL | Let a = 10; | ^ expected one of 8 possible tokens + | +help: write keyword `let` in lowercase + | +LL | let a = 10; + | ~~~ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `a` --> $DIR/let.rs:7:10 | LL | lett a = 10; | ^ expected one of 8 possible tokens + | +help: there is a keyword `let` with a similar name + | +LL | let a = 10; + | ~~~ error: aborting due to 2 previous errors diff --git a/tests/ui/parser/misspelled-keywords/match.stderr b/tests/ui/parser/misspelled-keywords/match.stderr index bc3eece1c9d9a..90780ebd38ef0 100644 --- a/tests/ui/parser/misspelled-keywords/match.stderr +++ b/tests/ui/parser/misspelled-keywords/match.stderr @@ -3,6 +3,11 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found | LL | matche a {} | ^ expected one of 8 possible tokens + | +help: there is a keyword `match` with a similar name + | +LL | match a {} + | ~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/misspelled-keywords/mod.stderr b/tests/ui/parser/misspelled-keywords/mod.stderr index 135f70ccfcbba..6daeb4e5a152e 100644 --- a/tests/ui/parser/misspelled-keywords/mod.stderr +++ b/tests/ui/parser/misspelled-keywords/mod.stderr @@ -3,6 +3,11 @@ error: expected one of `!` or `::`, found `parser` | LL | mode parser; | ^^^^^^ expected one of `!` or `::` + | +help: there is a keyword `mod` with a similar name + | +LL | mod parser; + | ~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/misspelled-keywords/pub-fn.stderr b/tests/ui/parser/misspelled-keywords/pub-fn.stderr index 15715514e6651..82ca7105a4965 100644 --- a/tests/ui/parser/misspelled-keywords/pub-fn.stderr +++ b/tests/ui/parser/misspelled-keywords/pub-fn.stderr @@ -3,6 +3,11 @@ error: expected one of `#`, `async`, `auto`, `const`, `default`, `enum`, `extern | LL | puB fn code() {} | ^^^ expected one of 21 possible tokens + | +help: write keyword `pub` in lowercase + | +LL | pub fn code() {} + | ~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/misspelled-keywords/ref.stderr b/tests/ui/parser/misspelled-keywords/ref.stderr index 2c23fe7a0afe8..3a79b7bdb0023 100644 --- a/tests/ui/parser/misspelled-keywords/ref.stderr +++ b/tests/ui/parser/misspelled-keywords/ref.stderr @@ -2,9 +2,16 @@ error: expected one of `)`, `,`, `@`, or `|`, found `list` --> $DIR/ref.rs:4:19 | LL | Some(refe list) => println!("{list:?}"), - | -^^^^ expected one of `)`, `,`, `@`, or `|` - | | - | help: missing `,` + | ^^^^ expected one of `)`, `,`, `@`, or `|` + | +help: there is a keyword `ref` with a similar name + | +LL | Some(ref list) => println!("{list:?}"), + | ~~~ +help: missing `,` + | +LL | Some(refe, list) => println!("{list:?}"), + | + error[E0023]: this pattern has 2 fields, but the corresponding tuple variant has 1 field --> $DIR/ref.rs:4:14 diff --git a/tests/ui/parser/misspelled-keywords/return.stderr b/tests/ui/parser/misspelled-keywords/return.stderr index 94789e7a92cd8..efa45f3229909 100644 --- a/tests/ui/parser/misspelled-keywords/return.stderr +++ b/tests/ui/parser/misspelled-keywords/return.stderr @@ -3,6 +3,11 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found | LL | returnn a; | ^ expected one of 8 possible tokens + | +help: there is a keyword `return` with a similar name + | +LL | return a; + | ~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/misspelled-keywords/static-mut.stderr b/tests/ui/parser/misspelled-keywords/static-mut.stderr index 1e5d25c709e7d..3c25af548a3df 100644 --- a/tests/ui/parser/misspelled-keywords/static-mut.stderr +++ b/tests/ui/parser/misspelled-keywords/static-mut.stderr @@ -3,6 +3,11 @@ error: expected one of `:`, `;`, or `=`, found `a` | LL | static muta a: u8 = 0; | ^ expected one of `:`, `;`, or `=` + | +help: there is a keyword `mut` with a similar name + | +LL | static mut a: u8 = 0; + | ~~~ error: missing type for `static` item --> $DIR/static-mut.rs:1:12 diff --git a/tests/ui/parser/misspelled-keywords/static.stderr b/tests/ui/parser/misspelled-keywords/static.stderr index 698cd47b16972..003aa3929bc22 100644 --- a/tests/ui/parser/misspelled-keywords/static.stderr +++ b/tests/ui/parser/misspelled-keywords/static.stderr @@ -3,6 +3,11 @@ error: expected one of `!` or `::`, found `a` | LL | Static a = 0; | ^ expected one of `!` or `::` + | +help: write keyword `static` in lowercase (notice the capitalization difference) + | +LL | static a = 0; + | ~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/misspelled-keywords/struct.stderr b/tests/ui/parser/misspelled-keywords/struct.stderr index 8f678f4ad2e03..559182f9c8f68 100644 --- a/tests/ui/parser/misspelled-keywords/struct.stderr +++ b/tests/ui/parser/misspelled-keywords/struct.stderr @@ -3,6 +3,11 @@ error: expected one of `!` or `::`, found `Foor` | LL | Struct Foor { | ^^^^ expected one of `!` or `::` + | +help: write keyword `struct` in lowercase (notice the capitalization difference) + | +LL | struct Foor { + | ~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/misspelled-keywords/unsafe-fn.stderr b/tests/ui/parser/misspelled-keywords/unsafe-fn.stderr index 2013df1c34aa8..b13281b039511 100644 --- a/tests/ui/parser/misspelled-keywords/unsafe-fn.stderr +++ b/tests/ui/parser/misspelled-keywords/unsafe-fn.stderr @@ -3,6 +3,11 @@ error: expected one of `!` or `::`, found keyword `fn` | LL | unsafee fn code() {} | ^^ expected one of `!` or `::` + | +help: there is a keyword `unsafe` with a similar name + | +LL | unsafe fn code() {} + | ~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/misspelled-keywords/use.stderr b/tests/ui/parser/misspelled-keywords/use.stderr index 4ca01dedd6b28..db6dffdb613c5 100644 --- a/tests/ui/parser/misspelled-keywords/use.stderr +++ b/tests/ui/parser/misspelled-keywords/use.stderr @@ -3,6 +3,11 @@ error: expected one of `!` or `::`, found `a` | LL | usee a::b; | ^ expected one of `!` or `::` + | +help: there is a keyword `use` with a similar name + | +LL | use a::b; + | ~~~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/misspelled-keywords/where-clause.stderr b/tests/ui/parser/misspelled-keywords/where-clause.stderr index 4b3f996c11254..5143c30ca5103 100644 --- a/tests/ui/parser/misspelled-keywords/where-clause.stderr +++ b/tests/ui/parser/misspelled-keywords/where-clause.stderr @@ -5,6 +5,11 @@ LL | fn code() -> u8 | - expected one of 7 possible tokens LL | wheree | ^^^^^^ unexpected token + | +help: there is a keyword `where` with a similar name + | +LL | where + | error: aborting due to 1 previous error diff --git a/tests/ui/parser/misspelled-keywords/while-loop.rs b/tests/ui/parser/misspelled-keywords/while-loop.rs index 8d19b3c572264..37d337f3f1959 100644 --- a/tests/ui/parser/misspelled-keywords/while-loop.rs +++ b/tests/ui/parser/misspelled-keywords/while-loop.rs @@ -1,7 +1,5 @@ fn main() { whilee a < b { //~^ ERROR expected one of - } } - diff --git a/tests/ui/parser/misspelled-keywords/while-loop.stderr b/tests/ui/parser/misspelled-keywords/while-loop.stderr index 8147a5de69673..7d150443f57e7 100644 --- a/tests/ui/parser/misspelled-keywords/while-loop.stderr +++ b/tests/ui/parser/misspelled-keywords/while-loop.stderr @@ -3,6 +3,11 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found | LL | whilee a < b { | ^ expected one of 8 possible tokens + | +help: there is a keyword `while` with a similar name + | +LL | while a < b { + | ~~~~~ error: aborting due to 1 previous error