feat/refactor: improve errors in case of ident with number at start
This commit is contained in:
parent
8824994ccd
commit
252e0b3385
@ -412,8 +412,7 @@ parse_fn_ptr_with_generics = function pointer types may not have generic paramet
|
|||||||
*[false] a
|
*[false] a
|
||||||
} `for` parameter list
|
} `for` parameter list
|
||||||
|
|
||||||
parse_invalid_identifier_with_leading_number = expected identifier, found number literal
|
parse_invalid_identifier_with_leading_number = identifiers cannot start with a number
|
||||||
.label = identifiers cannot start with a number
|
|
||||||
|
|
||||||
parse_maybe_fn_typo_with_impl = you might have meant to write `impl` instead of `fn`
|
parse_maybe_fn_typo_with_impl = you might have meant to write `impl` instead of `fn`
|
||||||
.suggestion = replace `fn` with `impl` here
|
.suggestion = replace `fn` with `impl` here
|
||||||
|
@ -939,6 +939,7 @@ pub(crate) struct ExpectedIdentifier {
|
|||||||
pub token: Token,
|
pub token: Token,
|
||||||
pub suggest_raw: Option<SuggEscapeToUseAsIdentifier>,
|
pub suggest_raw: Option<SuggEscapeToUseAsIdentifier>,
|
||||||
pub suggest_remove_comma: Option<SuggRemoveComma>,
|
pub suggest_remove_comma: Option<SuggRemoveComma>,
|
||||||
|
pub help_cannot_start_number: Option<HelpIdentifierStartsWithNumber>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier {
|
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier {
|
||||||
@ -975,10 +976,18 @@ fn into_diagnostic(
|
|||||||
sugg.add_to_diagnostic(&mut diag);
|
sugg.add_to_diagnostic(&mut diag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(help) = self.help_cannot_start_number {
|
||||||
|
help.add_to_diagnostic(&mut diag);
|
||||||
|
}
|
||||||
|
|
||||||
diag
|
diag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
#[help(parse_invalid_identifier_with_leading_number)]
|
||||||
|
pub(crate) struct HelpIdentifierStartsWithNumber;
|
||||||
|
|
||||||
pub(crate) struct ExpectedSemi {
|
pub(crate) struct ExpectedSemi {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub token: Token,
|
pub token: Token,
|
||||||
@ -1207,14 +1216,6 @@ pub(crate) struct SelfParamNotFirst {
|
|||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
|
||||||
#[diag(parse_invalid_identifier_with_leading_number)]
|
|
||||||
pub(crate) struct InvalidIdentiferStartsWithNumber {
|
|
||||||
#[primary_span]
|
|
||||||
#[label]
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(parse_const_generic_without_braces)]
|
#[diag(parse_const_generic_without_braces)]
|
||||||
pub(crate) struct ConstGenericWithoutBraces {
|
pub(crate) struct ConstGenericWithoutBraces {
|
||||||
|
@ -8,14 +8,14 @@
|
|||||||
ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg,
|
ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg,
|
||||||
ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentOnParamType,
|
ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentOnParamType,
|
||||||
DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
|
DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
|
||||||
GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg, InInTypo,
|
GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg,
|
||||||
IncorrectAwait, IncorrectSemicolon, IncorrectUseOfAwait, ParenthesesInForHead,
|
HelpIdentifierStartsWithNumber, InInTypo, IncorrectAwait, IncorrectSemicolon,
|
||||||
ParenthesesInForHeadSugg, PatternMethodParamWithoutBody, QuestionMarkInType,
|
IncorrectUseOfAwait, ParenthesesInForHead, ParenthesesInForHeadSugg,
|
||||||
QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath,
|
PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst,
|
||||||
StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, StructLiteralNeedingParensSugg,
|
StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens,
|
||||||
SuggEscapeToUseAsIdentifier, SuggRemoveComma, UnexpectedConstInGenericParam,
|
StructLiteralNeedingParensSugg, SuggEscapeToUseAsIdentifier, SuggRemoveComma,
|
||||||
UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets,
|
UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
|
||||||
UseEqInstead,
|
UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::fluent_generated as fluent;
|
use crate::fluent_generated as fluent;
|
||||||
@ -280,6 +280,7 @@ pub(super) fn expected_ident_found(&mut self) -> DiagnosticBuilder<'a, ErrorGuar
|
|||||||
TokenKind::CloseDelim(Delimiter::Brace),
|
TokenKind::CloseDelim(Delimiter::Brace),
|
||||||
TokenKind::CloseDelim(Delimiter::Parenthesis),
|
TokenKind::CloseDelim(Delimiter::Parenthesis),
|
||||||
];
|
];
|
||||||
|
|
||||||
let suggest_raw = match self.token.ident() {
|
let suggest_raw = match self.token.ident() {
|
||||||
Some((ident, false))
|
Some((ident, false))
|
||||||
if ident.is_raw_guess()
|
if ident.is_raw_guess()
|
||||||
@ -295,18 +296,19 @@ pub(super) fn expected_ident_found(&mut self) -> DiagnosticBuilder<'a, ErrorGuar
|
|||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let suggest_remove_comma =
|
let suggest_remove_comma = (self.token == token::Comma
|
||||||
if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) {
|
&& self.look_ahead(1, |t| t.is_ident()))
|
||||||
Some(SuggRemoveComma { span: self.token.span })
|
.then_some(SuggRemoveComma { span: self.token.span });
|
||||||
} else {
|
|
||||||
None
|
let help_cannot_start_number =
|
||||||
};
|
self.is_lit_bad_ident().then_some(HelpIdentifierStartsWithNumber);
|
||||||
|
|
||||||
let err = ExpectedIdentifier {
|
let err = ExpectedIdentifier {
|
||||||
span: self.token.span,
|
span: self.token.span,
|
||||||
token: self.token.clone(),
|
token: self.token.clone(),
|
||||||
suggest_raw,
|
suggest_raw,
|
||||||
suggest_remove_comma,
|
suggest_remove_comma,
|
||||||
|
help_cannot_start_number,
|
||||||
};
|
};
|
||||||
let mut err = err.into_diagnostic(&self.sess.span_diagnostic);
|
let mut err = err.into_diagnostic(&self.sess.span_diagnostic);
|
||||||
|
|
||||||
@ -365,6 +367,17 @@ pub(super) fn expected_ident_found(&mut self) -> DiagnosticBuilder<'a, ErrorGuar
|
|||||||
err
|
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(
|
pub(super) fn expected_one_of_not_found(
|
||||||
&mut self,
|
&mut self,
|
||||||
edible: &[TokenKind],
|
edible: &[TokenKind],
|
||||||
|
@ -348,6 +348,10 @@ fn parse_pat_with_range_pat(
|
|||||||
lo = self.token.span;
|
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 {
|
let pat = if self.check(&token::BinOp(token::And)) || self.token.kind == token::AndAnd {
|
||||||
self.parse_pat_deref(expected)?
|
self.parse_pat_deref(expected)?
|
||||||
} else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
|
} else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
|
||||||
|
@ -273,7 +273,6 @@ fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P<Local>> {
|
|||||||
self.bump();
|
self.bump();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.report_invalid_identifier_error()?;
|
|
||||||
let (pat, colon) =
|
let (pat, colon) =
|
||||||
self.parse_pat_before_ty(None, RecoverComma::Yes, PatternLocation::LetBinding)?;
|
self.parse_pat_before_ty(None, RecoverComma::Yes, PatternLocation::LetBinding)?;
|
||||||
|
|
||||||
@ -366,17 +365,6 @@ fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P<Local>> {
|
|||||||
Ok(P(ast::Local { ty, pat, kind, id: DUMMY_NODE_ID, span: lo.to(hi), attrs, tokens: None }))
|
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) {
|
fn check_let_else_init_bool_expr(&self, init: &ast::Expr) {
|
||||||
if let ast::ExprKind::Binary(op, ..) = init.kind {
|
if let ast::ExprKind::Binary(op, ..) = init.kind {
|
||||||
if op.node.lazy() {
|
if op.node.lazy() {
|
||||||
|
2
tests/ui/parser/integer-literal-start-ident.rs
Normal file
2
tests/ui/parser/integer-literal-start-ident.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
fn 1main() {}
|
||||||
|
//~^ ERROR expected identifier, found `1main`
|
10
tests/ui/parser/integer-literal-start-ident.stderr
Normal file
10
tests/ui/parser/integer-literal-start-ident.stderr
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
error: expected identifier, found `1main`
|
||||||
|
--> $DIR/integer-literal-start-ident.rs:1:4
|
||||||
|
|
|
||||||
|
LL | fn 1main() {}
|
||||||
|
| ^^^^^ expected identifier
|
||||||
|
|
|
||||||
|
= help: identifiers cannot start with a number
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
@ -4,12 +4,12 @@ fn test() {
|
|||||||
|
|
||||||
fn test_2() {
|
fn test_2() {
|
||||||
let 1x = 123;
|
let 1x = 123;
|
||||||
//~^ ERROR expected identifier, found number literal
|
//~^ ERROR expected identifier, found `1x`
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_3() {
|
fn test_3() {
|
||||||
let 2x: i32 = 123;
|
let 2x: i32 = 123;
|
||||||
//~^ ERROR expected identifier, found number literal
|
//~^ ERROR expected identifier, found `2x`
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_4() {
|
fn test_4() {
|
||||||
@ -20,7 +20,7 @@ fn test_4() {
|
|||||||
|
|
||||||
fn test_5() {
|
fn test_5() {
|
||||||
let 23name = 123;
|
let 23name = 123;
|
||||||
//~^ ERROR expected identifier, found number literal
|
//~^ ERROR expected identifier, found `23name`
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
@ -1,20 +1,26 @@
|
|||||||
error: expected identifier, found number literal
|
error: expected identifier, found `1x`
|
||||||
--> $DIR/issue-104088.rs:6:9
|
--> $DIR/issue-104088.rs:6:9
|
||||||
|
|
|
|
||||||
LL | let 1x = 123;
|
LL | let 1x = 123;
|
||||||
| ^^ identifiers cannot start with a number
|
| ^^ expected identifier
|
||||||
|
|
|
||||||
|
= help: identifiers cannot start with a number
|
||||||
|
|
||||||
error: expected identifier, found number literal
|
error: expected identifier, found `2x`
|
||||||
--> $DIR/issue-104088.rs:11:9
|
--> $DIR/issue-104088.rs:11:9
|
||||||
|
|
|
|
||||||
LL | let 2x: i32 = 123;
|
LL | let 2x: i32 = 123;
|
||||||
| ^^ identifiers cannot start with a number
|
| ^^ expected identifier
|
||||||
|
|
|
||||||
|
= help: identifiers cannot start with a number
|
||||||
|
|
||||||
error: expected identifier, found number literal
|
error: expected identifier, found `23name`
|
||||||
--> $DIR/issue-104088.rs:22:9
|
--> $DIR/issue-104088.rs:22:9
|
||||||
|
|
|
|
||||||
LL | let 23name = 123;
|
LL | let 23name = 123;
|
||||||
| ^^^^^^ identifiers cannot start with a number
|
| ^^^^^^ expected identifier
|
||||||
|
|
|
||||||
|
= help: identifiers cannot start with a number
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/issue-104088.rs:16:12
|
--> $DIR/issue-104088.rs:16:12
|
||||||
|
Loading…
Reference in New Issue
Block a user