Skip to content

Commit 252e0b3

Browse files
committedMar 9, 2023
feat/refactor: improve errors in case of ident with number at start
1 parent 8824994 commit 252e0b3

File tree

9 files changed

+68
-45
lines changed

9 files changed

+68
-45
lines changed
 

‎compiler/rustc_parse/locales/en-US.ftl

+1-2
Original file line numberDiff line numberDiff line change
@@ -412,8 +412,7 @@ parse_fn_ptr_with_generics = function pointer types may not have generic paramet
412412
*[false] a
413413
} `for` parameter list
414414
415-
parse_invalid_identifier_with_leading_number = expected identifier, found number literal
416-
.label = identifiers cannot start with a number
415+
parse_invalid_identifier_with_leading_number = identifiers cannot start with a number
417416
418417
parse_maybe_fn_typo_with_impl = you might have meant to write `impl` instead of `fn`
419418
.suggestion = replace `fn` with `impl` here

‎compiler/rustc_parse/src/errors.rs

+9-8
Original file line numberDiff line numberDiff line change
@@ -939,6 +939,7 @@ pub(crate) struct ExpectedIdentifier {
939939
pub token: Token,
940940
pub suggest_raw: Option<SuggEscapeToUseAsIdentifier>,
941941
pub suggest_remove_comma: Option<SuggRemoveComma>,
942+
pub help_cannot_start_number: Option<HelpIdentifierStartsWithNumber>,
942943
}
943944

944945
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier {
@@ -975,10 +976,18 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier {
975976
sugg.add_to_diagnostic(&mut diag);
976977
}
977978

979+
if let Some(help) = self.help_cannot_start_number {
980+
help.add_to_diagnostic(&mut diag);
981+
}
982+
978983
diag
979984
}
980985
}
981986

