Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 8df0582

Browse files
committed
Add metavariables to TokenDescription.
Pasted metavariables are wrapped in invisible delimiters, which pretty-print as empty strings, and changing that can break some proc macros. But error messages saying "expected identifer, found ``" are bad. So this commit adds support for metavariables in `TokenDescription` so they print as "metavariable" in error messages, instead of "``". It's not used meaningfully yet, but will be needed to get rid of interpolated tokens.
1 parent f484b6f commit 8df0582

File tree

3 files changed

+61
-17
lines changed

3 files changed

+61
-17
lines changed

compiler/rustc_parse/messages.ftl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,9 @@ parse_expected_identifier_found_doc_comment = expected identifier, found doc com
209209
parse_expected_identifier_found_doc_comment_str = expected identifier, found doc comment `{$token}`
210210
parse_expected_identifier_found_keyword = expected identifier, found keyword
211211
parse_expected_identifier_found_keyword_str = expected identifier, found keyword `{$token}`
212+
parse_expected_identifier_found_metavar = expected identifier, found metavariable
213+
# This one deliberately doesn't print a token.
214+
parse_expected_identifier_found_metavar_str = expected identifier, found metavariable
212215
parse_expected_identifier_found_reserved_identifier = expected identifier, found reserved identifier
213216
parse_expected_identifier_found_reserved_identifier_str = expected identifier, found reserved identifier `{$token}`
214217
parse_expected_identifier_found_reserved_keyword = expected identifier, found reserved keyword
@@ -220,6 +223,8 @@ parse_expected_mut_or_const_in_raw_pointer_type = expected `mut` or `const` keyw
220223
221224
parse_expected_semi_found_doc_comment_str = expected `;`, found doc comment `{$token}`
222225
parse_expected_semi_found_keyword_str = expected `;`, found keyword `{$token}`
226+
# This one deliberately doesn't print a token.
227+
parse_expected_semi_found_metavar_str = expected `;`, found metavariable
223228
parse_expected_semi_found_reserved_identifier_str = expected `;`, found reserved identifier `{$token}`
224229
parse_expected_semi_found_reserved_keyword_str = expected `;`, found reserved keyword `{$token}`
225230
parse_expected_semi_found_str = expected `;`, found `{$token}`
@@ -816,6 +821,8 @@ parse_unexpected_token_after_not_logical = use `!` to perform logical negation
816821
parse_unexpected_token_after_struct_name = expected `where`, `{"{"}`, `(`, or `;` after struct name
817822
parse_unexpected_token_after_struct_name_found_doc_comment = expected `where`, `{"{"}`, `(`, or `;` after struct name, found doc comment `{$token}`
818823
parse_unexpected_token_after_struct_name_found_keyword = expected `where`, `{"{"}`, `(`, or `;` after struct name, found keyword `{$token}`
824+
# This one deliberately doesn't print a token.
825+
parse_unexpected_token_after_struct_name_found_metavar = expected `where`, `{"{"}`, `(`, or `;` after struct name, found metavar
819826
parse_unexpected_token_after_struct_name_found_other = expected `where`, `{"{"}`, `(`, or `;` after struct name, found `{$token}`
820827
821828
parse_unexpected_token_after_struct_name_found_reserved_identifier = expected `where`, `{"{"}`, `(`, or `;` after struct name, found reserved identifier `{$token}`

