refactor: improve "ident starts with number" error

This commit is contained in:
Ezra Shaw 2023-03-17 21:41:26 +13:00
parent c9ddb73184
commit b4e17a5098
No known key found for this signature in database
GPG Key ID: 67ABF16FB0ECD870
6 changed files with 61 additions and 20 deletions

View File

@ -986,7 +986,10 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier {
#[derive(Subdiagnostic)] #[derive(Subdiagnostic)]
#[help(parse_invalid_identifier_with_leading_number)] #[help(parse_invalid_identifier_with_leading_number)]
pub(crate) struct HelpIdentifierStartsWithNumber; pub(crate) struct HelpIdentifierStartsWithNumber {
#[primary_span]
pub num_span: Span,
}
pub(crate) struct ExpectedSemi { pub(crate) struct ExpectedSemi {
pub span: Span, pub span: Span,

View File

@ -38,7 +38,7 @@ use rustc_errors::{
use rustc_session::errors::ExprParenthesesNeeded; use rustc_session::errors::ExprParenthesesNeeded;
use rustc_span::source_map::Spanned; use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{Span, SpanSnippetError, DUMMY_SP}; use rustc_span::{Span, SpanSnippetError, Symbol, DUMMY_SP};
use std::mem::take; use std::mem::take;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use thin_vec::{thin_vec, ThinVec}; use thin_vec::{thin_vec, ThinVec};
@ -309,8 +309,11 @@ impl<'a> Parser<'a> {
&& self.look_ahead(1, |t| t.is_ident())) && self.look_ahead(1, |t| t.is_ident()))
.then_some(SuggRemoveComma { span: self.token.span }); .then_some(SuggRemoveComma { span: self.token.span });
let help_cannot_start_number = let help_cannot_start_number = self.is_lit_bad_ident().map(|(len, _valid_portion)| {
self.is_lit_bad_ident().then_some(HelpIdentifierStartsWithNumber); let (invalid, _valid) = self.token.span.split_at(len as u32);
HelpIdentifierStartsWithNumber { num_span: invalid }
});
let err = ExpectedIdentifier { let err = ExpectedIdentifier {
span: self.token.span, span: self.token.span,
@ -378,13 +381,24 @@ impl<'a> Parser<'a> {
/// Checks if the current token is a integer or float literal and looks like /// 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. /// 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, .. }) /// Returns the number of characters (bytes) composing the invalid portion
// ensure that the integer literal is followed by a *invalid* /// of the identifier and the valid portion of the identifier.
// suffix: this is how we know that it is a identifier with an pub(super) fn is_lit_bad_ident(&mut self) -> Option<(usize, Symbol)> {
// invalid beginning. // ensure that the integer literal is followed by a *invalid*
if rustc_ast::MetaItemLit::from_token(&self.token).is_none() // suffix: this is how we know that it is a identifier with an
) // invalid beginning.
if let token::Literal(Lit {
kind: token::LitKind::Integer | token::LitKind::Float,
symbol,
suffix,
}) = self.token.uninterpolate().kind
&& rustc_ast::MetaItemLit::from_token(&self.token).is_none()
{
Some((symbol.as_str().len(), suffix.unwrap()))
} else {
None
}
} }
pub(super) fn expected_one_of_not_found( pub(super) fn expected_one_of_not_found(

View File

@ -348,10 +348,6 @@ impl<'a> Parser<'a> {
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)) {
@ -395,7 +391,7 @@ impl<'a> Parser<'a> {
} else { } else {
PatKind::Lit(const_expr) PatKind::Lit(const_expr)
} }
} else if self.can_be_ident_pat() { } else if self.can_be_ident_pat() || self.is_lit_bad_ident().is_some() {
// Parse `ident @ pat` // Parse `ident @ pat`
// This can give false positives and parse nullary enums, // This can give false positives and parse nullary enums,
// they are dealt with later in resolve. // they are dealt with later in resolve.

View File

@ -795,6 +795,18 @@ impl Span {
}) })
} }
/// Splits a span into two composite spans around a certain position.
pub fn split_at(self, pos: u32) -> (Span, Span) {
let len = self.hi().0 - self.lo().0;
debug_assert!(pos <= len);
let split_pos = BytePos(self.lo().0 + pos);
(
Span::new(self.lo(), split_pos, self.ctxt(), self.parent()),
Span::new(split_pos, self.hi(), self.ctxt(), self.parent()),
)
}
/// Returns a `Span` that would enclose both `self` and `end`. /// Returns a `Span` that would enclose both `self` and `end`.
/// ///
/// Note that this can also be used to extend the span "backwards": /// Note that this can also be used to extend the span "backwards":

View File

@ -4,7 +4,11 @@ error: expected identifier, found `1main`
LL | fn 1main() {} LL | fn 1main() {}
| ^^^^^ expected identifier | ^^^^^ expected identifier
| |
= help: identifiers cannot start with a number help: identifiers cannot start with a number
--> $DIR/integer-literal-start-ident.rs:1:4
|
LL | fn 1main() {}
| ^
error: aborting due to previous error error: aborting due to previous error

View File

@ -4,7 +4,11 @@ error: expected identifier, found `1x`
LL | let 1x = 123; LL | let 1x = 123;
| ^^ expected identifier | ^^ expected identifier
| |
= help: identifiers cannot start with a number help: identifiers cannot start with a number
--> $DIR/issue-104088.rs:6:9
|
LL | let 1x = 123;
| ^
error: expected identifier, found `2x` error: expected identifier, found `2x`
--> $DIR/issue-104088.rs:11:9 --> $DIR/issue-104088.rs:11:9
@ -12,7 +16,11 @@ error: expected identifier, found `2x`
LL | let 2x: i32 = 123; LL | let 2x: i32 = 123;
| ^^ expected identifier | ^^ expected identifier
| |
= help: identifiers cannot start with a number help: identifiers cannot start with a number
--> $DIR/issue-104088.rs:11:9
|
LL | let 2x: i32 = 123;
| ^
error: expected identifier, found `23name` error: expected identifier, found `23name`
--> $DIR/issue-104088.rs:22:9 --> $DIR/issue-104088.rs:22:9
@ -20,7 +28,11 @@ error: expected identifier, found `23name`
LL | let 23name = 123; LL | let 23name = 123;
| ^^^^^^ expected identifier | ^^^^^^ expected identifier
| |
= help: identifiers cannot start with a number help: identifiers cannot start with a number
--> $DIR/issue-104088.rs:22:9
|
LL | let 23name = 123;
| ^^
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/issue-104088.rs:16:12 --> $DIR/issue-104088.rs:16:12