Skip to content

Commit

Permalink
Remove NtIdent and NtLifetime.
Browse files Browse the repository at this point in the history
The extra span is now recorded in the new `TokenKind::InterpolatedIdent` and
`TokenKind::InterpolatedLifetime`. These both consist of a single token, and so
there's no operator precedence problems with inserting them directly into the
token stream.

The other way to do this would be to wrap the ident/lifetime in invisible
delimiters, but there's a lot of code that assumes an interpolated
ident/lifetime fits in a single token, and changing all that code to work with
invisible delimiters would have been a pain. (Maybe it could be done in a
follow-up.)

This change might not seem like much of a win, but it's a first step toward the
much bigger and long-desired removal of `Nonterminal` and
`TokenKind::Interpolated`. That change is big and complex enough that it's
worth doing this piece separately. (Indeed, this commit is based on part of a
late commit in rust-lang#114647, a prior attempt at that big and complex change.)
  • Loading branch information
nnethercote committed Apr 22, 2024
1 parent 16ae355 commit beced67
Show file tree
Hide file tree
Showing 11 changed files with 171 additions and 112 deletions.
2 changes: 0 additions & 2 deletions compiler/rustc_ast/src/ast_traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,6 @@ impl HasTokens for Nonterminal {
Nonterminal::NtPath(path) => path.tokens(),
Nonterminal::NtVis(vis) => vis.tokens(),
Nonterminal::NtBlock(block) => block.tokens(),
Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None,
}
}
fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
Expand All @@ -254,7 +253,6 @@ impl HasTokens for Nonterminal {
Nonterminal::NtPath(path) => path.tokens_mut(),
Nonterminal::NtVis(vis) => vis.tokens_mut(),
Nonterminal::NtBlock(block) => block.tokens_mut(),
Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None,
}
}
}
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_ast/src/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,9 @@ pub fn visit_token<T: MutVisitor>(t: &mut Token, vis: &mut T) {
*span = ident.span;
return; // Avoid visiting the span for the second time.
}
token::InterpolatedIdent(ident, _) | token::InterpolatedLifetime(ident) => {
vis.visit_ident(ident);
}
token::Interpolated(nt) => {
let nt = Lrc::make_mut(nt);
visit_nonterminal(nt, vis);
Expand Down Expand Up @@ -834,8 +837,6 @@ pub fn visit_nonterminal<T: MutVisitor>(nt: &mut token::Nonterminal, vis: &mut T
token::NtPat(pat) => vis.visit_pat(pat),
token::NtExpr(expr) => vis.visit_expr(expr),
token::NtTy(ty) => vis.visit_ty(ty),
token::NtIdent(ident, _is_raw) => vis.visit_ident(ident),
token::NtLifetime(ident) => vis.visit_ident(ident),
token::NtLiteral(expr) => vis.visit_expr(expr),
token::NtMeta(item) => {
let AttrItem { path, args, tokens } = item.deref_mut();
Expand Down
121 changes: 71 additions & 50 deletions compiler/rustc_ast/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,15 +314,24 @@ pub enum TokenKind {
Literal(Lit),

/// Identifier token.
/// Do not forget about `NtIdent` when you want to match on identifiers.
/// Do not forget about `InterpolatedIdent` when you want to match on identifiers.
/// It's recommended to use `Token::(ident,uninterpolate,uninterpolated_span)` to
/// treat regular and interpolated identifiers in the same way.
Ident(Symbol, IdentIsRaw),
/// This identifier (and its span) is the identifier passed to the
/// declarative macro. The span in the surrounding `Token` is the span of
/// the `ident` metavariable in the macro's RHS.
InterpolatedIdent(Ident, IdentIsRaw),

/// Lifetime identifier token.
/// Do not forget about `NtLifetime` when you want to match on lifetime identifiers.
/// Do not forget about `InterpolatedLIfetime` when you want to match on lifetime identifiers.
/// It's recommended to use `Token::(lifetime,uninterpolate,uninterpolated_span)` to
/// treat regular and interpolated lifetime identifiers in the same way.
Lifetime(Symbol),
/// This identifier (and its span) is the lifetime passed to the
/// declarative macro. The span in the surrounding `Token` is the span of
/// the `lifetime` metavariable in the macro's RHS.
InterpolatedLifetime(Ident),

/// An embedded AST node, as produced by a macro. This only exists for
/// historical reasons. We'd like to get rid of it, for multiple reasons.
Expand Down Expand Up @@ -444,8 +453,9 @@ impl Token {
/// Note that keywords are also identifiers, so they should use this
/// if they keep spans or perform edition checks.
pub fn uninterpolated_span(&self) -> Span {
match &self.kind {
Interpolated(nt) => nt.use_span(),
match self.kind {
InterpolatedIdent(ident, _) | InterpolatedLifetime(ident) => ident.span,
Interpolated(ref nt) => nt.use_span(),
_ => self.span,
}
}
Expand All @@ -462,8 +472,16 @@ impl Token {
true
}

OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..)
| Lifetime(..) | Interpolated(..) | Eof => false,
OpenDelim(..)
| CloseDelim(..)
| Literal(..)
| DocComment(..)
| Ident(..)
| InterpolatedIdent(..)
| Lifetime(..)
| InterpolatedLifetime(..)
| Interpolated(..)
| Eof => false,
}
}

Expand Down Expand Up @@ -613,14 +631,11 @@ impl Token {
/// into the regular identifier or lifetime token it refers to,
/// otherwise returns the original token.
pub fn uninterpolate(&self) -> Cow<'_, Token> {
match &self.kind {
Interpolated(nt) => match &**nt {
NtIdent(ident, is_raw) => {
Cow::Owned(Token::new(Ident(ident.name, *is_raw), ident.span))
}
NtLifetime(ident) => Cow::Owned(Token::new(Lifetime(ident.name), ident.span)),
_ => Cow::Borrowed(self),
},
match self.kind {
InterpolatedIdent(ident, is_raw) => {
Cow::Owned(Token::new(Ident(ident.name, is_raw), ident.span))
}
InterpolatedLifetime(ident) => Cow::Owned(Token::new(Lifetime(ident.name), ident.span)),
_ => Cow::Borrowed(self),
}
}
Expand All @@ -629,12 +644,9 @@ impl Token {
#[inline]
pub fn ident(&self) -> Option<(Ident, IdentIsRaw)> {
// We avoid using `Token::uninterpolate` here because it's slow.
match &self.kind {
&Ident(name, is_raw) => Some((Ident::new(name, self.span), is_raw)),
Interpolated(nt) => match &**nt {
NtIdent(ident, is_raw) => Some((*ident, *is_raw)),
_ => None,
},
match self.kind {
Ident(name, is_raw) => Some((Ident::new(name, self.span), is_raw)),
InterpolatedIdent(ident, is_raw) => Some((ident, is_raw)),
_ => None,
}
}
Expand All @@ -643,12 +655,9 @@ impl Token {
#[inline]
pub fn lifetime(&self) -> Option<Ident> {
// We avoid using `Token::uninterpolate` here because it's slow.
match &self.kind {
&Lifetime(name) => Some(Ident::new(name, self.span)),
Interpolated(nt) => match &**nt {
NtLifetime(ident) => Some(*ident),
_ => None,
},
match self.kind {
Lifetime(name) => Some(Ident::new(name, self.span)),
InterpolatedLifetime(ident) => Some(ident),
_ => None,
}
}
Expand Down Expand Up @@ -835,10 +844,36 @@ impl Token {
_ => return None,
},

Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot
| DotDotEq | Comma | Semi | PathSep | RArrow | LArrow | FatArrow | Pound | Dollar
| Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..)
| Lifetime(..) | Interpolated(..) | DocComment(..) | Eof => return None,
Le
| EqEq
| Ne
| Ge
| AndAnd
| OrOr
| Tilde
| BinOpEq(..)
| At
| DotDotDot
| DotDotEq
| Comma
| Semi
| PathSep
| RArrow
| LArrow
| FatArrow
| Pound
| Dollar
| Question
| OpenDelim(..)
| CloseDelim(..)
| Literal(..)
| Ident(..)
| InterpolatedIdent(..)
| Lifetime(..)
| InterpolatedLifetime(..)
| Interpolated(..)
| DocComment(..)
| Eof => return None,
};

Some(Token::new(kind, self.span.to(joint.span)))
Expand All @@ -861,9 +896,6 @@ pub enum Nonterminal {
NtPat(P<ast::Pat>),
NtExpr(P<ast::Expr>),
NtTy(P<ast::Ty>),
/// The span is for the identifier argument passed to the macro.
NtIdent(Ident, IdentIsRaw),
NtLifetime(Ident),
NtLiteral(P<ast::Expr>),
/// Stuff inside brackets for attributes
NtMeta(P<ast::AttrItem>),
Expand Down Expand Up @@ -958,7 +990,6 @@ impl Nonterminal {
NtPat(pat) => pat.span,
NtExpr(expr) | NtLiteral(expr) => expr.span,
NtTy(ty) => ty.span,
NtIdent(ident, _) | NtLifetime(ident) => ident.span,
NtMeta(attr_item) => attr_item.span(),
NtPath(path) => path.span,
NtVis(vis) => vis.span,
Expand All @@ -974,8 +1005,6 @@ impl Nonterminal {
NtExpr(..) => "expression",
NtLiteral(..) => "literal",
NtTy(..) => "type",
NtIdent(..) => "identifier",
NtLifetime(..) => "lifetime",
NtMeta(..) => "attribute",
NtPath(..) => "path",
NtVis(..) => "visibility",
Expand All @@ -984,18 +1013,12 @@ impl Nonterminal {
}

impl PartialEq for Nonterminal {
fn eq(&self, rhs: &Self) -> bool {
match (self, rhs) {
(NtIdent(ident_lhs, is_raw_lhs), NtIdent(ident_rhs, is_raw_rhs)) => {
ident_lhs == ident_rhs && is_raw_lhs == is_raw_rhs
}
(NtLifetime(ident_lhs), NtLifetime(ident_rhs)) => ident_lhs == ident_rhs,
// FIXME: Assume that all "complex" nonterminal are not equal, we can't compare them
// correctly based on data from AST. This will prevent them from matching each other
// in macros. The comparison will become possible only when each nonterminal has an
// attached token stream from which it was parsed.
_ => false,
}
fn eq(&self, _rhs: &Self) -> bool {
// FIXME: Assume that all nonterminals are not equal, we can't compare them
// correctly based on data from AST. This will prevent them from matching each other
// in macros. The comparison will become possible only when each nonterminal has an
// attached token stream from which it was parsed.
false
}
}

Expand All @@ -1008,12 +1031,10 @@ impl fmt::Debug for Nonterminal {
NtPat(..) => f.pad("NtPat(..)"),
NtExpr(..) => f.pad("NtExpr(..)"),
NtTy(..) => f.pad("NtTy(..)"),
NtIdent(..) => f.pad("NtIdent(..)"),
NtLiteral(..) => f.pad("NtLiteral(..)"),
NtMeta(..) => f.pad("NtMeta(..)"),
NtPath(..) => f.pad("NtPath(..)"),
NtVis(..) => f.pad("NtVis(..)"),
NtLifetime(..) => f.pad("NtLifetime(..)"),
}
}
}
Expand Down
27 changes: 16 additions & 11 deletions compiler/rustc_ast/src/tokenstream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -467,12 +467,6 @@ impl TokenStream {

pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream {
match nt {
Nonterminal::NtIdent(ident, is_raw) => {
TokenStream::token_alone(token::Ident(ident.name, *is_raw), ident.span)
}
Nonterminal::NtLifetime(ident) => {
TokenStream::token_alone(token::Lifetime(ident.name), ident.span)
}
Nonterminal::NtItem(item) => TokenStream::from_ast(item),
Nonterminal::NtBlock(block) => TokenStream::from_ast(block),
Nonterminal::NtStmt(stmt) if let StmtKind::Empty = stmt.kind => {
Expand All @@ -490,11 +484,17 @@ impl TokenStream {
}

fn flatten_token(token: &Token, spacing: Spacing) -> TokenTree {
match &token.kind {
token::Interpolated(nt) if let token::NtIdent(ident, is_raw) = &**nt => {
TokenTree::Token(Token::new(token::Ident(ident.name, *is_raw), ident.span), spacing)
match token.kind {
token::InterpolatedIdent(ident, is_raw) => {
TokenTree::Token(Token::new(token::Ident(ident.name, is_raw), ident.span), spacing)
}
token::Interpolated(nt) => TokenTree::Delimited(
token::InterpolatedLifetime(ident) => TokenTree::Delimited(
DelimSpan::from_single(token.span),
DelimSpacing::new(Spacing::JointHidden, spacing),
Delimiter::Invisible,
TokenStream::token_alone(token::Lifetime(ident.name), ident.span),
),
token::Interpolated(ref nt) => TokenTree::Delimited(
DelimSpan::from_single(token.span),
DelimSpacing::new(Spacing::JointHidden, spacing),
Delimiter::Invisible,
Expand All @@ -517,7 +517,12 @@ impl TokenStream {
pub fn flattened(&self) -> TokenStream {
fn can_skip(stream: &TokenStream) -> bool {
stream.trees().all(|tree| match tree {
TokenTree::Token(token, _) => !matches!(token.kind, token::Interpolated(_)),
TokenTree::Token(token, _) => !matches!(
token.kind,
token::InterpolatedIdent(..)
| token::InterpolatedLifetime(..)
| token::Interpolated(..)
),
TokenTree::Delimited(.., inner) => can_skip(inner),
})
}
Expand Down
14 changes: 9 additions & 5 deletions compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -852,8 +852,6 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
token::NtBlock(e) => self.block_to_string(e),
token::NtStmt(e) => self.stmt_to_string(e),
token::NtPat(e) => self.pat_to_string(e),
&token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(e, is_raw.into()).to_string(),
token::NtLifetime(e) => e.to_string(),
token::NtLiteral(e) => self.expr_to_string(e),
token::NtVis(e) => self.vis_to_string(e),
}
Expand Down Expand Up @@ -915,10 +913,16 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
token::Literal(lit) => literal_to_string(lit).into(),

/* Name components */
token::Ident(s, is_raw) => {
IdentPrinter::new(s, is_raw.into(), convert_dollar_crate).to_string().into()
token::Ident(name, is_raw) => {
IdentPrinter::new(name, is_raw.into(), convert_dollar_crate).to_string().into()
}
token::Lifetime(s) => s.to_string().into(),
token::InterpolatedIdent(ident, is_raw) => {
IdentPrinter::new(ident.name, is_raw.into(), convert_dollar_crate)
.to_string()
.into()
}
token::Lifetime(name) => name.to_string().into(),
token::InterpolatedLifetime(ident) => ident.name.to_string().into(),

/* Other */
token::DocComment(comment_kind, attr_style, data) => {
Expand Down
15 changes: 11 additions & 4 deletions compiler/rustc_expand/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,10 +199,17 @@ impl<'a> StripUnconfigured<'a> {
inner = self.configure_tokens(&inner);
Some(AttrTokenTree::Delimited(sp, spacing, delim, inner)).into_iter()
}
AttrTokenTree::Token(ref token, _)
if let TokenKind::Interpolated(nt) = &token.kind =>
{
panic!("Nonterminal should have been flattened at {:?}: {:?}", token.span, nt);
AttrTokenTree::Token(
Token {
kind:
TokenKind::InterpolatedIdent(..)
| TokenKind::InterpolatedLifetime(..)
| TokenKind::Interpolated(..),
..
},
_,
) => {
panic!("Nonterminal should have been flattened: {:?}", tree);
}
AttrTokenTree::Token(token, spacing) => {
Some(AttrTokenTree::Token(token, spacing)).into_iter()
Expand Down
13 changes: 10 additions & 3 deletions compiler/rustc_expand/src/mbe/transcribe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,10 +256,17 @@ pub(super) fn transcribe<'a>(
// without wrapping them into groups.
maybe_use_metavar_location(cx, &stack, sp, tt, &mut marker)
}
MatchedSingle(ParseNtResult::Ident(ident, is_raw)) => {
marker.visit_span(&mut sp);
let kind = token::InterpolatedIdent(*ident, *is_raw);
TokenTree::token_alone(kind, sp)
}
MatchedSingle(ParseNtResult::Lifetime(ident)) => {
marker.visit_span(&mut sp);
let kind = token::InterpolatedLifetime(*ident);
TokenTree::token_alone(kind, sp)
}
MatchedSingle(ParseNtResult::Nt(nt)) => {
// Other variables are emitted into the output stream as groups with
// `Delimiter::Invisible` to maintain parsing priorities.
// `Interpolated` is currently used for such groups in rustc parser.
marker.visit_span(&mut sp);
TokenTree::token_alone(token::Interpolated(nt.clone()), sp)
}
Expand Down
Loading

0 comments on commit beced67

Please sign in to comment.