Auto merge of #124256 - nnethercote:rm-NtIdent-NtLifetime, r=petrochenkov
Remove `NtIdent` and `NtLifetime` This is one part of the bigger "remove `Nonterminal` and `TokenKind::Interpolated`" change drafted in #114647. More details in the individual commit messages. r? `@petrochenkov`
This commit is contained in:
commit
9105c57b7f
22 changed files with 182 additions and 190 deletions
|
@ -240,7 +240,6 @@ impl HasTokens for Nonterminal {
|
||||||
Nonterminal::NtPath(path) => path.tokens(),
|
Nonterminal::NtPath(path) => path.tokens(),
|
||||||
Nonterminal::NtVis(vis) => vis.tokens(),
|
Nonterminal::NtVis(vis) => vis.tokens(),
|
||||||
Nonterminal::NtBlock(block) => block.tokens(),
|
Nonterminal::NtBlock(block) => block.tokens(),
|
||||||
Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
|
fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
|
||||||
|
@ -254,7 +253,6 @@ impl HasTokens for Nonterminal {
|
||||||
Nonterminal::NtPath(path) => path.tokens_mut(),
|
Nonterminal::NtPath(path) => path.tokens_mut(),
|
||||||
Nonterminal::NtVis(vis) => vis.tokens_mut(),
|
Nonterminal::NtVis(vis) => vis.tokens_mut(),
|
||||||
Nonterminal::NtBlock(block) => block.tokens_mut(),
|
Nonterminal::NtBlock(block) => block.tokens_mut(),
|
||||||
Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -345,7 +345,7 @@ impl MetaItem {
|
||||||
let span = span.with_hi(segments.last().unwrap().ident.span.hi());
|
let span = span.with_hi(segments.last().unwrap().ident.span.hi());
|
||||||
Path { span, segments, tokens: None }
|
Path { span, segments, tokens: None }
|
||||||
}
|
}
|
||||||
Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. }, _)) => match &nt.0 {
|
Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. }, _)) => match &**nt {
|
||||||
token::Nonterminal::NtMeta(item) => return item.meta(item.path.span),
|
token::Nonterminal::NtMeta(item) => return item.meta(item.path.span),
|
||||||
token::Nonterminal::NtPath(path) => (**path).clone(),
|
token::Nonterminal::NtPath(path) => (**path).clone(),
|
||||||
_ => return None,
|
_ => return None,
|
||||||
|
|
|
@ -781,10 +781,14 @@ pub fn visit_token<T: MutVisitor>(t: &mut Token, vis: &mut T) {
|
||||||
*span = ident.span;
|
*span = ident.span;
|
||||||
return; // Avoid visiting the span for the second time.
|
return; // Avoid visiting the span for the second time.
|
||||||
}
|
}
|
||||||
|
token::NtIdent(ident, _is_raw) => {
|
||||||
|
vis.visit_ident(ident);
|
||||||
|
}
|
||||||
|
token::NtLifetime(ident) => {
|
||||||
|
vis.visit_ident(ident);
|
||||||
|
}
|
||||||
token::Interpolated(nt) => {
|
token::Interpolated(nt) => {
|
||||||
let nt = Lrc::make_mut(nt);
|
let nt = Lrc::make_mut(nt);
|
||||||
let (nt, sp) = (&mut nt.0, &mut nt.1);
|
|
||||||
vis.visit_span(sp);
|
|
||||||
visit_nonterminal(nt, vis);
|
visit_nonterminal(nt, vis);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -834,8 +838,6 @@ fn visit_nonterminal<T: MutVisitor>(nt: &mut token::Nonterminal, vis: &mut T) {
|
||||||
token::NtPat(pat) => vis.visit_pat(pat),
|
token::NtPat(pat) => vis.visit_pat(pat),
|
||||||
token::NtExpr(expr) => vis.visit_expr(expr),
|
token::NtExpr(expr) => vis.visit_expr(expr),
|
||||||
token::NtTy(ty) => vis.visit_ty(ty),
|
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::NtLiteral(expr) => vis.visit_expr(expr),
|
||||||
token::NtMeta(item) => {
|
token::NtMeta(item) => {
|
||||||
let AttrItem { path, args, tokens } = item.deref_mut();
|
let AttrItem { path, args, tokens } = item.deref_mut();
|
||||||
|
|
|
@ -111,7 +111,7 @@ impl Lit {
|
||||||
Ident(name, IdentIsRaw::No) if name.is_bool_lit() => Some(Lit::new(Bool, name, None)),
|
Ident(name, IdentIsRaw::No) if name.is_bool_lit() => Some(Lit::new(Bool, name, None)),
|
||||||
Literal(token_lit) => Some(token_lit),
|
Literal(token_lit) => Some(token_lit),
|
||||||
Interpolated(ref nt)
|
Interpolated(ref nt)
|
||||||
if let NtExpr(expr) | NtLiteral(expr) = &nt.0
|
if let NtExpr(expr) | NtLiteral(expr) = &**nt
|
||||||
&& let ast::ExprKind::Lit(token_lit) = expr.kind =>
|
&& let ast::ExprKind::Lit(token_lit) = expr.kind =>
|
||||||
{
|
{
|
||||||
Some(token_lit)
|
Some(token_lit)
|
||||||
|
@ -318,11 +318,20 @@ pub enum TokenKind {
|
||||||
/// It's recommended to use `Token::(ident,uninterpolate,uninterpolated_span)` to
|
/// It's recommended to use `Token::(ident,uninterpolate,uninterpolated_span)` to
|
||||||
/// treat regular and interpolated identifiers in the same way.
|
/// treat regular and interpolated identifiers in the same way.
|
||||||
Ident(Symbol, IdentIsRaw),
|
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.
|
||||||
|
NtIdent(Ident, IdentIsRaw),
|
||||||
|
|
||||||
/// Lifetime identifier token.
|
/// Lifetime identifier token.
|
||||||
/// Do not forget about `NtLifetime` when you want to match on lifetime identifiers.
|
/// Do not forget about `NtLifetime` when you want to match on lifetime identifiers.
|
||||||
/// It's recommended to use `Token::(lifetime,uninterpolate,uninterpolated_span)` to
|
/// It's recommended to use `Token::(lifetime,uninterpolate,uninterpolated_span)` to
|
||||||
/// treat regular and interpolated lifetime identifiers in the same way.
|
/// treat regular and interpolated lifetime identifiers in the same way.
|
||||||
Lifetime(Symbol),
|
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.
|
||||||
|
NtLifetime(Ident),
|
||||||
|
|
||||||
/// An embedded AST node, as produced by a macro. This only exists for
|
/// 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.
|
/// historical reasons. We'd like to get rid of it, for multiple reasons.
|
||||||
|
@ -333,7 +342,11 @@ pub enum TokenKind {
|
||||||
/// - It prevents `Token` from implementing `Copy`.
|
/// - It prevents `Token` from implementing `Copy`.
|
||||||
/// It adds complexity and likely slows things down. Please don't add new
|
/// It adds complexity and likely slows things down. Please don't add new
|
||||||
/// occurrences of this token kind!
|
/// occurrences of this token kind!
|
||||||
Interpolated(Lrc<(Nonterminal, Span)>),
|
///
|
||||||
|
/// The span in the surrounding `Token` is that of the metavariable in the
|
||||||
|
/// macro's RHS. The span within the Nonterminal is that of the fragment
|
||||||
|
/// passed to the macro at the call site.
|
||||||
|
Interpolated(Lrc<Nonterminal>),
|
||||||
|
|
||||||
/// A doc comment token.
|
/// A doc comment token.
|
||||||
/// `Symbol` is the doc comment's data excluding its "quotes" (`///`, `/**`, etc)
|
/// `Symbol` is the doc comment's data excluding its "quotes" (`///`, `/**`, etc)
|
||||||
|
@ -440,8 +453,9 @@ impl Token {
|
||||||
/// Note that keywords are also identifiers, so they should use this
|
/// Note that keywords are also identifiers, so they should use this
|
||||||
/// if they keep spans or perform edition checks.
|
/// if they keep spans or perform edition checks.
|
||||||
pub fn uninterpolated_span(&self) -> Span {
|
pub fn uninterpolated_span(&self) -> Span {
|
||||||
match &self.kind {
|
match self.kind {
|
||||||
Interpolated(nt) => nt.0.use_span(),
|
NtIdent(ident, _) | NtLifetime(ident) => ident.span,
|
||||||
|
Interpolated(ref nt) => nt.use_span(),
|
||||||
_ => self.span,
|
_ => self.span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -459,7 +473,7 @@ impl Token {
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..)
|
OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..)
|
||||||
| Lifetime(..) | Interpolated(..) | Eof => false,
|
| NtIdent(..) | Lifetime(..) | NtLifetime(..) | Interpolated(..) | Eof => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -486,7 +500,7 @@ impl Token {
|
||||||
PathSep | // global path
|
PathSep | // global path
|
||||||
Lifetime(..) | // labeled loop
|
Lifetime(..) | // labeled loop
|
||||||
Pound => true, // expression attributes
|
Pound => true, // expression attributes
|
||||||
Interpolated(ref nt) => matches!(&nt.0, NtLiteral(..) |
|
Interpolated(ref nt) => matches!(&**nt, NtLiteral(..) |
|
||||||
NtExpr(..) |
|
NtExpr(..) |
|
||||||
NtBlock(..) |
|
NtBlock(..) |
|
||||||
NtPath(..)),
|
NtPath(..)),
|
||||||
|
@ -510,7 +524,7 @@ impl Token {
|
||||||
| DotDot | DotDotDot | DotDotEq // ranges
|
| DotDot | DotDotDot | DotDotEq // ranges
|
||||||
| Lt | BinOp(Shl) // associated path
|
| Lt | BinOp(Shl) // associated path
|
||||||
| PathSep => true, // global path
|
| PathSep => true, // global path
|
||||||
Interpolated(ref nt) => matches!(&nt.0, NtLiteral(..) |
|
Interpolated(ref nt) => matches!(&**nt, NtLiteral(..) |
|
||||||
NtPat(..) |
|
NtPat(..) |
|
||||||
NtBlock(..) |
|
NtBlock(..) |
|
||||||
NtPath(..)),
|
NtPath(..)),
|
||||||
|
@ -533,7 +547,7 @@ impl Token {
|
||||||
Lifetime(..) | // lifetime bound in trait object
|
Lifetime(..) | // lifetime bound in trait object
|
||||||
Lt | BinOp(Shl) | // associated path
|
Lt | BinOp(Shl) | // associated path
|
||||||
PathSep => true, // global path
|
PathSep => true, // global path
|
||||||
Interpolated(ref nt) => matches!(&nt.0, NtTy(..) | NtPath(..)),
|
Interpolated(ref nt) => matches!(&**nt, NtTy(..) | NtPath(..)),
|
||||||
// For anonymous structs or unions, which only appear in specific positions
|
// 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
|
// (type of struct fields or union fields), we don't consider them as regular types
|
||||||
_ => false,
|
_ => false,
|
||||||
|
@ -544,7 +558,7 @@ impl Token {
|
||||||
pub fn can_begin_const_arg(&self) -> bool {
|
pub fn can_begin_const_arg(&self) -> bool {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
OpenDelim(Delimiter::Brace) => true,
|
OpenDelim(Delimiter::Brace) => true,
|
||||||
Interpolated(ref nt) => matches!(&nt.0, NtExpr(..) | NtBlock(..) | NtLiteral(..)),
|
Interpolated(ref nt) => matches!(&**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)),
|
||||||
_ => self.can_begin_literal_maybe_minus(),
|
_ => self.can_begin_literal_maybe_minus(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -589,7 +603,7 @@ impl Token {
|
||||||
match self.uninterpolate().kind {
|
match self.uninterpolate().kind {
|
||||||
Literal(..) | BinOp(Minus) => true,
|
Literal(..) | BinOp(Minus) => true,
|
||||||
Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true,
|
Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true,
|
||||||
Interpolated(ref nt) => match &nt.0 {
|
Interpolated(ref nt) => match &**nt {
|
||||||
NtLiteral(_) => true,
|
NtLiteral(_) => true,
|
||||||
NtExpr(e) => match &e.kind {
|
NtExpr(e) => match &e.kind {
|
||||||
ast::ExprKind::Lit(_) => true,
|
ast::ExprKind::Lit(_) => true,
|
||||||
|
@ -609,15 +623,10 @@ impl Token {
|
||||||
/// into the regular identifier or lifetime token it refers to,
|
/// into the regular identifier or lifetime token it refers to,
|
||||||
/// otherwise returns the original token.
|
/// otherwise returns the original token.
|
||||||
pub fn uninterpolate(&self) -> Cow<'_, Token> {
|
pub fn uninterpolate(&self) -> Cow<'_, Token> {
|
||||||
match &self.kind {
|
match self.kind {
|
||||||
Interpolated(nt) => match &nt.0 {
|
NtIdent(ident, is_raw) => Cow::Owned(Token::new(Ident(ident.name, is_raw), ident.span)),
|
||||||
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)),
|
NtLifetime(ident) => Cow::Owned(Token::new(Lifetime(ident.name), ident.span)),
|
||||||
_ => Cow::Borrowed(self),
|
_ => Cow::Borrowed(self),
|
||||||
},
|
|
||||||
_ => Cow::Borrowed(self),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -625,12 +634,9 @@ impl Token {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn ident(&self) -> Option<(Ident, IdentIsRaw)> {
|
pub fn ident(&self) -> Option<(Ident, IdentIsRaw)> {
|
||||||
// We avoid using `Token::uninterpolate` here because it's slow.
|
// We avoid using `Token::uninterpolate` here because it's slow.
|
||||||
match &self.kind {
|
match self.kind {
|
||||||
&Ident(name, is_raw) => Some((Ident::new(name, self.span), is_raw)),
|
Ident(name, is_raw) => Some((Ident::new(name, self.span), is_raw)),
|
||||||
Interpolated(nt) => match &nt.0 {
|
NtIdent(ident, is_raw) => Some((ident, is_raw)),
|
||||||
NtIdent(ident, is_raw) => Some((*ident, *is_raw)),
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -639,12 +645,9 @@ impl Token {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn lifetime(&self) -> Option<Ident> {
|
pub fn lifetime(&self) -> Option<Ident> {
|
||||||
// We avoid using `Token::uninterpolate` here because it's slow.
|
// We avoid using `Token::uninterpolate` here because it's slow.
|
||||||
match &self.kind {
|
match self.kind {
|
||||||
&Lifetime(name) => Some(Ident::new(name, self.span)),
|
Lifetime(name) => Some(Ident::new(name, self.span)),
|
||||||
Interpolated(nt) => match &nt.0 {
|
NtLifetime(ident) => Some(ident),
|
||||||
NtLifetime(ident) => Some(*ident),
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -668,7 +671,7 @@ impl Token {
|
||||||
/// Returns `true` if the token is an interpolated path.
|
/// Returns `true` if the token is an interpolated path.
|
||||||
fn is_whole_path(&self) -> bool {
|
fn is_whole_path(&self) -> bool {
|
||||||
if let Interpolated(nt) = &self.kind
|
if let Interpolated(nt) = &self.kind
|
||||||
&& let NtPath(..) = &nt.0
|
&& let NtPath(..) = &**nt
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -681,7 +684,7 @@ impl Token {
|
||||||
/// (which happens while parsing the result of macro expansion)?
|
/// (which happens while parsing the result of macro expansion)?
|
||||||
pub fn is_whole_expr(&self) -> bool {
|
pub fn is_whole_expr(&self) -> bool {
|
||||||
if let Interpolated(nt) = &self.kind
|
if let Interpolated(nt) = &self.kind
|
||||||
&& let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtBlock(_) = &nt.0
|
&& let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtBlock(_) = &**nt
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -692,7 +695,7 @@ impl Token {
|
||||||
/// Is the token an interpolated block (`$b:block`)?
|
/// Is the token an interpolated block (`$b:block`)?
|
||||||
pub fn is_whole_block(&self) -> bool {
|
pub fn is_whole_block(&self) -> bool {
|
||||||
if let Interpolated(nt) = &self.kind
|
if let Interpolated(nt) = &self.kind
|
||||||
&& let NtBlock(..) = &nt.0
|
&& let NtBlock(..) = &**nt
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -833,8 +836,10 @@ impl Token {
|
||||||
|
|
||||||
Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot
|
Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot
|
||||||
| DotDotEq | Comma | Semi | PathSep | RArrow | LArrow | FatArrow | Pound | Dollar
|
| DotDotEq | Comma | Semi | PathSep | RArrow | LArrow | FatArrow | Pound | Dollar
|
||||||
| Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..)
|
| Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..) | NtIdent(..)
|
||||||
| Lifetime(..) | Interpolated(..) | DocComment(..) | Eof => return None,
|
| Lifetime(..) | NtLifetime(..) | Interpolated(..) | DocComment(..) | Eof => {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(Token::new(kind, self.span.to(joint.span)))
|
Some(Token::new(kind, self.span.to(joint.span)))
|
||||||
|
@ -857,8 +862,6 @@ pub enum Nonterminal {
|
||||||
NtPat(P<ast::Pat>),
|
NtPat(P<ast::Pat>),
|
||||||
NtExpr(P<ast::Expr>),
|
NtExpr(P<ast::Expr>),
|
||||||
NtTy(P<ast::Ty>),
|
NtTy(P<ast::Ty>),
|
||||||
NtIdent(Ident, IdentIsRaw),
|
|
||||||
NtLifetime(Ident),
|
|
||||||
NtLiteral(P<ast::Expr>),
|
NtLiteral(P<ast::Expr>),
|
||||||
/// Stuff inside brackets for attributes
|
/// Stuff inside brackets for attributes
|
||||||
NtMeta(P<ast::AttrItem>),
|
NtMeta(P<ast::AttrItem>),
|
||||||
|
@ -953,7 +956,6 @@ impl Nonterminal {
|
||||||
NtPat(pat) => pat.span,
|
NtPat(pat) => pat.span,
|
||||||
NtExpr(expr) | NtLiteral(expr) => expr.span,
|
NtExpr(expr) | NtLiteral(expr) => expr.span,
|
||||||
NtTy(ty) => ty.span,
|
NtTy(ty) => ty.span,
|
||||||
NtIdent(ident, _) | NtLifetime(ident) => ident.span,
|
|
||||||
NtMeta(attr_item) => attr_item.span(),
|
NtMeta(attr_item) => attr_item.span(),
|
||||||
NtPath(path) => path.span,
|
NtPath(path) => path.span,
|
||||||
NtVis(vis) => vis.span,
|
NtVis(vis) => vis.span,
|
||||||
|
@ -969,8 +971,6 @@ impl Nonterminal {
|
||||||
NtExpr(..) => "expression",
|
NtExpr(..) => "expression",
|
||||||
NtLiteral(..) => "literal",
|
NtLiteral(..) => "literal",
|
||||||
NtTy(..) => "type",
|
NtTy(..) => "type",
|
||||||
NtIdent(..) => "identifier",
|
|
||||||
NtLifetime(..) => "lifetime",
|
|
||||||
NtMeta(..) => "attribute",
|
NtMeta(..) => "attribute",
|
||||||
NtPath(..) => "path",
|
NtPath(..) => "path",
|
||||||
NtVis(..) => "visibility",
|
NtVis(..) => "visibility",
|
||||||
|
@ -979,18 +979,12 @@ impl Nonterminal {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for Nonterminal {
|
impl PartialEq for Nonterminal {
|
||||||
fn eq(&self, rhs: &Self) -> bool {
|
fn eq(&self, _rhs: &Self) -> bool {
|
||||||
match (self, rhs) {
|
// FIXME: Assume that all nonterminals are not equal, we can't compare them
|
||||||
(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
|
// 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
|
// in macros. The comparison will become possible only when each nonterminal has an
|
||||||
// attached token stream from which it was parsed.
|
// attached token stream from which it was parsed.
|
||||||
_ => false,
|
false
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1003,12 +997,10 @@ impl fmt::Debug for Nonterminal {
|
||||||
NtPat(..) => f.pad("NtPat(..)"),
|
NtPat(..) => f.pad("NtPat(..)"),
|
||||||
NtExpr(..) => f.pad("NtExpr(..)"),
|
NtExpr(..) => f.pad("NtExpr(..)"),
|
||||||
NtTy(..) => f.pad("NtTy(..)"),
|
NtTy(..) => f.pad("NtTy(..)"),
|
||||||
NtIdent(..) => f.pad("NtIdent(..)"),
|
|
||||||
NtLiteral(..) => f.pad("NtLiteral(..)"),
|
NtLiteral(..) => f.pad("NtLiteral(..)"),
|
||||||
NtMeta(..) => f.pad("NtMeta(..)"),
|
NtMeta(..) => f.pad("NtMeta(..)"),
|
||||||
NtPath(..) => f.pad("NtPath(..)"),
|
NtPath(..) => f.pad("NtPath(..)"),
|
||||||
NtVis(..) => f.pad("NtVis(..)"),
|
NtVis(..) => f.pad("NtVis(..)"),
|
||||||
NtLifetime(..) => f.pad("NtLifetime(..)"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -466,12 +466,6 @@ impl TokenStream {
|
||||||
|
|
||||||
pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream {
|
pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream {
|
||||||
match nt {
|
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::NtItem(item) => TokenStream::from_ast(item),
|
||||||
Nonterminal::NtBlock(block) => TokenStream::from_ast(block),
|
Nonterminal::NtBlock(block) => TokenStream::from_ast(block),
|
||||||
Nonterminal::NtStmt(stmt) if let StmtKind::Empty = stmt.kind => {
|
Nonterminal::NtStmt(stmt) if let StmtKind::Empty = stmt.kind => {
|
||||||
|
@ -489,15 +483,21 @@ impl TokenStream {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flatten_token(token: &Token, spacing: Spacing) -> TokenTree {
|
fn flatten_token(token: &Token, spacing: Spacing) -> TokenTree {
|
||||||
match &token.kind {
|
match token.kind {
|
||||||
token::Interpolated(nt) if let token::NtIdent(ident, is_raw) = nt.0 => {
|
token::NtIdent(ident, is_raw) => {
|
||||||
TokenTree::Token(Token::new(token::Ident(ident.name, is_raw), ident.span), spacing)
|
TokenTree::Token(Token::new(token::Ident(ident.name, is_raw), ident.span), spacing)
|
||||||
}
|
}
|
||||||
token::Interpolated(nt) => TokenTree::Delimited(
|
token::NtLifetime(ident) => TokenTree::Delimited(
|
||||||
DelimSpan::from_single(token.span),
|
DelimSpan::from_single(token.span),
|
||||||
DelimSpacing::new(Spacing::JointHidden, spacing),
|
DelimSpacing::new(Spacing::JointHidden, spacing),
|
||||||
Delimiter::Invisible,
|
Delimiter::Invisible,
|
||||||
TokenStream::from_nonterminal_ast(&nt.0).flattened(),
|
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,
|
||||||
|
TokenStream::from_nonterminal_ast(&nt).flattened(),
|
||||||
),
|
),
|
||||||
_ => TokenTree::Token(token.clone(), spacing),
|
_ => TokenTree::Token(token.clone(), spacing),
|
||||||
}
|
}
|
||||||
|
@ -516,7 +516,10 @@ impl TokenStream {
|
||||||
pub fn flattened(&self) -> TokenStream {
|
pub fn flattened(&self) -> TokenStream {
|
||||||
fn can_skip(stream: &TokenStream) -> bool {
|
fn can_skip(stream: &TokenStream) -> bool {
|
||||||
stream.trees().all(|tree| match tree {
|
stream.trees().all(|tree| match tree {
|
||||||
TokenTree::Token(token, _) => !matches!(token.kind, token::Interpolated(_)),
|
TokenTree::Token(token, _) => !matches!(
|
||||||
|
token.kind,
|
||||||
|
token::NtIdent(..) | token::NtLifetime(..) | token::Interpolated(..)
|
||||||
|
),
|
||||||
TokenTree::Delimited(.., inner) => can_skip(inner),
|
TokenTree::Delimited(.., inner) => can_skip(inner),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -858,8 +858,6 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
||||||
token::NtBlock(e) => self.block_to_string(e),
|
token::NtBlock(e) => self.block_to_string(e),
|
||||||
token::NtStmt(e) => self.stmt_to_string(e),
|
token::NtStmt(e) => self.stmt_to_string(e),
|
||||||
token::NtPat(e) => self.pat_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::NtLiteral(e) => self.expr_to_string(e),
|
||||||
token::NtVis(e) => self.vis_to_string(e),
|
token::NtVis(e) => self.vis_to_string(e),
|
||||||
}
|
}
|
||||||
|
@ -921,10 +919,14 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
||||||
token::Literal(lit) => literal_to_string(lit).into(),
|
token::Literal(lit) => literal_to_string(lit).into(),
|
||||||
|
|
||||||
/* Name components */
|
/* Name components */
|
||||||
token::Ident(s, is_raw) => {
|
token::Ident(name, is_raw) => {
|
||||||
IdentPrinter::new(s, is_raw.into(), convert_dollar_crate).to_string().into()
|
IdentPrinter::new(name, is_raw.into(), convert_dollar_crate).to_string().into()
|
||||||
}
|
}
|
||||||
token::Lifetime(s) => s.to_string().into(),
|
token::NtIdent(ident, is_raw) => {
|
||||||
|
IdentPrinter::for_ast_ident(ident, is_raw.into()).to_string().into()
|
||||||
|
}
|
||||||
|
token::Lifetime(name) => name.to_string().into(),
|
||||||
|
token::NtLifetime(ident) => ident.name.to_string().into(),
|
||||||
|
|
||||||
/* Other */
|
/* Other */
|
||||||
token::DocComment(comment_kind, attr_style, data) => {
|
token::DocComment(comment_kind, attr_style, data) => {
|
||||||
|
@ -932,7 +934,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
||||||
}
|
}
|
||||||
token::Eof => "<eof>".into(),
|
token::Eof => "<eof>".into(),
|
||||||
|
|
||||||
token::Interpolated(ref nt) => self.nonterminal_to_string(&nt.0).into(),
|
token::Interpolated(ref nt) => self.nonterminal_to_string(&nt).into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -201,10 +201,17 @@ impl<'a> StripUnconfigured<'a> {
|
||||||
inner = self.configure_tokens(&inner);
|
inner = self.configure_tokens(&inner);
|
||||||
Some(AttrTokenTree::Delimited(sp, spacing, delim, inner)).into_iter()
|
Some(AttrTokenTree::Delimited(sp, spacing, delim, inner)).into_iter()
|
||||||
}
|
}
|
||||||
AttrTokenTree::Token(ref token, _)
|
AttrTokenTree::Token(
|
||||||
if let TokenKind::Interpolated(nt) = &token.kind =>
|
Token {
|
||||||
{
|
kind:
|
||||||
panic!("Nonterminal should have been flattened at {:?}: {:?}", token.span, nt);
|
TokenKind::NtIdent(..)
|
||||||
|
| TokenKind::NtLifetime(..)
|
||||||
|
| TokenKind::Interpolated(..),
|
||||||
|
..
|
||||||
|
},
|
||||||
|
_,
|
||||||
|
) => {
|
||||||
|
panic!("Nonterminal should have been flattened: {:?}", tree);
|
||||||
}
|
}
|
||||||
AttrTokenTree::Token(token, spacing) => {
|
AttrTokenTree::Token(token, spacing) => {
|
||||||
Some(AttrTokenTree::Token(token, spacing)).into_iter()
|
Some(AttrTokenTree::Token(token, spacing)).into_iter()
|
||||||
|
|
|
@ -73,12 +73,6 @@ pub(super) fn failed_to_match_macro<'cx>(
|
||||||
&& (matches!(expected_token.kind, TokenKind::Interpolated(_))
|
&& (matches!(expected_token.kind, TokenKind::Interpolated(_))
|
||||||
|| matches!(token.kind, TokenKind::Interpolated(_)))
|
|| matches!(token.kind, TokenKind::Interpolated(_)))
|
||||||
{
|
{
|
||||||
if let TokenKind::Interpolated(node) = &expected_token.kind {
|
|
||||||
err.span_label(node.1, "");
|
|
||||||
}
|
|
||||||
if let TokenKind::Interpolated(node) = &token.kind {
|
|
||||||
err.span_label(node.1, "");
|
|
||||||
}
|
|
||||||
err.note("captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens");
|
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");
|
err.note("see <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> for more information");
|
||||||
|
|
||||||
|
|
|
@ -75,10 +75,9 @@ pub(crate) use ParseResult::*;
|
||||||
|
|
||||||
use crate::mbe::{macro_rules::Tracker, KleeneOp, TokenTree};
|
use crate::mbe::{macro_rules::Tracker, KleeneOp, TokenTree};
|
||||||
|
|
||||||
use rustc_ast::token::{self, DocComment, Nonterminal, NonterminalKind, Token};
|
use rustc_ast::token::{self, DocComment, NonterminalKind, Token};
|
||||||
use rustc_ast_pretty::pprust;
|
use rustc_ast_pretty::pprust;
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_data_structures::sync::Lrc;
|
|
||||||
use rustc_errors::ErrorGuaranteed;
|
use rustc_errors::ErrorGuaranteed;
|
||||||
use rustc_lint_defs::pluralize;
|
use rustc_lint_defs::pluralize;
|
||||||
use rustc_parse::parser::{ParseNtResult, Parser};
|
use rustc_parse::parser::{ParseNtResult, Parser};
|
||||||
|
@ -392,7 +391,7 @@ pub(super) fn count_metavar_decls(matcher: &[TokenTree]) -> usize {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) enum NamedMatch {
|
pub(crate) enum NamedMatch {
|
||||||
MatchedSeq(Vec<NamedMatch>),
|
MatchedSeq(Vec<NamedMatch>),
|
||||||
MatchedSingle(ParseNtResult<Lrc<(Nonterminal, Span)>>),
|
MatchedSingle(ParseNtResult),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Performs a token equality check, ignoring syntax context (that is, an unhygienic comparison)
|
/// Performs a token equality check, ignoring syntax context (that is, an unhygienic comparison)
|
||||||
|
@ -686,11 +685,7 @@ impl TtParser {
|
||||||
}
|
}
|
||||||
Ok(nt) => nt,
|
Ok(nt) => nt,
|
||||||
};
|
};
|
||||||
mp.push_match(
|
mp.push_match(next_metavar, seq_depth, MatchedSingle(nt));
|
||||||
next_metavar,
|
|
||||||
seq_depth,
|
|
||||||
MatchedSingle(nt.map_nt(|nt| (Lrc::new((nt, span))))),
|
|
||||||
);
|
|
||||||
mp.idx += 1;
|
mp.idx += 1;
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
|
|
|
@ -261,6 +261,16 @@ pub(super) fn transcribe<'a>(
|
||||||
// without wrapping them into groups.
|
// without wrapping them into groups.
|
||||||
maybe_use_metavar_location(cx, &stack, sp, tt, &mut marker)
|
maybe_use_metavar_location(cx, &stack, sp, tt, &mut marker)
|
||||||
}
|
}
|
||||||
|
MatchedSingle(ParseNtResult::Ident(ident, is_raw)) => {
|
||||||
|
marker.visit_span(&mut sp);
|
||||||
|
let kind = token::NtIdent(*ident, *is_raw);
|
||||||
|
TokenTree::token_alone(kind, sp)
|
||||||
|
}
|
||||||
|
MatchedSingle(ParseNtResult::Lifetime(ident)) => {
|
||||||
|
marker.visit_span(&mut sp);
|
||||||
|
let kind = token::NtLifetime(*ident);
|
||||||
|
TokenTree::token_alone(kind, sp)
|
||||||
|
}
|
||||||
MatchedSingle(ParseNtResult::Nt(nt)) => {
|
MatchedSingle(ParseNtResult::Nt(nt)) => {
|
||||||
// Other variables are emitted into the output stream as groups with
|
// Other variables are emitted into the output stream as groups with
|
||||||
// `Delimiter::Invisible` to maintain parsing priorities.
|
// `Delimiter::Invisible` to maintain parsing priorities.
|
||||||
|
|
|
@ -127,7 +127,7 @@ impl MultiItemModifier for DeriveProcMacro {
|
||||||
Annotatable::Stmt(stmt) => token::NtStmt(stmt),
|
Annotatable::Stmt(stmt) => token::NtStmt(stmt),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
TokenStream::token_alone(token::Interpolated(Lrc::new((nt, span))), DUMMY_SP)
|
TokenStream::token_alone(token::Interpolated(Lrc::new(nt)), DUMMY_SP)
|
||||||
} else {
|
} else {
|
||||||
item.to_tokens()
|
item.to_tokens()
|
||||||
};
|
};
|
||||||
|
|
|
@ -220,6 +220,12 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
|
||||||
Ident(sym, is_raw) => {
|
Ident(sym, is_raw) => {
|
||||||
trees.push(TokenTree::Ident(Ident { sym, is_raw: is_raw.into(), span }))
|
trees.push(TokenTree::Ident(Ident { sym, is_raw: is_raw.into(), span }))
|
||||||
}
|
}
|
||||||
|
NtIdent(ident, is_raw) => trees.push(TokenTree::Ident(Ident {
|
||||||
|
sym: ident.name,
|
||||||
|
is_raw: is_raw.into(),
|
||||||
|
span: ident.span,
|
||||||
|
})),
|
||||||
|
|
||||||
Lifetime(name) => {
|
Lifetime(name) => {
|
||||||
let ident = symbol::Ident::new(name, span).without_first_quote();
|
let ident = symbol::Ident::new(name, span).without_first_quote();
|
||||||
trees.extend([
|
trees.extend([
|
||||||
|
@ -227,6 +233,15 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
|
||||||
TokenTree::Ident(Ident { sym: ident.name, is_raw: false, span }),
|
TokenTree::Ident(Ident { sym: ident.name, is_raw: false, span }),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
NtLifetime(ident) => {
|
||||||
|
let stream = TokenStream::token_alone(token::Lifetime(ident.name), ident.span);
|
||||||
|
trees.push(TokenTree::Group(Group {
|
||||||
|
delimiter: pm::Delimiter::None,
|
||||||
|
stream: Some(stream),
|
||||||
|
span: DelimSpan::from_single(span),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
Literal(token::Lit { kind, symbol, suffix }) => {
|
Literal(token::Lit { kind, symbol, suffix }) => {
|
||||||
trees.push(TokenTree::Literal(self::Literal {
|
trees.push(TokenTree::Literal(self::Literal {
|
||||||
kind: FromInternal::from_internal(kind),
|
kind: FromInternal::from_internal(kind),
|
||||||
|
@ -259,23 +274,15 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
Interpolated(ref nt) if let NtIdent(ident, is_raw) = &nt.0 => {
|
|
||||||
trees.push(TokenTree::Ident(Ident {
|
|
||||||
sym: ident.name,
|
|
||||||
is_raw: matches!(is_raw, IdentIsRaw::Yes),
|
|
||||||
span: ident.span,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
Interpolated(nt) => {
|
Interpolated(nt) => {
|
||||||
let stream = TokenStream::from_nonterminal_ast(&nt.0);
|
let stream = TokenStream::from_nonterminal_ast(&nt);
|
||||||
// A hack used to pass AST fragments to attribute and derive
|
// A hack used to pass AST fragments to attribute and derive
|
||||||
// macros as a single nonterminal token instead of a token
|
// macros as a single nonterminal token instead of a token
|
||||||
// stream. Such token needs to be "unwrapped" and not
|
// stream. Such token needs to be "unwrapped" and not
|
||||||
// represented as a delimited group.
|
// represented as a delimited group.
|
||||||
// FIXME: It needs to be removed, but there are some
|
// FIXME: It needs to be removed, but there are some
|
||||||
// compatibility issues (see #73345).
|
// compatibility issues (see #73345).
|
||||||
if crate::base::nt_pretty_printing_compatibility_hack(&nt.0, rustc.ecx.sess) {
|
if crate::base::nt_pretty_printing_compatibility_hack(&nt, rustc.ecx.sess) {
|
||||||
trees.extend(Self::from_internal((stream, rustc)));
|
trees.extend(Self::from_internal((stream, rustc)));
|
||||||
} else {
|
} else {
|
||||||
trees.push(TokenTree::Group(Group {
|
trees.push(TokenTree::Group(Group {
|
||||||
|
|
|
@ -363,7 +363,7 @@ impl<'a> Parser<'a> {
|
||||||
// We can't use `maybe_whole` here because it would bump in the `None`
|
// We can't use `maybe_whole` here because it would bump in the `None`
|
||||||
// case, which we don't want.
|
// case, which we don't want.
|
||||||
if let token::Interpolated(nt) = &self.token.kind
|
if let token::Interpolated(nt) = &self.token.kind
|
||||||
&& let token::NtMeta(attr_item) = &nt.0
|
&& let token::NtMeta(attr_item) = &**nt
|
||||||
{
|
{
|
||||||
match attr_item.meta(attr_item.path.span) {
|
match attr_item.meta(attr_item.path.span) {
|
||||||
Some(meta) => {
|
Some(meta) => {
|
||||||
|
|
|
@ -2372,9 +2372,9 @@ impl<'a> Parser<'a> {
|
||||||
// in a subsequent macro invocation (#71039).
|
// in a subsequent macro invocation (#71039).
|
||||||
let mut tok = self.token.clone();
|
let mut tok = self.token.clone();
|
||||||
let mut labels = vec![];
|
let mut labels = vec![];
|
||||||
while let TokenKind::Interpolated(node) = &tok.kind {
|
while let TokenKind::Interpolated(nt) = &tok.kind {
|
||||||
let tokens = node.0.tokens();
|
let tokens = nt.tokens();
|
||||||
labels.push(node.clone());
|
labels.push(nt.clone());
|
||||||
if let Some(tokens) = tokens
|
if let Some(tokens) = tokens
|
||||||
&& let tokens = tokens.to_attr_token_stream()
|
&& let tokens = tokens.to_attr_token_stream()
|
||||||
&& let tokens = tokens.0.deref()
|
&& let tokens = tokens.0.deref()
|
||||||
|
@ -2387,27 +2387,20 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
let mut iter = labels.into_iter().peekable();
|
let mut iter = labels.into_iter().peekable();
|
||||||
let mut show_link = false;
|
let mut show_link = false;
|
||||||
while let Some(node) = iter.next() {
|
while let Some(nt) = iter.next() {
|
||||||
let descr = node.0.descr();
|
let descr = nt.descr();
|
||||||
if let Some(next) = iter.peek() {
|
if let Some(next) = iter.peek() {
|
||||||
let next_descr = next.0.descr();
|
let next_descr = next.descr();
|
||||||
if next_descr != descr {
|
if next_descr != descr {
|
||||||
err.span_label(next.1, format!("this macro fragment matcher is {next_descr}"));
|
err.span_label(next.use_span(), format!("this is expected to be {next_descr}"));
|
||||||
err.span_label(node.1, format!("this macro fragment matcher is {descr}"));
|
|
||||||
err.span_label(
|
err.span_label(
|
||||||
next.0.use_span(),
|
nt.use_span(),
|
||||||
format!("this is expected to be {next_descr}"),
|
|
||||||
);
|
|
||||||
err.span_label(
|
|
||||||
node.0.use_span(),
|
|
||||||
format!(
|
format!(
|
||||||
"this is interpreted as {}, but it is expected to be {}",
|
"this is interpreted as {}, but it is expected to be {}",
|
||||||
next_descr, descr,
|
next_descr, descr,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
show_link = true;
|
show_link = true;
|
||||||
} else {
|
|
||||||
err.span_label(node.1, "");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ use thin_vec::{thin_vec, ThinVec};
|
||||||
macro_rules! maybe_whole_expr {
|
macro_rules! maybe_whole_expr {
|
||||||
($p:expr) => {
|
($p:expr) => {
|
||||||
if let token::Interpolated(nt) = &$p.token.kind {
|
if let token::Interpolated(nt) = &$p.token.kind {
|
||||||
match &nt.0 {
|
match &**nt {
|
||||||
token::NtExpr(e) | token::NtLiteral(e) => {
|
token::NtExpr(e) | token::NtLiteral(e) => {
|
||||||
let e = e.clone();
|
let e = e.clone();
|
||||||
$p.bump();
|
$p.bump();
|
||||||
|
@ -724,7 +724,9 @@ impl<'a> Parser<'a> {
|
||||||
/// Returns the span of expr if it was not interpolated, or the span of the interpolated token.
|
/// Returns the span of expr if it was not interpolated, or the span of the interpolated token.
|
||||||
fn interpolated_or_expr_span(&self, expr: &Expr) -> Span {
|
fn interpolated_or_expr_span(&self, expr: &Expr) -> Span {
|
||||||
match self.prev_token.kind {
|
match self.prev_token.kind {
|
||||||
TokenKind::Interpolated(..) => self.prev_token.span,
|
TokenKind::NtIdent(..) | TokenKind::NtLifetime(..) | TokenKind::Interpolated(..) => {
|
||||||
|
self.prev_token.span
|
||||||
|
}
|
||||||
_ => expr.span,
|
_ => expr.span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2841,7 +2841,7 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
fn is_named_param(&self) -> bool {
|
fn is_named_param(&self) -> bool {
|
||||||
let offset = match &self.token.kind {
|
let offset = match &self.token.kind {
|
||||||
token::Interpolated(nt) => match &nt.0 {
|
token::Interpolated(nt) => match &**nt {
|
||||||
token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon),
|
token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon),
|
||||||
_ => 0,
|
_ => 0,
|
||||||
},
|
},
|
||||||
|
|
|
@ -11,7 +11,6 @@ mod stmt;
|
||||||
mod ty;
|
mod ty;
|
||||||
|
|
||||||
use crate::lexer::UnmatchedDelim;
|
use crate::lexer::UnmatchedDelim;
|
||||||
use ast::token::IdentIsRaw;
|
|
||||||
pub use attr_wrapper::AttrWrapper;
|
pub use attr_wrapper::AttrWrapper;
|
||||||
pub use diagnostics::AttemptLocalParseRecovery;
|
pub use diagnostics::AttemptLocalParseRecovery;
|
||||||
pub(crate) use expr::ForbiddenLetReason;
|
pub(crate) use expr::ForbiddenLetReason;
|
||||||
|
@ -21,7 +20,7 @@ pub use path::PathStyle;
|
||||||
|
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast::ptr::P;
|
||||||
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
|
use rustc_ast::token::{self, Delimiter, IdentIsRaw, Nonterminal, Token, TokenKind};
|
||||||
use rustc_ast::tokenstream::{AttributesData, DelimSpacing, DelimSpan, Spacing};
|
use rustc_ast::tokenstream::{AttributesData, DelimSpacing, DelimSpan, Spacing};
|
||||||
use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor};
|
use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor};
|
||||||
use rustc_ast::util::case::Case;
|
use rustc_ast::util::case::Case;
|
||||||
|
@ -32,6 +31,7 @@ use rustc_ast::{
|
||||||
};
|
};
|
||||||
use rustc_ast_pretty::pprust;
|
use rustc_ast_pretty::pprust;
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
|
use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_errors::{Applicability, Diag, FatalError, MultiSpan, PResult};
|
use rustc_errors::{Applicability, Diag, FatalError, MultiSpan, PResult};
|
||||||
use rustc_session::parse::ParseSess;
|
use rustc_session::parse::ParseSess;
|
||||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||||
|
@ -107,7 +107,7 @@ pub enum TrailingToken {
|
||||||
macro_rules! maybe_whole {
|
macro_rules! maybe_whole {
|
||||||
($p:expr, $constructor:ident, |$x:ident| $e:expr) => {
|
($p:expr, $constructor:ident, |$x:ident| $e:expr) => {
|
||||||
if let token::Interpolated(nt) = &$p.token.kind
|
if let token::Interpolated(nt) = &$p.token.kind
|
||||||
&& let token::$constructor(x) = &nt.0
|
&& let token::$constructor(x) = &**nt
|
||||||
{
|
{
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
let mut $x = x.clone();
|
let mut $x = x.clone();
|
||||||
|
@ -125,7 +125,7 @@ macro_rules! maybe_recover_from_interpolated_ty_qpath {
|
||||||
&& $self.may_recover()
|
&& $self.may_recover()
|
||||||
&& $self.look_ahead(1, |t| t == &token::PathSep)
|
&& $self.look_ahead(1, |t| t == &token::PathSep)
|
||||||
&& let token::Interpolated(nt) = &$self.token.kind
|
&& let token::Interpolated(nt) = &$self.token.kind
|
||||||
&& let token::NtTy(ty) = &nt.0
|
&& let token::NtTy(ty) = &**nt
|
||||||
{
|
{
|
||||||
let ty = ty.clone();
|
let ty = ty.clone();
|
||||||
$self.bump();
|
$self.bump();
|
||||||
|
@ -407,7 +407,9 @@ pub(super) fn token_descr(token: &Token) -> String {
|
||||||
(Some(TokenDescription::Keyword), _) => Some("keyword"),
|
(Some(TokenDescription::Keyword), _) => Some("keyword"),
|
||||||
(Some(TokenDescription::ReservedKeyword), _) => Some("reserved keyword"),
|
(Some(TokenDescription::ReservedKeyword), _) => Some("reserved keyword"),
|
||||||
(Some(TokenDescription::DocComment), _) => Some("doc comment"),
|
(Some(TokenDescription::DocComment), _) => Some("doc comment"),
|
||||||
(None, TokenKind::Interpolated(node)) => Some(node.0.descr()),
|
(None, TokenKind::NtIdent(..)) => Some("identifier"),
|
||||||
|
(None, TokenKind::NtLifetime(..)) => Some("lifetime"),
|
||||||
|
(None, TokenKind::Interpolated(node)) => Some(node.descr()),
|
||||||
(None, _) => None,
|
(None, _) => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -708,7 +710,7 @@ impl<'a> Parser<'a> {
|
||||||
fn check_inline_const(&self, dist: usize) -> bool {
|
fn check_inline_const(&self, dist: usize) -> bool {
|
||||||
self.is_keyword_ahead(dist, &[kw::Const])
|
self.is_keyword_ahead(dist, &[kw::Const])
|
||||||
&& self.look_ahead(dist + 1, |t| match &t.kind {
|
&& self.look_ahead(dist + 1, |t| match &t.kind {
|
||||||
token::Interpolated(nt) => matches!(&nt.0, token::NtBlock(..)),
|
token::Interpolated(nt) => matches!(&**nt, token::NtBlock(..)),
|
||||||
token::OpenDelim(Delimiter::Brace) => true,
|
token::OpenDelim(Delimiter::Brace) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
})
|
})
|
||||||
|
@ -1631,19 +1633,11 @@ pub enum FlatToken {
|
||||||
|
|
||||||
// Metavar captures of various kinds.
|
// Metavar captures of various kinds.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum ParseNtResult<NtType> {
|
pub enum ParseNtResult {
|
||||||
Tt(TokenTree),
|
Tt(TokenTree),
|
||||||
Nt(NtType),
|
Ident(Ident, IdentIsRaw),
|
||||||
}
|
Lifetime(Ident),
|
||||||
|
|
||||||
impl<T> ParseNtResult<T> {
|
/// This case will eventually be removed, along with `Token::Interpolate`.
|
||||||
pub fn map_nt<F, U>(self, mut f: F) -> ParseNtResult<U>
|
Nt(Lrc<Nonterminal>),
|
||||||
where
|
|
||||||
F: FnMut(T) -> U,
|
|
||||||
{
|
|
||||||
match self {
|
|
||||||
ParseNtResult::Tt(tt) => ParseNtResult::Tt(tt),
|
|
||||||
ParseNtResult::Nt(nt) => ParseNtResult::Nt(f(nt)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast::ptr::P;
|
||||||
use rustc_ast::token::{self, Delimiter, Nonterminal, Nonterminal::*, NonterminalKind, Token};
|
use rustc_ast::token::{self, Delimiter, Nonterminal::*, NonterminalKind, Token};
|
||||||
use rustc_ast::HasTokens;
|
use rustc_ast::HasTokens;
|
||||||
use rustc_ast_pretty::pprust;
|
use rustc_ast_pretty::pprust;
|
||||||
|
use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_errors::PResult;
|
use rustc_errors::PResult;
|
||||||
use rustc_span::symbol::{kw, Ident};
|
use rustc_span::symbol::{kw, Ident};
|
||||||
|
|
||||||
|
@ -24,15 +25,13 @@ impl<'a> Parser<'a> {
|
||||||
| NtPat(_)
|
| NtPat(_)
|
||||||
| NtExpr(_)
|
| NtExpr(_)
|
||||||
| NtTy(_)
|
| NtTy(_)
|
||||||
| NtIdent(..)
|
|
||||||
| NtLiteral(_) // `true`, `false`
|
| NtLiteral(_) // `true`, `false`
|
||||||
| NtMeta(_)
|
| NtMeta(_)
|
||||||
| NtPath(_) => true,
|
| NtPath(_) => true,
|
||||||
|
|
||||||
NtItem(_)
|
NtItem(_)
|
||||||
| NtBlock(_)
|
| NtBlock(_)
|
||||||
| NtVis(_)
|
| NtVis(_) => false,
|
||||||
| NtLifetime(_) => false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,25 +48,30 @@ impl<'a> Parser<'a> {
|
||||||
NonterminalKind::Literal => token.can_begin_literal_maybe_minus(),
|
NonterminalKind::Literal => token.can_begin_literal_maybe_minus(),
|
||||||
NonterminalKind::Vis => match token.kind {
|
NonterminalKind::Vis => match token.kind {
|
||||||
// The follow-set of :vis + "priv" keyword + interpolated
|
// The follow-set of :vis + "priv" keyword + interpolated
|
||||||
token::Comma | token::Ident(..) | token::Interpolated(_) => true,
|
token::Comma
|
||||||
|
| token::Ident(..)
|
||||||
|
| token::NtIdent(..)
|
||||||
|
| token::NtLifetime(..)
|
||||||
|
| token::Interpolated(_) => true,
|
||||||
_ => token.can_begin_type(),
|
_ => token.can_begin_type(),
|
||||||
},
|
},
|
||||||
NonterminalKind::Block => match &token.kind {
|
NonterminalKind::Block => match &token.kind {
|
||||||
token::OpenDelim(Delimiter::Brace) => true,
|
token::OpenDelim(Delimiter::Brace) => true,
|
||||||
token::Interpolated(nt) => match &nt.0 {
|
token::NtLifetime(..) => true,
|
||||||
NtBlock(_) | NtLifetime(_) | NtStmt(_) | NtExpr(_) | NtLiteral(_) => true,
|
token::Interpolated(nt) => match &**nt {
|
||||||
NtItem(_) | NtPat(_) | NtTy(_) | NtIdent(..) | NtMeta(_) | NtPath(_)
|
NtBlock(_) | NtStmt(_) | NtExpr(_) | NtLiteral(_) => true,
|
||||||
| NtVis(_) => false,
|
NtItem(_) | NtPat(_) | NtTy(_) | NtMeta(_) | NtPath(_) | NtVis(_) => false,
|
||||||
},
|
},
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
NonterminalKind::Path | NonterminalKind::Meta => match &token.kind {
|
NonterminalKind::Path | NonterminalKind::Meta => match &token.kind {
|
||||||
token::PathSep | token::Ident(..) => true,
|
token::PathSep | token::Ident(..) | token::NtIdent(..) => true,
|
||||||
token::Interpolated(nt) => may_be_ident(&nt.0),
|
token::Interpolated(nt) => may_be_ident(nt),
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr => match &token.kind {
|
NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr => match &token.kind {
|
||||||
token::Ident(..) | // box, ref, mut, and other identifiers (can stricten)
|
// box, ref, mut, and other identifiers (can stricten)
|
||||||
|
token::Ident(..) | token::NtIdent(..) |
|
||||||
token::OpenDelim(Delimiter::Parenthesis) | // tuple pattern
|
token::OpenDelim(Delimiter::Parenthesis) | // tuple pattern
|
||||||
token::OpenDelim(Delimiter::Bracket) | // slice pattern
|
token::OpenDelim(Delimiter::Bracket) | // slice pattern
|
||||||
token::BinOp(token::And) | // reference
|
token::BinOp(token::And) | // reference
|
||||||
|
@ -81,14 +85,11 @@ impl<'a> Parser<'a> {
|
||||||
token::BinOp(token::Shl) => true, // path (double UFCS)
|
token::BinOp(token::Shl) => true, // path (double UFCS)
|
||||||
// leading vert `|` or-pattern
|
// leading vert `|` or-pattern
|
||||||
token::BinOp(token::Or) => matches!(kind, NonterminalKind::PatWithOr),
|
token::BinOp(token::Or) => matches!(kind, NonterminalKind::PatWithOr),
|
||||||
token::Interpolated(nt) => may_be_ident(&nt.0),
|
token::Interpolated(nt) => may_be_ident(nt),
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
NonterminalKind::Lifetime => match &token.kind {
|
NonterminalKind::Lifetime => match &token.kind {
|
||||||
token::Lifetime(_) => true,
|
token::Lifetime(_) | token::NtLifetime(..) => true,
|
||||||
token::Interpolated(nt) => {
|
|
||||||
matches!(&nt.0, NtLifetime(_))
|
|
||||||
}
|
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
NonterminalKind::TT | NonterminalKind::Item | NonterminalKind::Stmt => {
|
NonterminalKind::TT | NonterminalKind::Item | NonterminalKind::Stmt => {
|
||||||
|
@ -100,10 +101,7 @@ impl<'a> Parser<'a> {
|
||||||
/// Parse a non-terminal (e.g. MBE `:pat` or `:ident`). Inlined because there is only one call
|
/// Parse a non-terminal (e.g. MBE `:pat` or `:ident`). Inlined because there is only one call
|
||||||
/// site.
|
/// site.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn parse_nonterminal(
|
pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, ParseNtResult> {
|
||||||
&mut self,
|
|
||||||
kind: NonterminalKind,
|
|
||||||
) -> PResult<'a, ParseNtResult<Nonterminal>> {
|
|
||||||
// A `macro_rules!` invocation may pass a captured item/expr to a proc-macro,
|
// A `macro_rules!` invocation may pass a captured item/expr to a proc-macro,
|
||||||
// which requires having captured tokens available. Since we cannot determine
|
// which requires having captured tokens available. Since we cannot determine
|
||||||
// in advance whether or not a proc-macro will be (transitively) invoked,
|
// in advance whether or not a proc-macro will be (transitively) invoked,
|
||||||
|
@ -156,15 +154,16 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// this could be handled like a token, since it is one
|
// this could be handled like a token, since it is one
|
||||||
NonterminalKind::Ident if let Some((ident, is_raw)) = get_macro_ident(&self.token) => {
|
|
||||||
self.bump();
|
|
||||||
NtIdent(ident, is_raw)
|
|
||||||
}
|
|
||||||
NonterminalKind::Ident => {
|
NonterminalKind::Ident => {
|
||||||
return Err(self.dcx().create_err(UnexpectedNonterminal::Ident {
|
return if let Some((ident, is_raw)) = get_macro_ident(&self.token) {
|
||||||
|
self.bump();
|
||||||
|
Ok(ParseNtResult::Ident(ident, is_raw))
|
||||||
|
} else {
|
||||||
|
Err(self.dcx().create_err(UnexpectedNonterminal::Ident {
|
||||||
span: self.token.span,
|
span: self.token.span,
|
||||||
token: self.token.clone(),
|
token: self.token.clone(),
|
||||||
}));
|
}))
|
||||||
|
};
|
||||||
}
|
}
|
||||||
NonterminalKind::Path => {
|
NonterminalKind::Path => {
|
||||||
NtPath(P(self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?))
|
NtPath(P(self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?))
|
||||||
|
@ -175,14 +174,14 @@ impl<'a> Parser<'a> {
|
||||||
.collect_tokens_no_attrs(|this| this.parse_visibility(FollowedByType::Yes))?))
|
.collect_tokens_no_attrs(|this| this.parse_visibility(FollowedByType::Yes))?))
|
||||||
}
|
}
|
||||||
NonterminalKind::Lifetime => {
|
NonterminalKind::Lifetime => {
|
||||||
if self.check_lifetime() {
|
return if self.check_lifetime() {
|
||||||
NtLifetime(self.expect_lifetime().ident)
|
Ok(ParseNtResult::Lifetime(self.expect_lifetime().ident))
|
||||||
} else {
|
} else {
|
||||||
return Err(self.dcx().create_err(UnexpectedNonterminal::Lifetime {
|
Err(self.dcx().create_err(UnexpectedNonterminal::Lifetime {
|
||||||
span: self.token.span,
|
span: self.token.span,
|
||||||
token: self.token.clone(),
|
token: self.token.clone(),
|
||||||
}));
|
}))
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -196,7 +195,7 @@ impl<'a> Parser<'a> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ParseNtResult::Nt(nt))
|
Ok(ParseNtResult::Nt(Lrc::new(nt)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -757,7 +757,7 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
// Make sure we don't allow e.g. `let mut $p;` where `$p:pat`.
|
// Make sure we don't allow e.g. `let mut $p;` where `$p:pat`.
|
||||||
if let token::Interpolated(nt) = &self.token.kind {
|
if let token::Interpolated(nt) = &self.token.kind {
|
||||||
if let token::NtPat(..) = &nt.0 {
|
if let token::NtPat(..) = &**nt {
|
||||||
self.expected_ident_found_err().emit();
|
self.expected_ident_found_err().emit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -193,7 +193,7 @@ impl<'a> Parser<'a> {
|
||||||
maybe_whole!(self, NtPath, |path| reject_generics_if_mod_style(self, path.into_inner()));
|
maybe_whole!(self, NtPath, |path| reject_generics_if_mod_style(self, path.into_inner()));
|
||||||
|
|
||||||
if let token::Interpolated(nt) = &self.token.kind {
|
if let token::Interpolated(nt) = &self.token.kind {
|
||||||
if let token::NtTy(ty) = &nt.0 {
|
if let token::NtTy(ty) = &**nt {
|
||||||
if let ast::TyKind::Path(None, path) = &ty.kind {
|
if let ast::TyKind::Path(None, path) = &ty.kind {
|
||||||
let path = path.clone();
|
let path = path.clone();
|
||||||
self.bump();
|
self.bump();
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
error: no rules expected the token `enum E {}`
|
error: no rules expected the token `enum E {}`
|
||||||
--> $DIR/nonterminal-matching.rs:19:10
|
--> $DIR/nonterminal-matching.rs:19:10
|
||||||
|
|
|
|
||||||
LL | macro complex_nonterminal($nt_item: item) {
|
|
||||||
| --------------
|
|
||||||
LL | macro n(a $nt_item b) {
|
LL | macro n(a $nt_item b) {
|
||||||
| --------------------- when calling this macro
|
| --------------------- when calling this macro
|
||||||
...
|
...
|
||||||
|
|
|
@ -73,14 +73,10 @@ error: expected expression, found pattern `1 + 1`
|
||||||
--> $DIR/trace_faulty_macros.rs:49:37
|
--> $DIR/trace_faulty_macros.rs:49:37
|
||||||
|
|
|
|
||||||
LL | (let $p:pat = $e:expr) => {test!(($p,$e))};
|
LL | (let $p:pat = $e:expr) => {test!(($p,$e))};
|
||||||
| ------- -- this is interpreted as expression, but it is expected to be pattern
|
| -- this is interpreted as expression, but it is expected to be pattern
|
||||||
| |
|
|
||||||
| this macro fragment matcher is expression
|
|
||||||
...
|
...
|
||||||
LL | (($p:pat, $e:pat)) => {let $p = $e;};
|
LL | (($p:pat, $e:pat)) => {let $p = $e;};
|
||||||
| ------ ^^ expected expression
|
| ^^ expected expression
|
||||||
| |
|
|
||||||
| this macro fragment matcher is pattern
|
|
||||||
...
|
...
|
||||||
LL | test!(let x = 1+1);
|
LL | test!(let x = 1+1);
|
||||||
| ------------------
|
| ------------------
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue