Skip to content

Commit 5fb9b2d

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 e0420d9 commit 5fb9b2d

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
@@ -214,6 +214,9 @@ parse_expected_identifier_found_doc_comment = expected identifier, found doc com
214214
parse_expected_identifier_found_doc_comment_str = expected identifier, found doc comment `{$token}`
215215
parse_expected_identifier_found_keyword = expected identifier, found keyword
216216
parse_expected_identifier_found_keyword_str = expected identifier, found keyword `{$token}`
217+
parse_expected_identifier_found_metavar = expected identifier, found metavariable
218+
# This one deliberately doesn't print a token.
219+
parse_expected_identifier_found_metavar_str = expected identifier, found metavariable
217220
parse_expected_identifier_found_reserved_identifier = expected identifier, found reserved identifier
218221
parse_expected_identifier_found_reserved_identifier_str = expected identifier, found reserved identifier `{$token}`
219222
parse_expected_identifier_found_reserved_keyword = expected identifier, found reserved keyword
@@ -225,6 +228,8 @@ parse_expected_mut_or_const_in_raw_pointer_type = expected `mut` or `const` keyw
225228
226229
parse_expected_semi_found_doc_comment_str = expected `;`, found doc comment `{$token}`
227230
parse_expected_semi_found_keyword_str = expected `;`, found keyword `{$token}`
231+
# This one deliberately doesn't print a token.
232+
parse_expected_semi_found_metavar_str = expected `;`, found metavariable
228233
parse_expected_semi_found_reserved_identifier_str = expected `;`, found reserved identifier `{$token}`
229234
parse_expected_semi_found_reserved_keyword_str = expected `;`, found reserved keyword `{$token}`
230235
parse_expected_semi_found_str = expected `;`, found `{$token}`
@@ -862,6 +867,8 @@ parse_unexpected_token_after_not_logical = use `!` to perform logical negation
862867
parse_unexpected_token_after_struct_name = expected `where`, `{"{"}`, `(`, or `;` after struct name
863868
parse_unexpected_token_after_struct_name_found_doc_comment = expected `where`, `{"{"}`, `(`, or `;` after struct name, found doc comment `{$token}`
864869
parse_unexpected_token_after_struct_name_found_keyword = expected `where`, `{"{"}`, `(`, or `;` after struct name, found keyword `{$token}`
870+
# This one deliberately doesn't print a token.
871+
parse_unexpected_token_after_struct_name_found_metavar = expected `where`, `{"{"}`, `(`, or `;` after struct name, found metavar
865872
parse_unexpected_token_after_struct_name_found_other = expected `where`, `{"{"}`, `(`, or `;` after struct name, found `{$token}`
866873
867874
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
@@ -1085,6 +1085,8 @@ pub(crate) enum ExpectedIdentifierFound {
10851085
ReservedKeyword(#[primary_span] Span),
10861086
#[label(parse_expected_identifier_found_doc_comment)]
10871087
DocComment(#[primary_span] Span),
1088+
#[label(parse_expected_identifier_found_metavar)]
1089+
MetaVar(#[primary_span] Span),
10881090
#[label(parse_expected_identifier)]
10891091
Other(#[primary_span] Span),
10901092
}
@@ -1098,6 +1100,7 @@ impl ExpectedIdentifierFound {
10981100
Some(TokenDescription::Keyword) => ExpectedIdentifierFound::Keyword,
10991101
Some(TokenDescription::ReservedKeyword) => ExpectedIdentifierFound::ReservedKeyword,
11001102
Some(TokenDescription::DocComment) => ExpectedIdentifierFound::DocComment,
1103+
Some(TokenDescription::MetaVar(_)) => ExpectedIdentifierFound::MetaVar,
11011104
None => ExpectedIdentifierFound::Other,
11021105
})(span)
11031106
}
@@ -1116,6 +1119,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedIdentifier {
11161119
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
11171120
let token_descr = TokenDescription::from_token(&self.token);
11181121

1122+
let mut add_token = true;
11191123
let mut diag = Diag::new(dcx, level, match token_descr {
11201124
Some(TokenDescription::ReservedIdentifier) => {
11211125
fluent::parse_expected_identifier_found_reserved_identifier_str
@@ -1127,10 +1131,16 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedIdentifier {
11271131
Some(TokenDescription::DocComment) => {
11281132
fluent::parse_expected_identifier_found_doc_comment_str
11291133
}
1134+
Some(TokenDescription::MetaVar(_)) => {
1135+
add_token = false;
1136+
fluent::parse_expected_identifier_found_metavar_str
1137+
}
11301138
None => fluent::parse_expected_identifier_found_str,
11311139
});
11321140
diag.span(self.span);
1133-
diag.arg("token", self.token);
1141+
if add_token {
1142+
diag.arg("token", self.token);
1143+
}
11341144

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

1183+
let mut add_token = true;
11731184
let mut diag = Diag::new(dcx, level, match token_descr {
11741185
Some(TokenDescription::ReservedIdentifier) => {
11751186
fluent::parse_expected_semi_found_reserved_identifier_str
@@ -1179,10 +1190,16 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedSemi {
11791190
fluent::parse_expected_semi_found_reserved_keyword_str
11801191
}
11811192
Some(TokenDescription::DocComment) => fluent::parse_expected_semi_found_doc_comment_str,
1193+
Some(TokenDescription::MetaVar(_)) => {
1194+
add_token = false;
1195+
fluent::parse_expected_semi_found_metavar_str
1196+
}
11821197
None => fluent::parse_expected_semi_found_str,
11831198
});
11841199
diag.span(self.span);
1185-
diag.arg("token", self.token);
1200+
if add_token {
1201+
diag.arg("token", self.token);
1202+
}
11861203

11871204
if let Some(unexpected_token_label) = self.unexpected_token_label {
11881205
diag.span_label(unexpected_token_label, fluent::parse_label_unexpected_token);
@@ -1924,6 +1941,12 @@ pub(crate) enum UnexpectedTokenAfterStructName {
19241941
span: Span,
19251942
token: Token,
19261943
},
1944+
#[diag(parse_unexpected_token_after_struct_name_found_metavar)]
1945+
MetaVar {
1946+
#[primary_span]
1947+
#[label(parse_unexpected_token_after_struct_name)]
1948+
span: Span,
1949+
},
19271950
#[diag(parse_unexpected_token_after_struct_name_found_other)]
19281951
Other {
19291952
#[primary_span]
@@ -1940,6 +1963,7 @@ impl UnexpectedTokenAfterStructName {
19401963
Some(TokenDescription::Keyword) => Self::Keyword { span, token },
19411964
Some(TokenDescription::ReservedKeyword) => Self::ReservedKeyword { span, token },
19421965
Some(TokenDescription::DocComment) => Self::DocComment { span, token },
1966+
Some(TokenDescription::MetaVar(_)) => Self::MetaVar { span },
19431967
None => Self::Other { span, token },
19441968
}
19451969
}

compiler/rustc_parse/src/parser/mod.rs

Lines changed: 28 additions & 15 deletions
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,31 @@ 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+
use TokenDescription::*;
440+
441+
let s = pprust::token_to_string(token).to_string();
442+
443+
match (TokenDescription::from_token(token), &token.kind) {
444+
(Some(ReservedIdentifier), _) => format!("reserved identifier `{s}`"),
445+
(Some(Keyword), _) => format!("keyword `{s}`"),
446+
(Some(ReservedKeyword), _) => format!("reserved keyword `{s}`"),
447+
(Some(DocComment), _) => format!("doc comment `{s}`"),
448+
// Deliberately doesn't print `s`, which is empty.
449+
(Some(MetaVar(kind)), _) => format!("`{kind}` metavariable"),
450+
(None, TokenKind::NtIdent(..)) => format!("identifier `{s}`"),
451+
(None, TokenKind::NtLifetime(..)) => format!("lifetime `{s}`"),
452+
(None, TokenKind::Interpolated(node)) => format!("{} `{s}`", node.descr()),
453+
(None, _) => format!("`{s}`"),
454+
}
442455
}
443456

444457
impl<'a> Parser<'a> {

0 commit comments

Comments
 (0)