Skip to content

Commit cfafa93

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 afe238f commit cfafa93

File tree

3 files changed

+59
-17
lines changed

3 files changed

+59
-17
lines changed

compiler/rustc_parse/messages.ftl

+7
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,9 @@ parse_expected_identifier_found_doc_comment = expected identifier, found doc com
216216
parse_expected_identifier_found_doc_comment_str = expected identifier, found doc comment `{$token}`
217217
parse_expected_identifier_found_keyword = expected identifier, found keyword
218218
parse_expected_identifier_found_keyword_str = expected identifier, found keyword `{$token}`
219+
parse_expected_identifier_found_metavar = expected identifier, found metavariable
220+
# This one deliberately doesn't print a token.
221+
parse_expected_identifier_found_metavar_str = expected identifier, found metavariable
219222
parse_expected_identifier_found_reserved_identifier = expected identifier, found reserved identifier
220223
parse_expected_identifier_found_reserved_identifier_str = expected identifier, found reserved identifier `{$token}`
221224
parse_expected_identifier_found_reserved_keyword = expected identifier, found reserved keyword
@@ -227,6 +230,8 @@ parse_expected_mut_or_const_in_raw_pointer_type = expected `mut` or `const` keyw
227230
228231
parse_expected_semi_found_doc_comment_str = expected `;`, found doc comment `{$token}`
229232
parse_expected_semi_found_keyword_str = expected `;`, found keyword `{$token}`
233+
# This one deliberately doesn't print a token.
234+
parse_expected_semi_found_metavar_str = expected `;`, found metavariable
230235
parse_expected_semi_found_reserved_identifier_str = expected `;`, found reserved identifier `{$token}`
231236
parse_expected_semi_found_reserved_keyword_str = expected `;`, found reserved keyword `{$token}`
232237
parse_expected_semi_found_str = expected `;`, found `{$token}`
@@ -864,6 +869,8 @@ parse_unexpected_token_after_not_logical = use `!` to perform logical negation
864869
parse_unexpected_token_after_struct_name = expected `where`, `{"{"}`, `(`, or `;` after struct name
865870
parse_unexpected_token_after_struct_name_found_doc_comment = expected `where`, `{"{"}`, `(`, or `;` after struct name, found doc comment `{$token}`
866871
parse_unexpected_token_after_struct_name_found_keyword = expected `where`, `{"{"}`, `(`, or `;` after struct name, found keyword `{$token}`
872+
# This one deliberately doesn't print a token.
873+
parse_unexpected_token_after_struct_name_found_metavar = expected `where`, `{"{"}`, `(`, or `;` after struct name, found metavar
867874
parse_unexpected_token_after_struct_name_found_other = expected `where`, `{"{"}`, `(`, or `;` after struct name, found `{$token}`
868875
869876
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