compiler/rustc_parse/src/errors.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,6 +1024,8 @@ pub(crate) enum ExpectedIdentifierFound {
10241024
ReservedKeyword(#[primary_span] Span),
10251025
#[label(parse_expected_identifier_found_doc_comment)]
10261026
DocComment(#[primary_span] Span),
1027+
#[label(parse_expected_identifier_found_metavar)]
1028+
MetaVar(#[primary_span] Span),
10271029
#[label(parse_expected_identifier)]
10281030
Other(#[primary_span] Span),
10291031
}
@@ -1037,6 +1039,7 @@ impl ExpectedIdentifierFound {
10371039
Some(TokenDescription::Keyword) => ExpectedIdentifierFound::Keyword,
10381040
Some(TokenDescription::ReservedKeyword) => ExpectedIdentifierFound::ReservedKeyword,
10391041
Some(TokenDescription::DocComment) => ExpectedIdentifierFound::DocComment,
1042+
Some(TokenDescription::MetaVar(_)) => ExpectedIdentifierFound::MetaVar,
10401043
None => ExpectedIdentifierFound::Other,
10411044
})(span)
10421045
}
@@ -1055,6 +1058,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedIdentifier {
10551058
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
10561059
let token_descr = TokenDescription::from_token(&self.token);
10571060

1061+
let mut add_token = true;
10581062
let mut diag = Diag::new(
10591063
dcx,
10601064
level,
@@ -1071,11 +1075,17 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedIdentifier {
10711075
Some(TokenDescription::DocComment) => {
10721076
fluent::parse_expected_identifier_found_doc_comment_str
10731077
}
1078+
Some(TokenDescription::MetaVar(_)) => {
1079+
add_token = false;
1080+
fluent::parse_expected_identifier_found_metavar_str
1081+
}
10741082
None => fluent::parse_expected_identifier_found_str,
10751083
},
10761084
);
10771085
diag.span(self.span);
1078-
diag.arg("token", self.token);
1086+
if add_token {
1087+
diag.arg("token", self.token);
1088+
}
10791089

10801090
if let Some(sugg) = self.suggest_raw {
10811091
sugg.add_to_diag(&mut diag);
@@ -1115,6 +1125,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedSemi {
11151125
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
11161126
let token_descr = TokenDescription::from_token(&self.token);
11171127

1128+
let mut add_token = true;
11181129
let mut diag = Diag::new(
11191130
dcx,
11201131
level,
@@ -1129,11 +1140,17 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedSemi {
11291140
Some(TokenDescription::DocComment) => {
11301141
fluent::parse_expected_semi_found_doc_comment_str
11311142
}
1143+
Some(TokenDescription::MetaVar(_)) => {
1144+
add_token = false;
1145+
fluent::parse_expected_semi_found_metavar_str
1146+
}
11321147
None => fluent::parse_expected_semi_found_str,
11331148
},
11341149
);
11351150
diag.span(self.span);
1136-
diag.arg("token", self.token);
1151+
if add_token {
1152+
diag.arg("token", self.token);
1153+
}
11371154

11381155
if let Some(unexpected_token_label) = self.unexpected_token_label {
11391156
diag.span_label(unexpected_token_label, fluent::parse_label_unexpected_token);
@@ -1813,6 +1830,12 @@ pub(crate) enum UnexpectedTokenAfterStructName {
18131830
span: Span,
18141831
token: Token,
18151832
},
1833+
#[diag(parse_unexpected_token_after_struct_name_found_metavar)]
1834+
MetaVar {
1835+
#[primary_span]
1836+
#[label(parse_unexpected_token_after_struct_name)]
1837+
span: Span,
1838+
},
18161839
#[diag(parse_unexpected_token_after_struct_name_found_other)]
18171840
Other {
18181841
#[primary_span]
@@ -1829,6 +1852,7 @@ impl UnexpectedTokenAfterStructName {
18291852
Some(TokenDescription::Keyword) => Self::Keyword { span, token },
18301853
Some(TokenDescription::ReservedKeyword) => Self::ReservedKeyword { span, token },
18311854
Some(TokenDescription::DocComment) => Self::DocComment { span, token },
1855+
Some(TokenDescription::MetaVar(_)) => Self::MetaVar { span },
18321856
None => Self::Other { span, token },
18331857
}
18341858
}

compiler/rustc_parse/src/parser/mod.rs

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma};
1919
use path::PathStyle;
2020

2121
use rustc_ast::ptr::P;
22-
use rustc_ast::token::{self, Delimiter, IdentIsRaw, Nonterminal, Token, TokenKind};
22+
use rustc_ast::token::{
23+
self, Delimiter, IdentIsRaw, InvisibleOrigin, Nonterminal, NonterminalKind, Token, TokenKind,
24+
};
2325
use rustc_ast::tokenstream::{AttributesData, DelimSpacing, DelimSpan, Spacing};
2426
use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor};
2527
use rustc_ast::util::case::Case;
@@ -372,6 +374,12 @@ pub(super) enum TokenDescription {
372374
Keyword,
373375
ReservedKeyword,
374376
DocComment,
377+
378+
// Expanded metavariables are wrapped in invisible delimiters which aren't
379+
// pretty-printed. In error messages we must handle these specially
380+
// otherwise we get confusing things in messages like "expected `(`, found
381+
// ``". It's better to say e.g. "expected `(`, found type metavariable".
382+
MetaVar(NonterminalKind),
375383
}
376384

377385
impl TokenDescription {
@@ -381,26 +389,31 @@ impl TokenDescription {
381389
_ if token.is_used_keyword() => Some(TokenDescription::Keyword),
382390
_ if token.is_unused_keyword() => Some(TokenDescription::ReservedKeyword),
383391
token::DocComment(..) => Some(TokenDescription::DocComment),
392+
token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(kind))) => {
393+
Some(TokenDescription::MetaVar(kind))
394+
}
384395
_ => None,
385396
}
386397
}
387398
}
388399

389400
pub fn token_descr(token: &Token) -> String {
390-
let name = pprust::token_to_string(token).to_string();
391-
392-
let kind = match (TokenDescription::from_token(token), &token.kind) {
393-
(Some(TokenDescription::ReservedIdentifier), _) => Some("reserved identifier"),
394-
(Some(TokenDescription::Keyword), _) => Some("keyword"),
395-
(Some(TokenDescription::ReservedKeyword), _) => Some("reserved keyword"),
396-
(Some(TokenDescription::DocComment), _) => Some("doc comment"),
397-
(None, TokenKind::NtIdent(..)) => Some("identifier"),
398-
(None, TokenKind::NtLifetime(..)) => Some("lifetime"),
399-
(None, TokenKind::Interpolated(node)) => Some(node.descr()),
400-
(None, _) => None,
401-
};
402-
403-
if let Some(kind) = kind { format!("{kind} `{name}`") } else { format!("`{name}`") }
401+
use TokenDescription::*;
402+
403+
let s = pprust::token_to_string(token).to_string();
404+
405+
match (TokenDescription::from_token(token), &token.kind) {
406+
(Some(ReservedIdentifier), _) => format!("reserved identifier `{s}`"),
407+
(Some(Keyword), _) => format!("keyword `{s}`"),
408+
(Some(ReservedKeyword), _) => format!("reserved keyword `{s}`"),
409+
(Some(DocComment), _) => format!("doc comment `{s}`"),
410+
// Deliberately doesn't print `s`, which is empty.
411+
(Some(MetaVar(kind)), _) => format!("`{kind}` metavariable"),
412+
(None, TokenKind::NtIdent(..)) => format!("identifier `{s}`"),
413+
(None, TokenKind::NtLifetime(..)) => format!("lifetime `{s}`"),
414+
(None, TokenKind::Interpolated(node)) => format!("{} `{s}`", node.descr()),
415+
(None, _) => format!("`{s}`"),
416+
}
404417
}
405418

406419
impl<'a> Parser<'a> {

0 commit comments

Comments
 (0)