From 252e0b338575e6dc1d5bde8f9d38fca91305203f Mon Sep 17 00:00:00 2001 From: Ezra Shaw Date: Tue, 7 Mar 2023 23:01:26 +1300 Subject: feat/refactor: improve errors in case of ident with number at start --- compiler/rustc_parse/locales/en-US.ftl | 3 +- compiler/rustc_parse/src/errors.rs | 17 ++++++----- compiler/rustc_parse/src/parser/diagnostics.rs | 41 +++++++++++++++++--------- compiler/rustc_parse/src/parser/pat.rs | 4 +++ compiler/rustc_parse/src/parser/stmt.rs | 12 -------- 5 files changed, 41 insertions(+), 36 deletions(-) (limited to 'compiler/rustc_parse') diff --git a/compiler/rustc_parse/locales/en-US.ftl b/compiler/rustc_parse/locales/en-US.ftl index e76e91fc1b1..5c7dc1e2abf 100644 --- a/compiler/rustc_parse/locales/en-US.ftl +++ b/compiler/rustc_parse/locales/en-US.ftl @@ -412,8 +412,7 @@ parse_fn_ptr_with_generics = function pointer types may not have generic paramet *[false] a } `for` parameter list -parse_invalid_identifier_with_leading_number = expected identifier, found number literal - .label = identifiers cannot start with a number +parse_invalid_identifier_with_leading_number = identifiers cannot start with a number parse_maybe_fn_typo_with_impl = you might have meant to write `impl` instead of `fn` .suggestion = replace `fn` with `impl` here diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 1662db36d10..63e5bc50513 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -939,6 +939,7 @@ pub(crate) struct ExpectedIdentifier { pub token: Token, pub suggest_raw: Option, pub suggest_remove_comma: Option, + pub help_cannot_start_number: Option, } impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier { @@ -975,10 +976,18 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier { sugg.add_to_diagnostic(&mut diag); } + if let Some(help) = self.help_cannot_start_number { + help.add_to_diagnostic(&mut diag); + } + diag } } +#[derive(Subdiagnostic)] +#[help(parse_invalid_identifier_with_leading_number)] +pub(crate) struct HelpIdentifierStartsWithNumber; + pub(crate) struct ExpectedSemi { pub span: Span, pub token: Token, @@ -1207,14 +1216,6 @@ pub(crate) struct SelfParamNotFirst { pub span: Span, } -#[derive(Diagnostic)] -#[diag(parse_invalid_identifier_with_leading_number)] -pub(crate) struct InvalidIdentiferStartsWithNumber { - #[primary_span] - #[label] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(parse_const_generic_without_braces)] pub(crate) struct ConstGenericWithoutBraces { diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 0a65c37ea7b..5b12bcc1822 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -8,14 +8,14 @@ use crate::errors::{ ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg, ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentOnParamType, DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, - GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg, InInTypo, - IncorrectAwait, IncorrectSemicolon, IncorrectUseOfAwait, ParenthesesInForHead, - ParenthesesInForHeadSugg, PatternMethodParamWithoutBody, QuestionMarkInType, - QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath, - StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, StructLiteralNeedingParensSugg, - SuggEscapeToUseAsIdentifier, SuggRemoveComma, UnexpectedConstInGenericParam, - UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, - UseEqInstead, + GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg, + HelpIdentifierStartsWithNumber, InInTypo, IncorrectAwait, IncorrectSemicolon, + IncorrectUseOfAwait, ParenthesesInForHead, ParenthesesInForHeadSugg, + PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, + StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, + StructLiteralNeedingParensSugg, SuggEscapeToUseAsIdentifier, SuggRemoveComma, + UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration, + UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, }; use crate::fluent_generated as fluent; @@ -280,6 +280,7 @@ impl<'a> Parser<'a> { TokenKind::CloseDelim(Delimiter::Brace), TokenKind::CloseDelim(Delimiter::Parenthesis), ]; + let suggest_raw = match self.token.ident() { Some((ident, false)) if ident.is_raw_guess() @@ -295,18 +296,19 @@ impl<'a> Parser<'a> { _ => None, }; - let suggest_remove_comma = - if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) { - Some(SuggRemoveComma { span: self.token.span }) - } else { - None - }; + let suggest_remove_comma = (self.token == token::Comma + && self.look_ahead(1, |t| t.is_ident())) + .then_some(SuggRemoveComma { span: self.token.span }); + + let help_cannot_start_number = + self.is_lit_bad_ident().then_some(HelpIdentifierStartsWithNumber); let err = ExpectedIdentifier { span: self.token.span, token: self.token.clone(), suggest_raw, suggest_remove_comma, + help_cannot_start_number, }; let mut err = err.into_diagnostic(&self.sess.span_diagnostic); @@ -365,6 +367,17 @@ impl<'a> Parser<'a> { err } + /// Checks if the current token is a integer or float literal and looks like + /// it could be a invalid identifier with digits at the start. + pub(super) fn is_lit_bad_ident(&mut self) -> bool { + matches!(self.token.uninterpolate().kind, token::Literal(Lit { kind: token::LitKind::Integer | token::LitKind::Float, .. }) + // ensure that the integer literal is followed by a *invalid* + // suffix: this is how we know that it is a identifier with an + // invalid beginning. + if rustc_ast::MetaItemLit::from_token(&self.token).is_none() + ) + } + pub(super) fn expected_one_of_not_found( &mut self, edible: &[TokenKind], diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 8e920f1c421..fc9f1d1330a 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -348,6 +348,10 @@ impl<'a> Parser<'a> { lo = self.token.span; } + if self.is_lit_bad_ident() { + return Err(self.expected_ident_found()); + } + let pat = if self.check(&token::BinOp(token::And)) || self.token.kind == token::AndAnd { self.parse_pat_deref(expected)? } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) { diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 92a22ffc2b0..fbe5b88c49e 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -273,7 +273,6 @@ impl<'a> Parser<'a> { self.bump(); } - self.report_invalid_identifier_error()?; let (pat, colon) = self.parse_pat_before_ty(None, RecoverComma::Yes, PatternLocation::LetBinding)?; @@ -366,17 +365,6 @@ impl<'a> Parser<'a> { Ok(P(ast::Local { ty, pat, kind, id: DUMMY_NODE_ID, span: lo.to(hi), attrs, tokens: None })) } - /// report error for `let 1x = 123` - pub fn report_invalid_identifier_error(&mut self) -> PResult<'a, ()> { - if let token::Literal(lit) = self.token.uninterpolate().kind && - rustc_ast::MetaItemLit::from_token(&self.token).is_none() && - (lit.kind == token::LitKind::Integer || lit.kind == token::LitKind::Float) && - self.look_ahead(1, |t| matches!(t.kind, token::Eq) || matches!(t.kind, token::Colon ) ) { - return Err(self.sess.create_err(errors::InvalidIdentiferStartsWithNumber { span: self.token.span })); - } - Ok(()) - } - fn check_let_else_init_bool_expr(&self, init: &ast::Expr) { if let ast::ExprKind::Binary(op, ..) = init.kind { if op.node.lazy() { -- cgit 1.4.1-3-g733a5