+26-2
Original file line numberDiff line numberDiff line change
@@ -1086,6 +1086,8 @@ pub(crate) enum ExpectedIdentifierFound {
10861086
ReservedKeyword(#[primary_span] Span),
10871087
#[label(parse_expected_identifier_found_doc_comment)]
10881088
DocComment(#[primary_span] Span),
1089+
#[label(parse_expected_identifier_found_metavar)]
1090+
MetaVar(#[primary_span] Span),
10891091
#[label(parse_expected_identifier)]
10901092
Other(#[primary_span] Span),
10911093
}
@@ -1099,6 +1101,7 @@ impl ExpectedIdentifierFound {
10991101
Some(TokenDescription::Keyword) => ExpectedIdentifierFound::Keyword,
11001102
Some(TokenDescription::ReservedKeyword) => ExpectedIdentifierFound::ReservedKeyword,
11011103
Some(TokenDescription::DocComment) => ExpectedIdentifierFound::DocComment,
1104+
Some(TokenDescription::MetaVar(_)) => ExpectedIdentifierFound::MetaVar,
11021105
None => ExpectedIdentifierFound::Other,
11031106
})(span)
11041107
}
@@ -1117,6 +1120,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedIdentifier {
11171120
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
11181121
let token_descr = TokenDescription::from_token(&self.token);
11191122

1123+
let mut add_token = true;
11201124
let mut diag = Diag::new(dcx, level, match token_descr {
11211125
Some(TokenDescription::ReservedIdentifier) => {
11221126
fluent::parse_expected_identifier_found_reserved_identifier_str
@@ -1128,10 +1132,16 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedIdentifier {
11281132
Some(TokenDescription::DocComment) => {
11291133
fluent::parse_expected_identifier_found_doc_comment_str
11301134
}
1135+
Some(TokenDescription::MetaVar(_)) => {
1136+
add_token = false;
1137+
fluent::parse_expected_identifier_found_metavar_str
1138+
}
11311139
None => fluent::parse_expected_identifier_found_str,
11321140
});
11331141
diag.span(self.span);
1134-
diag.arg("token", self.token);
1142+
if add_token {
1143+
diag.arg("token", self.token);
1144+
}
11351145

11361146
if let Some(sugg) = self.suggest_raw {
11371147
sugg.add_to_diag(&mut diag);
@@ -1171,6 +1181,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedSemi {
11711181
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
11721182
let token_descr = TokenDescription::from_token(&self.token);
11731183

1184+
let mut add_token = true;
11741185
let mut diag = Diag::new(dcx, level, match token_descr {
11751186
Some(TokenDescription::ReservedIdentifier) => {
11761187
fluent::parse_expected_semi_found_reserved_identifier_str
@@ -1180,10 +1191,16 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedSemi {
11801191
fluent::parse_expected_semi_found_reserved_keyword_str
11811192
}
11821193
Some(TokenDescription::DocComment) => fluent::parse_expected_semi_found_doc_comment_str,
1194+
Some(TokenDescription::MetaVar(_)) => {
1195+
add_token = false;
1196+
fluent::parse_expected_semi_found_metavar_str
1197+
}
11831198
None => fluent::parse_expected_semi_found_str,
11841199
});
11851200
diag.span(self.span);
1186-
diag.arg("token", self.token);
1201+
if add_token {
1202+
diag.arg("token", self.token);
1203+
}
11871204

11881205
if let Some(unexpected_token_label) = self.unexpected_token_label {
11891206
diag.span_label(unexpected_token_label, fluent::parse_label_unexpected_token);
@@ -1925,6 +1942,12 @@ pub(crate) enum UnexpectedTokenAfterStructName {
19251942
span: Span,
19261943
token: Token,
19271944
},
1945+
#[diag(parse_unexpected_token_after_struct_name_found_metavar)]
1946+
MetaVar {
1947+
#[primary_span]
1948+
#[label(parse_unexpected_token_after_struct_name)]
1949+
span: Span,
1950+
},
19281951
#[diag(parse_unexpected_token_after_struct_name_found_other)]
19291952
Other {
19301953
#[primary_span]
@@ -1941,6 +1964,7 @@ impl UnexpectedTokenAfterStructName {
19411964
Some(TokenDescription::Keyword) => Self::Keyword { span, token },
19421965
Some(TokenDescription::ReservedKeyword) => Self::ReservedKeyword { span, token },
19431966
Some(TokenDescription::DocComment) => Self::DocComment { span, token },
1967+
Some(TokenDescription::MetaVar(_)) => Self::MetaVar { span },
19441968
None => Self::Other { span, token },
19451969
}
19461970
}

compiler/rustc_parse/src/parser/mod.rs

+26-15
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ pub(crate) use item::FnParseMode;
2121
pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma};
2222
use path::PathStyle;
2323
use rustc_ast::ptr::P;
24-
use rustc_ast::token::{self, Delimiter, IdentIsRaw, Nonterminal, Token, TokenKind};
24+
use rustc_ast::token::{
25+
self, Delimiter, IdentIsRaw, InvisibleOrigin, MetaVarKind, Nonterminal, Token, TokenKind,
26+
};
2527
use rustc_ast::tokenstream::{
2628
AttrsTarget, DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree, TokenTreeCursor,
2729
};
@@ -410,6 +412,12 @@ pub(super) enum TokenDescription {
410412
Keyword,
411413
ReservedKeyword,
412414
DocComment,
415+
416+
// Expanded metavariables are wrapped in invisible delimiters which aren't
417+
// pretty-printed. In error messages we must handle these specially
418+
// otherwise we get confusing things in messages like "expected `(`, found
419+
// ``". It's better to say e.g. "expected `(`, found type metavariable".
420+
MetaVar(MetaVarKind),
413421
}
414422

415423
impl TokenDescription {
@@ -419,26 +427,29 @@ impl TokenDescription {
419427
_ if token.is_used_keyword() => Some(TokenDescription::Keyword),
420428
_ if token.is_unused_keyword() => Some(TokenDescription::ReservedKeyword),
421429
token::DocComment(..) => Some(TokenDescription::DocComment),
430+
token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(kind))) => {
431+
Some(TokenDescription::MetaVar(kind))
432+
}
422433
_ => None,
423434
}
424435
}
425436
}
426437

427438
pub fn token_descr(token: &Token) -> String {
428-
let name = pprust::token_to_string(token).to_string();
429-
430-
let kind = match (TokenDescription::from_token(token), &token.kind) {
431-
(Some(TokenDescription::ReservedIdentifier), _) => Some("reserved identifier"),
432-
(Some(TokenDescription::Keyword), _) => Some("keyword"),
433-
(Some(TokenDescription::ReservedKeyword), _) => Some("reserved keyword"),
434-
(Some(TokenDescription::DocComment), _) => Some("doc comment"),
435-
(None, TokenKind::NtIdent(..)) => Some("identifier"),
436-
(None, TokenKind::NtLifetime(..)) => Some("lifetime"),
437-
(None, TokenKind::Interpolated(node)) => Some(node.descr()),
438-
(None, _) => None,
439-
};
440-
441-
if let Some(kind) = kind { format!("{kind} `{name}`") } else { format!("`{name}`") }
439+
let s = pprust::token_to_string(token).to_string();
440+
441+
match (TokenDescription::from_token(token), &token.kind) {
442+
(Some(TokenDescription::ReservedIdentifier), _) => format!("reserved identifier `{s}`"),
443+
(Some(TokenDescription::Keyword), _) => format!("keyword `{s}`"),
444+
(Some(TokenDescription::ReservedKeyword), _) => format!("reserved keyword `{s}`"),
445+
(Some(TokenDescription::DocComment), _) => format!("doc comment `{s}`"),
446+
// Deliberately doesn't print `s`, which is empty.
447+
(Some(TokenDescription::MetaVar(kind)), _) => format!("`{kind}` metavariable"),
448+
(None, TokenKind::NtIdent(..)) => format!("identifier `{s}`"),
449+
(None, TokenKind::NtLifetime(..)) => format!("lifetime `{s}`"),
450+
(None, TokenKind::Interpolated(node)) => format!("{} `{s}`", node.descr()),
451+
(None, _) => format!("`{s}`"),
452+
}
442453
}
443454

444455
impl<'a> Parser<'a> {

0 commit comments

Comments
 (0)