Rework pattern and expression nonterminal kinds.
Merge `PatParam`/`PatWithOr`, and `Expr`/`Expr2021`, for a few reasons. - It's conceptually nice, because the two pattern kinds and the two expression kinds are very similar. - With expressions in particular, there are several places where both expression kinds get the same treatment. - It removes one unreachable match arm. - Most importantly, for #124141 I will need to introduce a new type `MetaVarKind` that is very similar to `NonterminalKind`, but records a couple of extra fields for expression metavars. It's nicer to have a single `MetaVarKind::Expr` expression variant to hold those extra fields instead of duplicating them across two variants `MetaVarKind::{Expr,Expr2021}`. And then it makes sense for patterns to be treated the same way, and for `NonterminalKind` to also be treated the same way. I also clarified the comments, because I have long found them a little hard to understand.
This commit is contained in:
parent
70fa67c0b2
commit
e2aa38e6ab
@ -1,6 +1,8 @@
|
|||||||
pub use BinOpToken::*;
|
pub use BinOpToken::*;
|
||||||
pub use LitKind::*;
|
pub use LitKind::*;
|
||||||
pub use Nonterminal::*;
|
pub use Nonterminal::*;
|
||||||
|
pub use NtExprKind::*;
|
||||||
|
pub use NtPatKind::*;
|
||||||
pub use TokenKind::*;
|
pub use TokenKind::*;
|
||||||
|
|
||||||
use crate::ast;
|
use crate::ast;
|
||||||
@ -871,6 +873,27 @@ fn eq(&self, rhs: &TokenKind) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable)]
|
||||||
|
pub enum NtPatKind {
|
||||||
|
// Matches or-patterns. Was written using `pat` in edition 2021 or later.
|
||||||
|
PatWithOr,
|
||||||
|
// Doesn't match or-patterns.
|
||||||
|
// - `inferred`: was written using `pat` in edition 2015 or 2018.
|
||||||
|
// - `!inferred`: was written using `pat_param`.
|
||||||
|
PatParam { inferred: bool },
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable)]
|
||||||
|
pub enum NtExprKind {
|
||||||
|
// Matches expressions using the post-edition 2024. Was written using
|
||||||
|
// `expr` in edition 2024 or later.
|
||||||
|
Expr,
|
||||||
|
// Matches expressions using the pre-edition 2024 rules.
|
||||||
|
// - `inferred`: was written using `expr` in edition 2021 or earlier.
|
||||||
|
// - `!inferred`: was written using `expr_2021`.
|
||||||
|
Expr2021 { inferred: bool },
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Encodable, Decodable)]
|
#[derive(Clone, Encodable, Decodable)]
|
||||||
/// For interpolation during macro expansion.
|
/// For interpolation during macro expansion.
|
||||||
pub enum Nonterminal {
|
pub enum Nonterminal {
|
||||||
@ -892,19 +915,8 @@ pub enum NonterminalKind {
|
|||||||
Item,
|
Item,
|
||||||
Block,
|
Block,
|
||||||
Stmt,
|
Stmt,
|
||||||
PatParam {
|
Pat(NtPatKind),
|
||||||
/// Keep track of whether the user used `:pat_param` or `:pat` and we inferred it from the
|
Expr(NtExprKind),
|
||||||
/// edition of the span. This is used for diagnostics.
|
|
||||||
inferred: bool,
|
|
||||||
},
|
|
||||||
PatWithOr,
|
|
||||||
Expr,
|
|
||||||
/// Matches an expression using the rules from edition 2021 and earlier.
|
|
||||||
Expr2021 {
|
|
||||||
/// Keep track of whether the user used `:expr` or `:expr_2021` and we inferred it from the
|
|
||||||
/// edition of the span. This is used for diagnostics AND feature gating.
|
|
||||||
inferred: bool,
|
|
||||||
},
|
|
||||||
Ty,
|
Ty,
|
||||||
Ident,
|
Ident,
|
||||||
Lifetime,
|
Lifetime,
|
||||||
@ -926,20 +938,22 @@ pub fn from_symbol(
|
|||||||
sym::item => NonterminalKind::Item,
|
sym::item => NonterminalKind::Item,
|
||||||
sym::block => NonterminalKind::Block,
|
sym::block => NonterminalKind::Block,
|
||||||
sym::stmt => NonterminalKind::Stmt,
|
sym::stmt => NonterminalKind::Stmt,
|
||||||
sym::pat => match edition() {
|
sym::pat => {
|
||||||
Edition::Edition2015 | Edition::Edition2018 => {
|
if edition().at_least_rust_2021() {
|
||||||
NonterminalKind::PatParam { inferred: true }
|
NonterminalKind::Pat(PatWithOr)
|
||||||
|
} else {
|
||||||
|
NonterminalKind::Pat(PatParam { inferred: true })
|
||||||
}
|
}
|
||||||
Edition::Edition2021 | Edition::Edition2024 => NonterminalKind::PatWithOr,
|
}
|
||||||
},
|
sym::pat_param => NonterminalKind::Pat(PatParam { inferred: false }),
|
||||||
sym::pat_param => NonterminalKind::PatParam { inferred: false },
|
sym::expr => {
|
||||||
sym::expr => match edition() {
|
if edition().at_least_rust_2024() {
|
||||||
Edition::Edition2015 | Edition::Edition2018 | Edition::Edition2021 => {
|
NonterminalKind::Expr(Expr)
|
||||||
NonterminalKind::Expr2021 { inferred: true }
|
} else {
|
||||||
|
NonterminalKind::Expr(Expr2021 { inferred: true })
|
||||||
}
|
}
|
||||||
Edition::Edition2024 => NonterminalKind::Expr,
|
}
|
||||||
},
|
sym::expr_2021 => NonterminalKind::Expr(Expr2021 { inferred: false }),
|
||||||
sym::expr_2021 => NonterminalKind::Expr2021 { inferred: false },
|
|
||||||
sym::ty => NonterminalKind::Ty,
|
sym::ty => NonterminalKind::Ty,
|
||||||
sym::ident => NonterminalKind::Ident,
|
sym::ident => NonterminalKind::Ident,
|
||||||
sym::lifetime => NonterminalKind::Lifetime,
|
sym::lifetime => NonterminalKind::Lifetime,
|
||||||
@ -951,15 +965,16 @@ pub fn from_symbol(
|
|||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn symbol(self) -> Symbol {
|
fn symbol(self) -> Symbol {
|
||||||
match self {
|
match self {
|
||||||
NonterminalKind::Item => sym::item,
|
NonterminalKind::Item => sym::item,
|
||||||
NonterminalKind::Block => sym::block,
|
NonterminalKind::Block => sym::block,
|
||||||
NonterminalKind::Stmt => sym::stmt,
|
NonterminalKind::Stmt => sym::stmt,
|
||||||
NonterminalKind::PatParam { inferred: false } => sym::pat_param,
|
NonterminalKind::Pat(PatParam { inferred: true } | PatWithOr) => sym::pat,
|
||||||
NonterminalKind::PatParam { inferred: true } | NonterminalKind::PatWithOr => sym::pat,
|
NonterminalKind::Pat(PatParam { inferred: false }) => sym::pat_param,
|
||||||
NonterminalKind::Expr | NonterminalKind::Expr2021 { inferred: true } => sym::expr,
|
NonterminalKind::Expr(Expr2021 { inferred: true } | Expr) => sym::expr,
|
||||||
NonterminalKind::Expr2021 { inferred: false } => sym::expr_2021,
|
NonterminalKind::Expr(Expr2021 { inferred: false }) => sym::expr_2021,
|
||||||
NonterminalKind::Ty => sym::ty,
|
NonterminalKind::Ty => sym::ty,
|
||||||
NonterminalKind::Ident => sym::ident,
|
NonterminalKind::Ident => sym::ident,
|
||||||
NonterminalKind::Lifetime => sym::lifetime,
|
NonterminalKind::Lifetime => sym::lifetime,
|
||||||
|
@ -10,7 +10,9 @@
|
|||||||
|
|
||||||
use ast::token::IdentIsRaw;
|
use ast::token::IdentIsRaw;
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind, TokenKind::*};
|
use rustc_ast::token::{
|
||||||
|
self, Delimiter, NonterminalKind, NtPatKind::*, Token, TokenKind, TokenKind::*,
|
||||||
|
};
|
||||||
use rustc_ast::tokenstream::{DelimSpan, TokenStream};
|
use rustc_ast::tokenstream::{DelimSpan, TokenStream};
|
||||||
use rustc_ast::{NodeId, DUMMY_NODE_ID};
|
use rustc_ast::{NodeId, DUMMY_NODE_ID};
|
||||||
use rustc_ast_pretty::pprust;
|
use rustc_ast_pretty::pprust;
|
||||||
@ -1145,7 +1147,7 @@ fn check_matcher_core<'tt>(
|
|||||||
// Macros defined in the current crate have a real node id,
|
// Macros defined in the current crate have a real node id,
|
||||||
// whereas macros from an external crate have a dummy id.
|
// whereas macros from an external crate have a dummy id.
|
||||||
if def.id != DUMMY_NODE_ID
|
if def.id != DUMMY_NODE_ID
|
||||||
&& matches!(kind, NonterminalKind::PatParam { inferred: true })
|
&& matches!(kind, NonterminalKind::Pat(PatParam { inferred: true }))
|
||||||
&& matches!(
|
&& matches!(
|
||||||
next_token,
|
next_token,
|
||||||
TokenTree::Token(token) if token.kind == BinOp(token::BinOpToken::Or)
|
TokenTree::Token(token) if token.kind == BinOp(token::BinOpToken::Or)
|
||||||
@ -1155,7 +1157,7 @@ fn check_matcher_core<'tt>(
|
|||||||
let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl(
|
let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl(
|
||||||
span,
|
span,
|
||||||
name,
|
name,
|
||||||
Some(NonterminalKind::PatParam { inferred: false }),
|
Some(NonterminalKind::Pat(PatParam { inferred: false })),
|
||||||
));
|
));
|
||||||
sess.psess.buffer_lint(
|
sess.psess.buffer_lint(
|
||||||
RUST_2021_INCOMPATIBLE_OR_PATTERNS,
|
RUST_2021_INCOMPATIBLE_OR_PATTERNS,
|
||||||
@ -1188,14 +1190,14 @@ fn check_matcher_core<'tt>(
|
|||||||
);
|
);
|
||||||
err.span_label(sp, format!("not allowed after `{kind}` fragments"));
|
err.span_label(sp, format!("not allowed after `{kind}` fragments"));
|
||||||
|
|
||||||
if kind == NonterminalKind::PatWithOr
|
if kind == NonterminalKind::Pat(PatWithOr)
|
||||||
&& sess.psess.edition.at_least_rust_2021()
|
&& sess.psess.edition.at_least_rust_2021()
|
||||||
&& next_token.is_token(&BinOp(token::BinOpToken::Or))
|
&& next_token.is_token(&BinOp(token::BinOpToken::Or))
|
||||||
{
|
{
|
||||||
let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl(
|
let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl(
|
||||||
span,
|
span,
|
||||||
name,
|
name,
|
||||||
Some(NonterminalKind::PatParam { inferred: false }),
|
Some(NonterminalKind::Pat(PatParam { inferred: false })),
|
||||||
));
|
));
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
span,
|
span,
|
||||||
@ -1295,9 +1297,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
|
|||||||
// maintain
|
// maintain
|
||||||
IsInFollow::Yes
|
IsInFollow::Yes
|
||||||
}
|
}
|
||||||
NonterminalKind::Stmt
|
NonterminalKind::Stmt | NonterminalKind::Expr(_) => {
|
||||||
| NonterminalKind::Expr
|
|
||||||
| NonterminalKind::Expr2021 { inferred: _ } => {
|
|
||||||
const TOKENS: &[&str] = &["`=>`", "`,`", "`;`"];
|
const TOKENS: &[&str] = &["`=>`", "`,`", "`;`"];
|
||||||
match tok {
|
match tok {
|
||||||
TokenTree::Token(token) => match token.kind {
|
TokenTree::Token(token) => match token.kind {
|
||||||
@ -1307,7 +1307,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
|
|||||||
_ => IsInFollow::No(TOKENS),
|
_ => IsInFollow::No(TOKENS),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NonterminalKind::PatParam { .. } => {
|
NonterminalKind::Pat(PatParam { .. }) => {
|
||||||
const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`|`", "`if`", "`in`"];
|
const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`|`", "`if`", "`in`"];
|
||||||
match tok {
|
match tok {
|
||||||
TokenTree::Token(token) => match token.kind {
|
TokenTree::Token(token) => match token.kind {
|
||||||
@ -1320,7 +1320,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
|
|||||||
_ => IsInFollow::No(TOKENS),
|
_ => IsInFollow::No(TOKENS),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NonterminalKind::PatWithOr => {
|
NonterminalKind::Pat(PatWithOr) => {
|
||||||
const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`if`", "`in`"];
|
const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`if`", "`in`"];
|
||||||
match tok {
|
match tok {
|
||||||
TokenTree::Token(token) => match token.kind {
|
TokenTree::Token(token) => match token.kind {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
use crate::mbe::macro_parser::count_metavar_decls;
|
use crate::mbe::macro_parser::count_metavar_decls;
|
||||||
use crate::mbe::{Delimited, KleeneOp, KleeneToken, MetaVarExpr, SequenceRepetition, TokenTree};
|
use crate::mbe::{Delimited, KleeneOp, KleeneToken, MetaVarExpr, SequenceRepetition, TokenTree};
|
||||||
|
|
||||||
use rustc_ast::token::{self, Delimiter, IdentIsRaw, NonterminalKind, Token};
|
use rustc_ast::token::{self, Delimiter, IdentIsRaw, NonterminalKind, NtExprKind::*, Token};
|
||||||
use rustc_ast::{tokenstream, NodeId};
|
use rustc_ast::{tokenstream, NodeId};
|
||||||
use rustc_ast_pretty::pprust;
|
use rustc_ast_pretty::pprust;
|
||||||
use rustc_feature::Features;
|
use rustc_feature::Features;
|
||||||
@ -109,7 +109,7 @@ pub(super) fn parse(
|
|||||||
});
|
});
|
||||||
NonterminalKind::Ident
|
NonterminalKind::Ident
|
||||||
});
|
});
|
||||||
if kind == (NonterminalKind::Expr2021 { inferred: false })
|
if kind == NonterminalKind::Expr(Expr2021 { inferred: false })
|
||||||
&& !features.expr_fragment_specifier_2024
|
&& !features.expr_fragment_specifier_2024
|
||||||
{
|
{
|
||||||
rustc_session::parse::feature_err(
|
rustc_session::parse::feature_err(
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
use rustc_ast::ptr::P;
|
use rustc_ast::ptr::P;
|
||||||
use rustc_ast::token::{self, Delimiter, Nonterminal::*, NonterminalKind, Token};
|
use rustc_ast::token::{
|
||||||
|
self, Delimiter, Nonterminal::*, NonterminalKind, NtExprKind::*, NtPatKind::*, 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_data_structures::sync::Lrc;
|
||||||
@ -36,14 +38,14 @@ fn may_be_ident(nt: &token::Nonterminal) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match kind {
|
match kind {
|
||||||
NonterminalKind::Expr2021 { inferred: _ } => {
|
NonterminalKind::Expr(Expr2021 { .. }) => {
|
||||||
token.can_begin_expr()
|
token.can_begin_expr()
|
||||||
// This exception is here for backwards compatibility.
|
// This exception is here for backwards compatibility.
|
||||||
&& !token.is_keyword(kw::Let)
|
&& !token.is_keyword(kw::Let)
|
||||||
// This exception is here for backwards compatibility.
|
// This exception is here for backwards compatibility.
|
||||||
&& !token.is_keyword(kw::Const)
|
&& !token.is_keyword(kw::Const)
|
||||||
}
|
}
|
||||||
NonterminalKind::Expr => {
|
NonterminalKind::Expr(Expr) => {
|
||||||
token.can_begin_expr()
|
token.can_begin_expr()
|
||||||
// This exception is here for backwards compatibility.
|
// This exception is here for backwards compatibility.
|
||||||
&& !token.is_keyword(kw::Let)
|
&& !token.is_keyword(kw::Let)
|
||||||
@ -74,7 +76,7 @@ fn may_be_ident(nt: &token::Nonterminal) -> bool {
|
|||||||
token::Interpolated(nt) => may_be_ident(nt),
|
token::Interpolated(nt) => may_be_ident(nt),
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr => match &token.kind {
|
NonterminalKind::Pat(pat_kind) => match &token.kind {
|
||||||
// box, ref, mut, and other identifiers (can stricten)
|
// box, ref, mut, and other identifiers (can stricten)
|
||||||
token::Ident(..) | token::NtIdent(..) |
|
token::Ident(..) | token::NtIdent(..) |
|
||||||
token::OpenDelim(Delimiter::Parenthesis) | // tuple pattern
|
token::OpenDelim(Delimiter::Parenthesis) | // tuple pattern
|
||||||
@ -89,7 +91,7 @@ fn may_be_ident(nt: &token::Nonterminal) -> bool {
|
|||||||
token::Lt | // path (UFCS constant)
|
token::Lt | // path (UFCS constant)
|
||||||
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!(pat_kind, PatWithOr),
|
||||||
token::Interpolated(nt) => may_be_ident(nt),
|
token::Interpolated(nt) => may_be_ident(nt),
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
@ -135,31 +137,25 @@ pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, ParseN
|
|||||||
.create_err(UnexpectedNonterminal::Statement(self.token.span)));
|
.create_err(UnexpectedNonterminal::Statement(self.token.span)));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr => {
|
NonterminalKind::Pat(pat_kind) => {
|
||||||
NtPat(self.collect_tokens_no_attrs(|this| match kind {
|
NtPat(self.collect_tokens_no_attrs(|this| match pat_kind {
|
||||||
NonterminalKind::PatParam { .. } => this.parse_pat_no_top_alt(None, None),
|
PatParam { .. } => this.parse_pat_no_top_alt(None, None),
|
||||||
NonterminalKind::PatWithOr => this.parse_pat_allow_top_alt(
|
PatWithOr => this.parse_pat_allow_top_alt(
|
||||||
None,
|
None,
|
||||||
RecoverComma::No,
|
RecoverComma::No,
|
||||||
RecoverColon::No,
|
RecoverColon::No,
|
||||||
CommaRecoveryMode::EitherTupleOrPipe,
|
CommaRecoveryMode::EitherTupleOrPipe,
|
||||||
),
|
),
|
||||||
_ => unreachable!(),
|
|
||||||
})?)
|
})?)
|
||||||
}
|
}
|
||||||
|
NonterminalKind::Expr(_) => NtExpr(self.parse_expr_force_collect()?),
|
||||||
NonterminalKind::Expr | NonterminalKind::Expr2021 { inferred: _ } => {
|
|
||||||
NtExpr(self.parse_expr_force_collect()?)
|
|
||||||
}
|
|
||||||
NonterminalKind::Literal => {
|
NonterminalKind::Literal => {
|
||||||
// The `:literal` matcher does not support attributes
|
// The `:literal` matcher does not support attributes
|
||||||
NtLiteral(self.collect_tokens_no_attrs(|this| this.parse_literal_maybe_minus())?)
|
NtLiteral(self.collect_tokens_no_attrs(|this| this.parse_literal_maybe_minus())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
NonterminalKind::Ty => {
|
NonterminalKind::Ty => {
|
||||||
NtTy(self.collect_tokens_no_attrs(|this| this.parse_ty_no_question_mark_recover())?)
|
NtTy(self.collect_tokens_no_attrs(|this| this.parse_ty_no_question_mark_recover())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
// this could be handled like a token, since it is one
|
// this could be handled like a token, since it is one
|
||||||
NonterminalKind::Ident => {
|
NonterminalKind::Ident => {
|
||||||
return if let Some((ident, is_raw)) = get_macro_ident(&self.token) {
|
return if let Some((ident, is_raw)) = get_macro_ident(&self.token) {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use rustc_ast::token::{Delimiter, NonterminalKind, TokenKind};
|
use rustc_ast::token::{Delimiter, NonterminalKind, NtExprKind::*, NtPatKind::*, TokenKind};
|
||||||
use rustc_ast::tokenstream::TokenStream;
|
use rustc_ast::tokenstream::TokenStream;
|
||||||
use rustc_ast::{ast, ptr};
|
use rustc_ast::{ast, ptr};
|
||||||
use rustc_parse::parser::{ForceCollect, Parser, Recovery};
|
use rustc_parse::parser::{ForceCollect, Parser, Recovery};
|
||||||
@ -48,7 +48,7 @@ macro_rules! parse_macro_arg {
|
|||||||
|
|
||||||
parse_macro_arg!(
|
parse_macro_arg!(
|
||||||
Expr,
|
Expr,
|
||||||
NonterminalKind::Expr,
|
NonterminalKind::Expr(Expr),
|
||||||
|parser: &mut Parser<'b>| parser.parse_expr(),
|
|parser: &mut Parser<'b>| parser.parse_expr(),
|
||||||
|x: ptr::P<ast::Expr>| Some(x)
|
|x: ptr::P<ast::Expr>| Some(x)
|
||||||
);
|
);
|
||||||
@ -60,7 +60,7 @@ macro_rules! parse_macro_arg {
|
|||||||
);
|
);
|
||||||
parse_macro_arg!(
|
parse_macro_arg!(
|
||||||
Pat,
|
Pat,
|
||||||
NonterminalKind::PatParam { inferred: false },
|
NonterminalKind::Pat(PatParam { inferred: false }),
|
||||||
|parser: &mut Parser<'b>| parser.parse_pat_no_top_alt(None, None),
|
|parser: &mut Parser<'b>| parser.parse_pat_no_top_alt(None, None),
|
||||||
|x: ptr::P<ast::Pat>| Some(x)
|
|x: ptr::P<ast::Pat>| Some(x)
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user