Skip to content

#124141 preliminaries #132629

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions compiler/rustc_ast/src/attr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ impl MetaItemKind {
tokens: &mut impl Iterator<Item = &'a TokenTree>,
) -> Option<MetaItemKind> {
match tokens.next() {
Some(TokenTree::Delimited(.., Delimiter::Invisible, inner_tokens)) => {
Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => {
MetaItemKind::name_value_from_tokens(&mut inner_tokens.trees())
}
Some(TokenTree::Token(token, _)) => {
Expand Down Expand Up @@ -605,7 +605,7 @@ impl MetaItemInner {
tokens.next();
return Some(MetaItemInner::Lit(lit));
}
Some(TokenTree::Delimited(.., Delimiter::Invisible, inner_tokens)) => {
Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => {
tokens.next();
return MetaItemInner::from_tokens(&mut inner_tokens.trees().peekable());
}
Expand Down
152 changes: 144 additions & 8 deletions compiler/rustc_ast/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,86 @@ pub enum BinOpToken {
Shr,
}

// This type must not implement `Hash` due to the unusual `PartialEq` impl below.
#[derive(Copy, Clone, Debug, Encodable, Decodable, HashStable_Generic)]
pub enum InvisibleOrigin {
// From the expansion of a metavariable in a declarative macro.
MetaVar(MetaVarKind),

// Converted from `proc_macro::Delimiter` in
// `proc_macro::Delimiter::to_internal`, i.e. returned by a proc macro.
ProcMacro,

// Converted from `TokenKind::Interpolated` in
// `TokenStream::flatten_token`. Treated similarly to `ProcMacro`.
FlattenToken,
}

impl PartialEq for InvisibleOrigin {
#[inline]
fn eq(&self, _other: &InvisibleOrigin) -> bool {
// When we had AST-based nonterminals we couldn't compare them, and the
// old `Nonterminal` type had an `eq` that always returned false,
// resulting in this restriction:
// https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment
// This `eq` emulates that behaviour. We could consider lifting this
// restriction now but there are still cases involving invisible
// delimiters that make it harder than it first appears.
false
}
}

/// Annoyingly similar to `NonterminalKind`, but the slight differences are important.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
pub enum MetaVarKind {
Item,
Block,
Stmt,
Pat(NtPatKind),
Expr {
kind: NtExprKind,
// This field is needed for `Token::can_begin_literal_maybe_minus`.
can_begin_literal_maybe_minus: bool,
// This field is needed for `Token::can_begin_string_literal`.
can_begin_string_literal: bool,
},
Ty,
Ident,
Lifetime,
Literal,
Meta,
Path,
Vis,
TT,
}

impl fmt::Display for MetaVarKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let sym = match self {
MetaVarKind::Item => sym::item,
MetaVarKind::Block => sym::block,
MetaVarKind::Stmt => sym::stmt,
MetaVarKind::Pat(PatParam { inferred: true } | PatWithOr) => sym::pat,
MetaVarKind::Pat(PatParam { inferred: false }) => sym::pat_param,
MetaVarKind::Expr { kind: Expr2021 { inferred: true } | Expr, .. } => sym::expr,
MetaVarKind::Expr { kind: Expr2021 { inferred: false }, .. } => sym::expr_2021,
MetaVarKind::Ty => sym::ty,
MetaVarKind::Ident => sym::ident,
MetaVarKind::Lifetime => sym::lifetime,
MetaVarKind::Literal => sym::literal,
MetaVarKind::Meta => sym::meta,
MetaVarKind::Path => sym::path,
MetaVarKind::Vis => sym::vis,
MetaVarKind::TT => sym::tt,
};
write!(f, "{sym}")
}
}

/// Describes how a sequence of token trees is delimited.
/// Cannot use `proc_macro::Delimiter` directly because this
/// structure should implement some additional traits.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[derive(Encodable, Decodable, Hash, HashStable_Generic)]
#[derive(Copy, Clone, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
pub enum Delimiter {
/// `( ... )`
Parenthesis,
Expand All @@ -59,7 +134,34 @@ pub enum Delimiter {
/// "macro variable" `$var`. It is important to preserve operator priorities in cases like
/// `$var * 3` where `$var` is `1 + 2`.
/// Invisible delimiters might not survive roundtrip of a token stream through a string.
Invisible,
Invisible(InvisibleOrigin),
}

impl Delimiter {
// Should the parser skip these delimiters? Only happens for certain kinds
// of invisible delimiters. Ideally this function will eventually disappear
// and no invisible delimiters will be skipped.
#[inline]
pub fn skip(&self) -> bool {
match self {
Delimiter::Parenthesis | Delimiter::Bracket | Delimiter::Brace => false,
Delimiter::Invisible(InvisibleOrigin::MetaVar(_)) => false,
Delimiter::Invisible(InvisibleOrigin::FlattenToken | InvisibleOrigin::ProcMacro) => {
true
}
}
}

// This exists because `InvisibleOrigin`s should be compared. It is only used for assertions.
pub fn eq_ignoring_invisible_origin(&self, other: &Delimiter) -> bool {
match (self, other) {
(Delimiter::Parenthesis, Delimiter::Parenthesis) => true,
(Delimiter::Brace, Delimiter::Brace) => true,
(Delimiter::Bracket, Delimiter::Bracket) => true,
(Delimiter::Invisible(_), Delimiter::Invisible(_)) => true,
_ => false,
}
}
}

// Note that the suffix is *not* considered when deciding the `LitKind` in this
Expand Down Expand Up @@ -496,10 +598,11 @@ impl Token {
/// **NB**: Take care when modifying this function, since it will change
/// the stable set of tokens that are allowed to match an expr nonterminal.
pub fn can_begin_expr(&self) -> bool {
use Delimiter::*;
match self.uninterpolate().kind {
Ident(name, is_raw) =>
ident_can_begin_expr(name, self.span, is_raw), // value name or keyword
OpenDelim(..) | // tuple, array or block
OpenDelim(Parenthesis | Brace | Bracket) | // tuple, array or block
Literal(..) | // literal
Not | // operator not
BinOp(Minus) | // unary minus
Expand All @@ -510,7 +613,7 @@ impl Token {
// DotDotDot is no longer supported, but we need some way to display the error
DotDot | DotDotDot | DotDotEq | // range notation
Lt | BinOp(Shl) | // associated path
PathSep | // global path
PathSep | // global path
Lifetime(..) | // labeled loop
Pound => true, // expression attributes
Interpolated(ref nt) =>
Expand All @@ -520,6 +623,12 @@ impl Token {
NtLiteral(..) |
NtPath(..)
),
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
MetaVarKind::Block |
MetaVarKind::Expr { .. } |
MetaVarKind::Literal |
MetaVarKind::Path
))) => true,
_ => false,
}
}
Expand Down Expand Up @@ -553,6 +662,14 @@ impl Token {
| NtPath(..)
| NtTy(..)
),
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
MetaVarKind::Expr { .. } |
MetaVarKind::Literal |
MetaVarKind::Meta |
MetaVarKind::Pat(_) |
MetaVarKind::Path |
MetaVarKind::Ty
))) => true,
_ => false,
}
}
Expand All @@ -573,6 +690,10 @@ impl Token {
Lt | BinOp(Shl) | // associated path
PathSep => true, // global path
Interpolated(ref nt) => matches!(&**nt, NtTy(..) | NtPath(..)),
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
MetaVarKind::Ty |
MetaVarKind::Path
))) => true,
// For anonymous structs or unions, which only appear in specific positions
// (type of struct fields or union fields), we don't consider them as regular types
_ => false,
Expand All @@ -585,6 +706,9 @@ impl Token {
OpenDelim(Delimiter::Brace) | Literal(..) | BinOp(Minus) => true,
Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true,
Interpolated(ref nt) => matches!(&**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)),
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
MetaVarKind::Expr { .. } | MetaVarKind::Block | MetaVarKind::Literal,
))) => true,
_ => false,
}
}
Expand Down Expand Up @@ -641,6 +765,13 @@ impl Token {
},
_ => false,
},
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind))) => match mv_kind {
MetaVarKind::Literal => true,
MetaVarKind::Expr { can_begin_literal_maybe_minus, .. } => {
can_begin_literal_maybe_minus
}
_ => false,
},
_ => false,
}
}
Expand All @@ -656,6 +787,11 @@ impl Token {
},
_ => false,
},
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind))) => match mv_kind {
MetaVarKind::Literal => true,
MetaVarKind::Expr { can_begin_string_literal, .. } => can_begin_string_literal,
_ => false,
},
_ => false,
}
}
Expand Down Expand Up @@ -896,7 +1032,7 @@ impl PartialEq<TokenKind> for Token {
}
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
pub enum NtPatKind {
// Matches or-patterns. Was written using `pat` in edition 2021 or later.
PatWithOr,
Expand All @@ -906,7 +1042,7 @@ pub enum NtPatKind {
PatParam { inferred: bool },
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
pub enum NtExprKind {
// Matches expressions using the post-edition 2024. Was written using
// `expr` in edition 2024 or later.
Expand All @@ -933,7 +1069,7 @@ pub enum Nonterminal {
NtVis(P<ast::Visibility>),
}

#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
pub enum NonterminalKind {
Item,
Block,
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_ast/src/tokenstream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use rustc_span::{DUMMY_SP, Span, SpanDecoder, SpanEncoder, Symbol, sym};

use crate::ast::{AttrStyle, StmtKind};
use crate::ast_traits::{HasAttrs, HasTokens};
use crate::token::{self, Delimiter, Nonterminal, Token, TokenKind};
use crate::token::{self, Delimiter, InvisibleOrigin, Nonterminal, Token, TokenKind};
use crate::{AttrVec, Attribute};

/// Part of a `TokenStream`.
Expand Down Expand Up @@ -484,13 +484,13 @@ impl TokenStream {
token::NtLifetime(ident, is_raw) => TokenTree::Delimited(
DelimSpan::from_single(token.span),
DelimSpacing::new(Spacing::JointHidden, spacing),
Delimiter::Invisible,
Delimiter::Invisible(InvisibleOrigin::FlattenToken),
TokenStream::token_alone(token::Lifetime(ident.name, is_raw), ident.span),
),
token::Interpolated(ref nt) => TokenTree::Delimited(
DelimSpan::from_single(token.span),
DelimSpacing::new(Spacing::JointHidden, spacing),
Delimiter::Invisible,
Delimiter::Invisible(InvisibleOrigin::FlattenToken),
TokenStream::from_nonterminal_ast(&nt).flattened(),
),
_ => TokenTree::Token(token.clone(), spacing),
Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -942,9 +942,8 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
token::CloseDelim(Delimiter::Bracket) => "]".into(),
token::OpenDelim(Delimiter::Brace) => "{".into(),
token::CloseDelim(Delimiter::Brace) => "}".into(),
token::OpenDelim(Delimiter::Invisible) | token::CloseDelim(Delimiter::Invisible) => {
"".into()
}
token::OpenDelim(Delimiter::Invisible(_))
| token::CloseDelim(Delimiter::Invisible(_)) => "".into(),
token::Pound => "#".into(),
token::Dollar => "$".into(),
token::Question => "?".into(),
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_expand/src/mbe/diagnostics.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::borrow::Cow;

use rustc_ast::token::{self, Token, TokenKind};
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
use rustc_ast::tokenstream::TokenStream;
use rustc_errors::{Applicability, Diag, DiagCtxtHandle, DiagMessage};
use rustc_macros::Subdiagnostic;
Expand Down Expand Up @@ -68,7 +68,9 @@ pub(super) fn failed_to_match_macro(

if let MatcherLoc::Token { token: expected_token } = &remaining_matcher
&& (matches!(expected_token.kind, TokenKind::Interpolated(_))
|| matches!(token.kind, TokenKind::Interpolated(_)))
|| matches!(token.kind, TokenKind::Interpolated(_))
|| matches!(expected_token.kind, TokenKind::OpenDelim(Delimiter::Invisible(_)))
|| matches!(token.kind, TokenKind::OpenDelim(Delimiter::Invisible(_))))
{
err.note("captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens");
err.note("see <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> for more information");
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_expand/src/mbe/macro_rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -693,7 +693,7 @@ fn has_compile_error_macro(rhs: &mbe::TokenTree) -> bool {
&& let mbe::TokenTree::Token(bang) = bang
&& let TokenKind::Not = bang.kind
&& let mbe::TokenTree::Delimited(.., del) = args
&& del.delim != Delimiter::Invisible
&& !del.delim.skip()
{
true
} else {
Expand Down
11 changes: 6 additions & 5 deletions compiler/rustc_expand/src/mbe/quoted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,12 @@ fn parse_tree<'a>(
// during parsing.
let mut next = outer_trees.next();
let mut trees: Box<dyn Iterator<Item = &tokenstream::TokenTree>>;
if let Some(tokenstream::TokenTree::Delimited(.., Delimiter::Invisible, tts)) = next {
trees = Box::new(tts.trees());
next = trees.next();
} else {
trees = Box::new(outer_trees);
match next {
Some(tokenstream::TokenTree::Delimited(.., delim, tts)) if delim.skip() => {
trees = Box::new(tts.trees());
next = trees.next();
}
_ => trees = Box::new(outer_trees),
}

match next {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_expand/src/proc_macro_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ impl FromInternal<token::Delimiter> for Delimiter {
token::Delimiter::Parenthesis => Delimiter::Parenthesis,
token::Delimiter::Brace => Delimiter::Brace,
token::Delimiter::Bracket => Delimiter::Bracket,
token::Delimiter::Invisible => Delimiter::None,
token::Delimiter::Invisible(_) => Delimiter::None,
}
}
}
Expand All @@ -49,7 +49,7 @@ impl ToInternal<token::Delimiter> for Delimiter {
Delimiter::Parenthesis => token::Delimiter::Parenthesis,
Delimiter::Brace => token::Delimiter::Brace,
Delimiter::Bracket => token::Delimiter::Bracket,
Delimiter::None => token::Delimiter::Invisible,
Delimiter::None => token::Delimiter::Invisible(token::InvisibleOrigin::ProcMacro),
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_parse/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,9 @@ parse_expected_identifier_found_doc_comment = expected identifier, found doc com
parse_expected_identifier_found_doc_comment_str = expected identifier, found doc comment `{$token}`
parse_expected_identifier_found_keyword = expected identifier, found keyword
parse_expected_identifier_found_keyword_str = expected identifier, found keyword `{$token}`
parse_expected_identifier_found_metavar = expected identifier, found metavariable
# This one deliberately doesn't print a token.
parse_expected_identifier_found_metavar_str = expected identifier, found metavariable
parse_expected_identifier_found_reserved_identifier = expected identifier, found reserved identifier
parse_expected_identifier_found_reserved_identifier_str = expected identifier, found reserved identifier `{$token}`
parse_expected_identifier_found_reserved_keyword = expected identifier, found reserved keyword
Expand All @@ -227,6 +230,8 @@ parse_expected_mut_or_const_in_raw_pointer_type = expected `mut` or `const` keyw

parse_expected_semi_found_doc_comment_str = expected `;`, found doc comment `{$token}`
parse_expected_semi_found_keyword_str = expected `;`, found keyword `{$token}`
# This one deliberately doesn't print a token.
parse_expected_semi_found_metavar_str = expected `;`, found metavariable
parse_expected_semi_found_reserved_identifier_str = expected `;`, found reserved identifier `{$token}`
parse_expected_semi_found_reserved_keyword_str = expected `;`, found reserved keyword `{$token}`
parse_expected_semi_found_str = expected `;`, found `{$token}`
Expand Down Expand Up @@ -864,6 +869,8 @@ parse_unexpected_token_after_not_logical = use `!` to perform logical negation
parse_unexpected_token_after_struct_name = expected `where`, `{"{"}`, `(`, or `;` after struct name
parse_unexpected_token_after_struct_name_found_doc_comment = expected `where`, `{"{"}`, `(`, or `;` after struct name, found doc comment `{$token}`
parse_unexpected_token_after_struct_name_found_keyword = expected `where`, `{"{"}`, `(`, or `;` after struct name, found keyword `{$token}`
# This one deliberately doesn't print a token.
parse_unexpected_token_after_struct_name_found_metavar = expected `where`, `{"{"}`, `(`, or `;` after struct name, found metavar
parse_unexpected_token_after_struct_name_found_other = expected `where`, `{"{"}`, `(`, or `;` after struct name, found `{$token}`

parse_unexpected_token_after_struct_name_found_reserved_identifier = expected `where`, `{"{"}`, `(`, or `;` after struct name, found reserved identifier `{$token}`
Expand Down
Loading
Loading