feat: Implement expr_2021

This commit is contained in:
Shoyu Vanilla 2024-09-18 15:58:03 +09:00
parent 94b526fc86
commit d34a663c70
5 changed files with 192 additions and 21 deletions

View file

@ -146,7 +146,7 @@ fn invocation_fixtures(
Some(MetaVarKind::Pat) => token_trees.push(make_ident("foo")),
Some(MetaVarKind::Path) => token_trees.push(make_ident("foo")),
Some(MetaVarKind::Literal) => token_trees.push(make_literal("1")),
Some(MetaVarKind::Expr) => token_trees.push(make_ident("foo")),
Some(MetaVarKind::Expr(_)) => token_trees.push(make_ident("foo")),
Some(MetaVarKind::Lifetime) => {
token_trees.push(make_punct('\''));
token_trees.push(make_ident("a"));

View file

@ -69,7 +69,7 @@ use tt::{iter::TtIter, DelimSpan};
use crate::{
expander::{Binding, Bindings, ExpandResult, Fragment},
expect_fragment,
parser::{MetaVarKind, Op, RepeatKind, Separator},
parser::{ExprKind, MetaVarKind, Op, RepeatKind, Separator},
ExpandError, ExpandErrorKind, MetaTemplate, ValueResult,
};
@ -769,23 +769,28 @@ fn match_meta_var(
it.map(|it| tt::TokenTree::subtree_or_wrap(it, delim_span)).map(Fragment::Path)
});
}
MetaVarKind::Expr => {
// `expr` should not match underscores, let expressions, or inline const. The latter
// two are for [backwards compatibility][0].
MetaVarKind::Expr(expr) => {
// `expr_2021` should not match underscores, let expressions, or inline const.
// The latter two are for [backwards compatibility][0].
// And `expr` also should not contain let expressions but may contain the other two
// since `Edition2024`.
// HACK: Macro expansion should not be done using "rollback and try another alternative".
// rustc [explicitly checks the next token][1].
// [0]: https://github.com/rust-lang/rust/issues/86730
// [1]: https://github.com/rust-lang/rust/blob/f0c4da499/compiler/rustc_expand/src/mbe/macro_parser.rs#L576
match input.peek_n(0) {
Some(tt::TokenTree::Leaf(tt::Leaf::Ident(it)))
if it.sym == sym::underscore
|| it.sym == sym::let_
|| it.sym == sym::const_ =>
{
return ExpandResult::only_err(ExpandError::new(
it.span,
ExpandErrorKind::NoMatchingRule,
))
Some(tt::TokenTree::Leaf(tt::Leaf::Ident(it))) => {
let is_err = if matches!(expr, ExprKind::Expr2021) {
it.sym == sym::underscore || it.sym == sym::let_ || it.sym == sym::const_
} else {
it.sym == sym::let_
};
if is_err {
return ExpandResult::only_err(ExpandError::new(
it.span,
ExpandErrorKind::NoMatchingRule,
));
}
}
_ => {}
};

View file

@ -97,7 +97,7 @@ impl Bindings {
| MetaVarKind::Ty
| MetaVarKind::Pat
| MetaVarKind::PatParam
| MetaVarKind::Expr
| MetaVarKind::Expr(_)
| MetaVarKind::Ident => {
Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
sym: sym::missing.clone(),

View file

@ -105,6 +105,16 @@ pub(crate) enum RepeatKind {
ZeroOrOne,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(crate) enum ExprKind {
// 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.
// Either written using `expr` in edition 2021 or earlier or.was written using `expr_2021`.
Expr2021,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(crate) enum MetaVarKind {
Path,
@ -116,7 +126,7 @@ pub(crate) enum MetaVarKind {
Meta,
Item,
Vis,
Expr,
Expr(ExprKind),
Ident,
Tt,
Lifetime,
@ -277,17 +287,27 @@ fn eat_fragment_kind(
let kind = match ident.sym.as_str() {
"path" => MetaVarKind::Path,
"ty" => MetaVarKind::Ty,
"pat" => match edition(ident.span.ctx) {
Edition::Edition2015 | Edition::Edition2018 => MetaVarKind::PatParam,
Edition::Edition2021 | Edition::Edition2024 => MetaVarKind::Pat,
},
"pat" => {
if edition(ident.span.ctx).at_least_2021() {
MetaVarKind::Pat
} else {
MetaVarKind::PatParam
}
}
"pat_param" => MetaVarKind::PatParam,
"stmt" => MetaVarKind::Stmt,
"block" => MetaVarKind::Block,
"meta" => MetaVarKind::Meta,
"item" => MetaVarKind::Item,
"vis" => MetaVarKind::Vis,
"expr" => MetaVarKind::Expr,
"expr" => {
if edition(ident.span.ctx).at_least_2024() {
MetaVarKind::Expr(ExprKind::Expr)
} else {
MetaVarKind::Expr(ExprKind::Expr2021)
}
}
"expr_2021" => MetaVarKind::Expr(ExprKind::Expr2021),
"ident" => MetaVarKind::Ident,
"tt" => MetaVarKind::Tt,
"lifetime" => MetaVarKind::Lifetime,

View file

@ -177,3 +177,149 @@ fn main() {
}"#]],
);
}
#[test]
fn expr_2021() {
check(
Edition::Edition2024,
Edition::Edition2024,
r#"
($($e:expr),* $(,)?) => {
$($e);* ;
};
"#,
r#"
_,
const { 1 },
"#,
expect![[r#"
SUBTREE $$ 1:0@0..25#0 1:0@0..25#0
IDENT _ 1:0@5..6#0
PUNCH ; [joint] 0:0@36..37#0
SUBTREE () 0:0@34..35#0 0:0@34..35#0
IDENT const 1:0@12..17#0
SUBTREE {} 1:0@18..19#0 1:0@22..23#0
LITERAL Integer 1 1:0@20..21#0
PUNCH ; [alone] 0:0@39..40#0
_;
(const {
1
});"#]],
);
check(
Edition::Edition2021,
Edition::Edition2024,
r#"
($($e:expr),* $(,)?) => {
$($e);* ;
};
"#,
r#"
_,
"#,
expect![[r#"
ExpandError {
inner: (
1:0@5..6#0,
NoMatchingRule,
),
}
SUBTREE $$ 1:0@0..8#0 1:0@0..8#0
PUNCH ; [alone] 0:0@39..40#0
;"#]],
);
check(
Edition::Edition2021,
Edition::Edition2024,
r#"
($($e:expr),* $(,)?) => {
$($e);* ;
};
"#,
r#"
const { 1 },
"#,
expect![[r#"
ExpandError {
inner: (
1:0@5..10#0,
NoMatchingRule,
),
}
SUBTREE $$ 1:0@0..18#0 1:0@0..18#0
PUNCH ; [alone] 0:0@39..40#0
;"#]],
);
check(
Edition::Edition2024,
Edition::Edition2024,
r#"
($($e:expr_2021),* $(,)?) => {
$($e);* ;
};
"#,
r#"
4,
"literal",
funcall(),
future.await,
break 'foo bar,
"#,
expect![[r#"
SUBTREE $$ 1:0@0..76#0 1:0@0..76#0
LITERAL Integer 4 1:0@5..6#0
PUNCH ; [joint] 0:0@41..42#0
LITERAL Str literal 1:0@12..21#0
PUNCH ; [joint] 0:0@41..42#0
SUBTREE () 0:0@39..40#0 0:0@39..40#0
IDENT funcall 1:0@27..34#0
SUBTREE () 1:0@34..35#0 1:0@35..36#0
PUNCH ; [joint] 0:0@41..42#0
SUBTREE () 0:0@39..40#0 0:0@39..40#0
IDENT future 1:0@42..48#0
PUNCH . [alone] 1:0@48..49#0
IDENT await 1:0@49..54#0
PUNCH ; [joint] 0:0@41..42#0
SUBTREE () 0:0@39..40#0 0:0@39..40#0
IDENT break 1:0@60..65#0
PUNCH ' [joint] 1:0@66..67#0
IDENT foo 1:0@67..70#0
IDENT bar 1:0@71..74#0
PUNCH ; [alone] 0:0@44..45#0
4;
"literal";
(funcall());
(future.await);
(break 'foo bar);"#]],
);
check(
Edition::Edition2024,
Edition::Edition2024,
r#"
($($e:expr_2021),* $(,)?) => {
$($e);* ;
};
"#,
r#"
_,
"#,
expect![[r#"
ExpandError {
inner: (
1:0@5..6#0,
NoMatchingRule,
),
}
SUBTREE $$ 1:0@0..8#0 1:0@0..8#0
PUNCH ; [alone] 0:0@44..45#0
;"#]],
);
}