diff options
Diffstat (limited to 'compiler/rustc_parse/src')
| -rw-r--r-- | compiler/rustc_parse/src/errors.rs | 95 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/diagnostics.rs | 54 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/mod.rs | 48 |
3 files changed, 154 insertions, 43 deletions
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 968d0be5b42..3b86dd15747 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1,9 +1,11 @@ -use rustc_errors::Applicability; +use rustc_errors::{fluent, AddToDiagnostic, Applicability, EmissionGuarantee, IntoDiagnostic}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::symbol::Ident; use rustc_span::{Span, Symbol}; +use crate::parser::{TokenDescription, TokenDescriptionKind}; + #[derive(Diagnostic)] #[diag(parser::maybe_report_ambiguous_plus)] pub(crate) struct AmbiguousPlus { @@ -870,3 +872,94 @@ pub(crate) struct InvalidMetaItem { pub span: Span, pub token: String, } + +#[derive(Subdiagnostic)] +#[suggestion_verbose( + parser::sugg_escape_to_use_as_identifier, + applicability = "maybe-incorrect", + code = "r#" +)] +pub(crate) struct SuggEscapeToUseAsIdentifier { + #[primary_span] + pub span: Span, + pub ident_name: String, +} + +#[derive(Subdiagnostic)] +#[suggestion(parser::sugg_remove_comma, applicability = "machine-applicable", code = "")] +pub(crate) struct SuggRemoveComma { + #[primary_span] + pub span: Span, +} + +#[derive(Subdiagnostic)] +pub(crate) enum ExpectedIdentifierFound { + #[label(parser::expected_identifier_found_reserved_identifier)] + ReservedIdentifier(#[primary_span] Span), + #[label(parser::expected_identifier_found_keyword)] + Keyword(#[primary_span] Span), + #[label(parser::expected_identifier_found_reserved_keyword)] + ReservedKeyword(#[primary_span] Span), + #[label(parser::expected_identifier_found_doc_comment)] + DocComment(#[primary_span] Span), + #[label(parser::expected_identifier)] + Other(#[primary_span] Span), +} + +impl ExpectedIdentifierFound { + pub fn new(token_descr_kind: Option<TokenDescriptionKind>, span: Span) -> Self { + (match token_descr_kind { + Some(TokenDescriptionKind::ReservedIdentifier) => { + ExpectedIdentifierFound::ReservedIdentifier + } + Some(TokenDescriptionKind::Keyword) => ExpectedIdentifierFound::Keyword, + Some(TokenDescriptionKind::ReservedKeyword) => ExpectedIdentifierFound::ReservedKeyword, + Some(TokenDescriptionKind::DocComment) => ExpectedIdentifierFound::DocComment, + None => ExpectedIdentifierFound::Other, + })(span) + } +} + +pub(crate) struct ExpectedIdentifier { + pub span: Span, + pub token_descr: TokenDescription, + pub suggest_raw: Option<SuggEscapeToUseAsIdentifier>, + pub suggest_remove_comma: Option<SuggRemoveComma>, +} + +impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier { + fn into_diagnostic( + self, + handler: &'a rustc_errors::Handler, + ) -> rustc_errors::DiagnosticBuilder<'a, G> { + let mut diag = handler.struct_diagnostic(match self.token_descr.kind { + Some(TokenDescriptionKind::ReservedIdentifier) => { + fluent::parser::expected_identifier_found_reserved_identifier_str + } + Some(TokenDescriptionKind::Keyword) => { + fluent::parser::expected_identifier_found_keyword_str + } + Some(TokenDescriptionKind::ReservedKeyword) => { + fluent::parser::expected_identifier_found_reserved_keyword_str + } + Some(TokenDescriptionKind::DocComment) => { + fluent::parser::expected_identifier_found_doc_comment_str + } + None => fluent::parser::expected_identifier_found_str, + }); + diag.set_span(self.span); + diag.set_arg("token_str", self.token_descr.name); + + if let Some(sugg) = self.suggest_raw { + sugg.add_to_diagnostic(&mut diag); + } + + ExpectedIdentifierFound::new(self.token_descr.kind, self.span).add_to_diagnostic(&mut diag); + + if let Some(sugg) = self.suggest_remove_comma { + sugg.add_to_diagnostic(&mut diag); + } + + diag + } +} diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 326b2553eaf..8c2a925a231 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -4,8 +4,9 @@ use super::{ TokenExpectType, TokenType, }; use crate::errors::{ - AmbiguousPlus, BadQPathStage2, BadTypePlus, BadTypePlusSub, InInTypo, IncorrectAwait, - IncorrectSemicolon, IncorrectUseOfAwait, UseEqInstead, + AmbiguousPlus, BadQPathStage2, BadTypePlus, BadTypePlusSub, ExpectedIdentifier, InInTypo, + IncorrectAwait, IncorrectSemicolon, IncorrectUseOfAwait, SuggEscapeToUseAsIdentifier, + SuggRemoveComma, UseEqInstead, }; use crate::lexer::UnmatchedBrace; @@ -23,7 +24,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ fluent, Applicability, DiagnosticBuilder, DiagnosticMessage, Handler, MultiSpan, PResult, }; -use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed}; +use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed, IntoDiagnostic}; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{Span, SpanSnippetError, DUMMY_SP}; @@ -285,10 +286,6 @@ impl<'a> Parser<'a> { } pub(super) fn expected_ident_found(&self) -> DiagnosticBuilder<'a, ErrorGuaranteed> { - let mut err = self.struct_span_err( - self.token.span, - &format!("expected identifier, found {}", super::token_descr(&self.token)), - ); let valid_follow = &[ TokenKind::Eq, TokenKind::Colon, @@ -300,34 +297,33 @@ impl<'a> Parser<'a> { TokenKind::CloseDelim(Delimiter::Brace), TokenKind::CloseDelim(Delimiter::Parenthesis), ]; - match self.token.ident() { + let suggest_raw = match self.token.ident() { Some((ident, false)) if ident.is_raw_guess() && self.look_ahead(1, |t| valid_follow.contains(&t.kind)) => { - err.span_suggestion_verbose( - ident.span.shrink_to_lo(), - &format!("escape `{}` to use it as an identifier", ident.name), - "r#", - Applicability::MaybeIncorrect, - ); + Some(SuggEscapeToUseAsIdentifier { + span: ident.span.shrink_to_lo(), + ident_name: ident.name.to_string(), + }) } - _ => {} - } - if let Some(token_descr) = super::token_descr_opt(&self.token) { - err.span_label(self.token.span, format!("expected identifier, found {}", token_descr)); - } else { - err.span_label(self.token.span, "expected identifier"); + _ => None, + }; + + let suggest_remove_comma = if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) { - err.span_suggestion( - self.token.span, - "remove this comma", - "", - Applicability::MachineApplicable, - ); - } - } - err + Some(SuggRemoveComma { span: self.token.span }) + } else { + None + }; + + let err = ExpectedIdentifier { + span: self.token.span, + token_descr: super::token_descr_struct(&self.token), + suggest_raw, + suggest_remove_comma, + }; + err.into_diagnostic(&self.sess.span_diagnostic) } pub(super) fn expected_one_of_not_found( diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 07fa909e71b..a1a224e8524 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -410,22 +410,44 @@ pub enum FollowedByType { No, } -fn token_descr_opt(token: &Token) -> Option<&'static str> { - Some(match token.kind { - _ if token.is_special_ident() => "reserved identifier", - _ if token.is_used_keyword() => "keyword", - _ if token.is_unused_keyword() => "reserved keyword", - token::DocComment(..) => "doc comment", - _ => return None, - }) +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum TokenDescriptionKind { + ReservedIdentifier, + Keyword, + ReservedKeyword, + DocComment, +} + +#[derive(Clone, PartialEq, Eq)] +pub struct TokenDescription { + pub kind: Option<TokenDescriptionKind>, + pub name: String, +} + +pub(super) fn token_descr_struct(token: &Token) -> TokenDescription { + let kind = match token.kind { + _ if token.is_special_ident() => Some(TokenDescriptionKind::ReservedIdentifier), + _ if token.is_used_keyword() => Some(TokenDescriptionKind::Keyword), + _ if token.is_unused_keyword() => Some(TokenDescriptionKind::ReservedKeyword), + token::DocComment(..) => Some(TokenDescriptionKind::DocComment), + _ => None, + }; + let name = pprust::token_to_string(token).to_string(); + + TokenDescription { kind, name } } pub(super) fn token_descr(token: &Token) -> String { - let token_str = pprust::token_to_string(token); - match token_descr_opt(token) { - Some(prefix) => format!("{} `{}`", prefix, token_str), - _ => format!("`{}`", token_str), - } + let TokenDescription { kind, name } = token_descr_struct(token); + + let kind = kind.map(|kind| match kind { + TokenDescriptionKind::ReservedIdentifier => "reserved identifier", + TokenDescriptionKind::Keyword => "keyword", + TokenDescriptionKind::ReservedKeyword => "reserved keyword", + TokenDescriptionKind::DocComment => "doc comment", + }); + + if let Some(kind) = kind { format!("{} `{}`", kind, name) } else { format!("`{}`", name) } } impl<'a> Parser<'a> { |
