about summary refs log tree commit diff
path: root/compiler/rustc_parse/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_parse/src')
-rw-r--r--compiler/rustc_parse/src/errors.rs95
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs54
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs48
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> {