Skip to content

Commit b4e17a5

Browse files
committed
refactor: improve "ident starts with number" error
1 parent c9ddb73 commit b4e17a5

File tree

6 files changed

+61
-20
lines changed

6 files changed

+61
-20
lines changed

compiler/rustc_parse/src/errors.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -986,7 +986,10 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier {
986986

987987
#[derive(Subdiagnostic)]
988988
#[help(parse_invalid_identifier_with_leading_number)]
989-
pub(crate) struct HelpIdentifierStartsWithNumber;
989+
pub(crate) struct HelpIdentifierStartsWithNumber {
990+
#[primary_span]
991+
pub num_span: Span,
992+
}
990993

991994
pub(crate) struct ExpectedSemi {
992995
pub span: Span,

compiler/rustc_parse/src/parser/diagnostics.rs

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ use rustc_errors::{
3838
use rustc_session::errors::ExprParenthesesNeeded;
3939
use rustc_span::source_map::Spanned;
4040
use rustc_span::symbol::{kw, sym, Ident};
41-
use rustc_span::{Span, SpanSnippetError, DUMMY_SP};
41+
use rustc_span::{Span, SpanSnippetError, Symbol, DUMMY_SP};
4242
use std::mem::take;
4343
use std::ops::{Deref, DerefMut};
4444
use thin_vec::{thin_vec, ThinVec};
@@ -309,8 +309,11 @@ impl<'a> Parser<'a> {
309309
&& self.look_ahead(1, |t| t.is_ident()))
310310
.then_some(SuggRemoveComma { span: self.token.span });
311311

312-
let help_cannot_start_number =
313-
self.is_lit_bad_ident().then_some(HelpIdentifierStartsWithNumber);
312+
let help_cannot_start_number = self.is_lit_bad_ident().map(|(len, _valid_portion)| {
313+
let (invalid, _valid) = self.token.span.split_at(len as u32);
314+
315+
HelpIdentifierStartsWithNumber { num_span: invalid }
316+
});
314317

315318
let err = ExpectedIdentifier {
316319
span: self.token.span,
@@ -378,13 +381,24 @@ impl<'a> Parser<'a> {
378381

379382
/// Checks if the current token is a integer or float literal and looks like
380383
/// it could be a invalid identifier with digits at the start.
381-
pub(super) fn is_lit_bad_ident(&mut self) -> bool {
382-
matches!(self.token.uninterpolate().kind, token::Literal(Lit { kind: token::LitKind::Integer | token::LitKind::Float, .. })
383-
// ensure that the integer literal is followed by a *invalid*
384-
// suffix: this is how we know that it is a identifier with an
385-
// invalid beginning.
386-
if rustc_ast::MetaItemLit::from_token(&self.token).is_none()
387-
)
384+
///
385+
/// Returns the number of characters (bytes) composing the invalid portion
386+
/// of the identifier and the valid portion of the identifier.
387+
pub(super) fn is_lit_bad_ident(&mut self) -> Option<(usize, Symbol)> {
388+
// ensure that the integer literal is followed by a *invalid*
389+
// suffix: this is how we know that it is a identifier with an
390+
// invalid beginning.
391+
if let token::Literal(Lit {
392+
kind: token::LitKind::Integer | token::LitKind::Float,
393+
symbol,
394+
suffix,
395+
}) = self.token.uninterpolate().kind
396+
&& rustc_ast::MetaItemLit::from_token(&self.token).is_none()
397+
{
398+
Some((symbol.as_str().len(), suffix.unwrap()))
399+
} else {
400+
None
401+
}
388402
}
389403

390404
pub(super) fn expected_one_of_not_found(

compiler/rustc_parse/src/parser/pat.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -348,10 +348,6 @@ 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-
355351
let pat = if self.check(&token::BinOp(token::And)) || self.token.kind == token::AndAnd {
356352
self.parse_pat_deref(expected)?
357353
} else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
@@ -395,7 +391,7 @@ impl<'a> Parser<'a> {
395391
} else {
396392
PatKind::Lit(const_expr)
397393
}
398-
} else if self.can_be_ident_pat() {
394+
} else if self.can_be_ident_pat() || self.is_lit_bad_ident().is_some() {
399395
// Parse `ident @ pat`
400396
// This can give false positives and parse nullary enums,
401397
// they are dealt with later in resolve.

compiler/rustc_span/src/lib.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -795,6 +795,18 @@ impl Span {
795795
})
796796
}
797797

798+
/// Splits a span into two composite spans around a certain position.
799+
pub fn split_at(self, pos: u32) -> (Span, Span) {
800+
let len = self.hi().0 - self.lo().0;
801+
debug_assert!(pos <= len);
802+
803+
let split_pos = BytePos(self.lo().0 + pos);
804+
(
805+
Span::new(self.lo(), split_pos, self.ctxt(), self.parent()),
806+
Span::new(split_pos, self.hi(), self.ctxt(), self.parent()),
807+
)
808+
}
809+
798810
/// Returns a `Span` that would enclose both `self` and `end`.
799811
///
800812
/// Note that this can also be used to extend the span "backwards":

tests/ui/parser/integer-literal-start-ident.stderr

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ error: expected identifier, found `1main`
44
LL | fn 1main() {}
55
| ^^^^^ expected identifier
66
|
7-
= help: identifiers cannot start with a number
7+
help: identifiers cannot start with a number
8+
--> $DIR/integer-literal-start-ident.rs:1:4
9+
|
10+
LL | fn 1main() {}
11+
| ^
812

913
error: aborting due to previous error
1014

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

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,35 @@ error: expected identifier, found `1x`
44
LL | let 1x = 123;
55
| ^^ expected identifier
66
|
7-
= help: identifiers cannot start with a number
7+
help: identifiers cannot start with a number
8+
--> $DIR/issue-104088.rs:6:9
9+
|
10+
LL | let 1x = 123;
11+
| ^
812

913
error: expected identifier, found `2x`
1014
--> $DIR/issue-104088.rs:11:9
1115
|
1216
LL | let 2x: i32 = 123;
1317
| ^^ expected identifier
1418
|
15-
= help: identifiers cannot start with a number
19+
help: identifiers cannot start with a number
20+
--> $DIR/issue-104088.rs:11:9
21+
|
22+
LL | let 2x: i32 = 123;
23+
| ^
1624

1725
error: expected identifier, found `23name`
1826
--> $DIR/issue-104088.rs:22:9
1927
|
2028
LL | let 23name = 123;
2129
| ^^^^^^ expected identifier
2230
|
23-
= help: identifiers cannot start with a number
31+
help: identifiers cannot start with a number
32+
--> $DIR/issue-104088.rs:22:9
33+
|
34+
LL | let 23name = 123;
35+
| ^^
2436

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

0 commit comments

Comments
 (0)