987+
#[derive(Subdiagnostic)]
988+
#[help(parse_invalid_identifier_with_leading_number)]
989+
pub(crate) struct HelpIdentifierStartsWithNumber;
990+
982991
pub(crate) struct ExpectedSemi {
983992
pub span: Span,
984993
pub token: Token,
@@ -1207,14 +1216,6 @@ pub(crate) struct SelfParamNotFirst {
12071216
pub span: Span,
12081217
}
12091218

1210-
#[derive(Diagnostic)]
1211-
#[diag(parse_invalid_identifier_with_leading_number)]
1212-
pub(crate) struct InvalidIdentiferStartsWithNumber {
1213-
#[primary_span]
1214-
#[label]
1215-
pub span: Span,
1216-
}
1217-
12181219
#[derive(Diagnostic)]
12191220
#[diag(parse_const_generic_without_braces)]
12201221
pub(crate) struct ConstGenericWithoutBraces {

‎compiler/rustc_parse/src/parser/diagnostics.rs

+27-14
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ use crate::errors::{
88
ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg,
99
ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentOnParamType,
1010
DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
11-
GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg, InInTypo,
12-
IncorrectAwait, IncorrectSemicolon, IncorrectUseOfAwait, ParenthesesInForHead,
13-
ParenthesesInForHeadSugg, PatternMethodParamWithoutBody, QuestionMarkInType,
14-
QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath,
15-
StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, StructLiteralNeedingParensSugg,
16-
SuggEscapeToUseAsIdentifier, SuggRemoveComma, UnexpectedConstInGenericParam,
17-
UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets,
18-
UseEqInstead,
11+
GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg,
12+
HelpIdentifierStartsWithNumber, InInTypo, IncorrectAwait, IncorrectSemicolon,
13+
IncorrectUseOfAwait, ParenthesesInForHead, ParenthesesInForHeadSugg,
14+
PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst,
15+
StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens,
16+
StructLiteralNeedingParensSugg, SuggEscapeToUseAsIdentifier, SuggRemoveComma,
17+
UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
18+
UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead,
1919
};
2020

2121
use crate::fluent_generated as fluent;
@@ -280,6 +280,7 @@ impl<'a> Parser<'a> {
280280
TokenKind::CloseDelim(Delimiter::Brace),
281281
TokenKind::CloseDelim(Delimiter::Parenthesis),
282282
];
283+
283284
let suggest_raw = match self.token.ident() {
284285
Some((ident, false))
285286
if ident.is_raw_guess()
@@ -295,18 +296,19 @@ impl<'a> Parser<'a> {
295296
_ => None,
296297
};
297298

298-
let suggest_remove_comma =
299-
if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) {
300-
Some(SuggRemoveComma { span: self.token.span })
301-
} else {
302-
None
303-
};
299+
let suggest_remove_comma = (self.token == token::Comma
300+
&& self.look_ahead(1, |t| t.is_ident()))
301+
.then_some(SuggRemoveComma { span: self.token.span });
302+
303+
let help_cannot_start_number =
304+
self.is_lit_bad_ident().then_some(HelpIdentifierStartsWithNumber);
304305

305306
let err = ExpectedIdentifier {
306307
span: self.token.span,
307308
token: self.token.clone(),
308309
suggest_raw,
309310
suggest_remove_comma,
311+
help_cannot_start_number,
310312
};
311313
let mut err = err.into_diagnostic(&self.sess.span_diagnostic);
312314

@@ -365,6 +367,17 @@ impl<'a> Parser<'a> {
365367
err
366368
}
367369

370+
/// Checks if the current token is a integer or float literal and looks like
371+
/// it could be a invalid identifier with digits at the start.
372+
pub(super) fn is_lit_bad_ident(&mut self) -> bool {
373+
matches!(self.token.uninterpolate().kind, token::Literal(Lit { kind: token::LitKind::Integer | token::LitKind::Float, .. })
374+
// ensure that the integer literal is followed by a *invalid*
375+
// suffix: this is how we know that it is a identifier with an
376+
// invalid beginning.
377+
if rustc_ast::MetaItemLit::from_token(&self.token).is_none()
378+
)
379+
}
380+
368381
pub(super) fn expected_one_of_not_found(
369382
&mut self,
370383
edible: &[TokenKind],

‎compiler/rustc_parse/src/parser/pat.rs

+4
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,10 @@ impl<'a> Parser<'a> {
348348
lo = self.token.span;
349349
}
350350

351+
if self.is_lit_bad_ident() {
352+
return Err(self.expected_ident_found());
353+
}
354+
351355
let pat = if self.check(&token::BinOp(token::And)) || self.token.kind == token::AndAnd {
352356
self.parse_pat_deref(expected)?
353357
} else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {

‎compiler/rustc_parse/src/parser/stmt.rs

-12
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,6 @@ impl<'a> Parser<'a> {
273273
self.bump();
274274
}
275275

276-
self.report_invalid_identifier_error()?;
277276
let (pat, colon) =
278277
self.parse_pat_before_ty(None, RecoverComma::Yes, PatternLocation::LetBinding)?;
279278

@@ -366,17 +365,6 @@ impl<'a> Parser<'a> {
366365
Ok(P(ast::Local { ty, pat, kind, id: DUMMY_NODE_ID, span: lo.to(hi), attrs, tokens: None }))
367366
}
368367

369-
/// report error for `let 1x = 123`
370-
pub fn report_invalid_identifier_error(&mut self) -> PResult<'a, ()> {
371-
if let token::Literal(lit) = self.token.uninterpolate().kind &&
372-
rustc_ast::MetaItemLit::from_token(&self.token).is_none() &&
373-
(lit.kind == token::LitKind::Integer || lit.kind == token::LitKind::Float) &&
374-
self.look_ahead(1, |t| matches!(t.kind, token::Eq) || matches!(t.kind, token::Colon ) ) {
375-
return Err(self.sess.create_err(errors::InvalidIdentiferStartsWithNumber { span: self.token.span }));
376-
}
377-
Ok(())
378-
}
379-
380368
fn check_let_else_init_bool_expr(&self, init: &ast::Expr) {
381369
if let ast::ExprKind::Binary(op, ..) = init.kind {
382370
if op.node.lazy() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
fn 1main() {}
2+
//~^ ERROR expected identifier, found `1main`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: expected identifier, found `1main`
2+
--> $DIR/integer-literal-start-ident.rs:1:4
3+
|
4+
LL | fn 1main() {}
5+
| ^^^^^ expected identifier
6+
|
7+
= help: identifiers cannot start with a number
8+
9+
error: aborting due to previous error
10+

‎tests/ui/parser/issues/issue-104088.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ fn test() {
44

55
fn test_2() {
66
let 1x = 123;
7-
//~^ ERROR expected identifier, found number literal
7+
//~^ ERROR expected identifier, found `1x`
88
}
99

1010
fn test_3() {
1111
let 2x: i32 = 123;
12-
//~^ ERROR expected identifier, found number literal
12+
//~^ ERROR expected identifier, found `2x`
1313
}
1414

1515
fn test_4() {
@@ -20,7 +20,7 @@ fn test_4() {
2020

2121
fn test_5() {
2222
let 23name = 123;
23-
//~^ ERROR expected identifier, found number literal
23+
//~^ ERROR expected identifier, found `23name`
2424
}
2525

2626
fn main() {}

‎tests/ui/parser/issues/issue-104088.stderr

+12-6
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,26 @@
1-
error: expected identifier, found number literal
1+
error: expected identifier, found `1x`
22
--> $DIR/issue-104088.rs:6:9
33
|
44
LL | let 1x = 123;
5-
| ^^ identifiers cannot start with a number
5+
| ^^ expected identifier
6+
|
7+
= help: identifiers cannot start with a number
68

7-
error: expected identifier, found number literal
9+
error: expected identifier, found `2x`
810
--> $DIR/issue-104088.rs:11:9
911
|
1012
LL | let 2x: i32 = 123;
11-
| ^^ identifiers cannot start with a number
13+
| ^^ expected identifier
14+
|
15+
= help: identifiers cannot start with a number
1216

13-
error: expected identifier, found number literal
17+
error: expected identifier, found `23name`
1418
--> $DIR/issue-104088.rs:22:9
1519
|
1620
LL | let 23name = 123;
17-
| ^^^^^^ identifiers cannot start with a number
21+
| ^^^^^^ expected identifier
22+
|
23+
= help: identifiers cannot start with a number
1824

1925
error[E0308]: mismatched types
2026
--> $DIR/issue-104088.rs:16:12

0 commit comments

Comments
 (0)
Please sign in to comment.