Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-def/src/macro_expansion_tests/mbe.rs22
-rw-r--r--crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs4
-rw-r--r--crates/hir-def/src/macro_expansion_tests/mbe/regression.rs2
-rw-r--r--crates/hir-def/src/macro_expansion_tests/mod.rs11
-rw-r--r--crates/mbe/src/benchmark.rs4
-rw-r--r--crates/mbe/src/expander/matcher.rs11
-rw-r--r--crates/mbe/src/expander/transcriber.rs4
-rw-r--r--crates/mbe/src/parser.rs19
8 files changed, 63 insertions, 14 deletions
diff --git a/crates/hir-def/src/macro_expansion_tests/mbe.rs b/crates/hir-def/src/macro_expansion_tests/mbe.rs
index eea50d16f5..c6d901ec93 100644
--- a/crates/hir-def/src/macro_expansion_tests/mbe.rs
+++ b/crates/hir-def/src/macro_expansion_tests/mbe.rs
@@ -2029,3 +2029,25 @@ fn f() {
"#]],
);
}
+
+#[test]
+fn lifetime_repeat() {
+ check(
+ r#"
+macro_rules! m {
+ ($($x:expr)'a*) => (stringify!($($x)'b*));
+}
+fn f() {
+ let _ = m!(0 'a 1 'a 2);
+}
+ "#,
+ expect![[r#"
+macro_rules! m {
+ ($($x:expr)'a*) => (stringify!($($x)'b*));
+}
+fn f() {
+ let _ = stringify!(0 'b 1 'b 2);
+}
+ "#]],
+ );
+}
diff --git a/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs b/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs
index 2d289b7683..2c94f0e8d0 100644
--- a/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs
+++ b/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs
@@ -13,6 +13,8 @@ macro_rules! m {
($(x),*) => ();
($(x)_*) => ();
($(x)i*) => ();
+ ($(x)'a*) => ();
+ ($(x)'_*) => ();
($($i:ident)*) => ($_);
($($true:ident)*) => ($true);
($($false:ident)*) => ($false);
@@ -28,6 +30,8 @@ macro_rules! m {
($(x),*) => ();
($(x)_*) => ();
($(x)i*) => ();
+ ($(x)'a*) => ();
+ ($(x)'_*) => ();
($($i:ident)*) => ($_);
($($true:ident)*) => ($true);
($($false:ident)*) => ($false);
diff --git a/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs b/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
index 2cc3ca8c75..e2022c7967 100644
--- a/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
+++ b/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
@@ -784,7 +784,7 @@ macro_rules! delegate_impl {
}
}
}
-impl <> Data for &'amut G where G: Data {}
+impl <> Data for &'a mut G where G: Data {}
"#]],
);
}
diff --git a/crates/hir-def/src/macro_expansion_tests/mod.rs b/crates/hir-def/src/macro_expansion_tests/mod.rs
index b532156091..1c69b37f16 100644
--- a/crates/hir-def/src/macro_expansion_tests/mod.rs
+++ b/crates/hir-def/src/macro_expansion_tests/mod.rs
@@ -302,14 +302,15 @@ fn pretty_print_macro_expansion(
(_, T!['{']) => " ",
(T![;] | T!['{'] | T!['}'], _) => "\n",
(_, T!['}']) => "\n",
- (IDENT | LIFETIME_IDENT, IDENT | LIFETIME_IDENT) => " ",
- _ if prev_kind.is_keyword(Edition::CURRENT)
- && curr_kind.is_keyword(Edition::CURRENT) =>
+ _ if (prev_kind.is_any_identifier()
+ || prev_kind == LIFETIME_IDENT
+ || prev_kind.is_literal())
+ && (curr_kind.is_any_identifier()
+ || curr_kind == LIFETIME_IDENT
+ || curr_kind.is_literal()) =>
{
" "
}
- (IDENT, _) if curr_kind.is_keyword(Edition::CURRENT) => " ",
- (_, IDENT) if prev_kind.is_keyword(Edition::CURRENT) => " ",
(T![>], IDENT) => " ",
(T![>], _) if curr_kind.is_keyword(Edition::CURRENT) => " ",
(T![->], _) | (_, T![->]) => " ",
diff --git a/crates/mbe/src/benchmark.rs b/crates/mbe/src/benchmark.rs
index db75dceae1..04ac85ad43 100644
--- a/crates/mbe/src/benchmark.rs
+++ b/crates/mbe/src/benchmark.rs
@@ -197,6 +197,10 @@ fn invocation_fixtures(
builder.push(tt::Leaf::Punct(*it))
}
}
+ Separator::Lifetime(punct, ident) => {
+ builder.push(tt::Leaf::Punct(*punct));
+ builder.push(tt::Leaf::Ident(ident.clone()));
+ }
};
}
}
diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs
index 940aaacb02..a8d5965d48 100644
--- a/crates/mbe/src/expander/matcher.rs
+++ b/crates/mbe/src/expander/matcher.rs
@@ -823,7 +823,7 @@ fn match_meta_var<'t>(
"expected token tree",
)
}),
- MetaVarKind::Lifetime => expect_lifetime(input).map_err(|()| {
+ MetaVarKind::Lifetime => expect_lifetime(input).map(drop).map_err(|()| {
ExpandError::binding_error(
span.unwrap_or(delim_span.close),
"expected lifetime",
@@ -963,6 +963,10 @@ fn expect_separator<S: Copy>(iter: &mut TtIter<'_, S>, separator: &Separator) ->
}
Err(_) => false,
},
+ Separator::Lifetime(_punct, ident) => match expect_lifetime(&mut fork) {
+ Ok(lifetime) => lifetime.sym == ident.sym,
+ Err(_) => false,
+ },
};
if ok {
*iter = fork;
@@ -983,13 +987,12 @@ fn expect_tt<S: Copy>(iter: &mut TtIter<'_, S>) -> Result<(), ()> {
Ok(())
}
-fn expect_lifetime<S: Copy>(iter: &mut TtIter<'_, S>) -> Result<(), ()> {
+fn expect_lifetime<'a, S: Copy>(iter: &mut TtIter<'a, S>) -> Result<&'a tt::Ident<S>, ()> {
let punct = iter.expect_single_punct()?;
if punct.char != '\'' {
return Err(());
}
- iter.expect_ident_or_underscore()?;
- Ok(())
+ iter.expect_ident_or_underscore()
}
fn eat_char<S: Copy>(iter: &mut TtIter<'_, S>, c: char) {
diff --git a/crates/mbe/src/expander/transcriber.rs b/crates/mbe/src/expander/transcriber.rs
index ec277ba72e..2c046df10f 100644
--- a/crates/mbe/src/expander/transcriber.rs
+++ b/crates/mbe/src/expander/transcriber.rs
@@ -497,6 +497,10 @@ fn expand_repeat(
builder.push(tt::Leaf::from(punct));
}
}
+ Separator::Lifetime(punct, ident) => {
+ builder.push(tt::Leaf::from(*punct));
+ builder.push(tt::Leaf::from(ident.clone()));
+ }
};
}
diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs
index fbc353d610..711101260a 100644
--- a/crates/mbe/src/parser.rs
+++ b/crates/mbe/src/parser.rs
@@ -155,6 +155,7 @@ pub(crate) enum Separator {
Literal(tt::Literal<Span>),
Ident(tt::Ident<Span>),
Puncts(ArrayVec<tt::Punct<Span>, MAX_GLUED_PUNCT_LEN>),
+ Lifetime(tt::Punct<Span>, tt::Ident<Span>),
}
// Note that when we compare a Separator, we just care about its textual value.
@@ -170,6 +171,7 @@ impl PartialEq for Separator {
let b_iter = b.iter().map(|b| b.char);
a_iter.eq(b_iter)
}
+ (Lifetime(_, a), Lifetime(_, b)) => a.sym == b.sym,
_ => false,
}
}
@@ -350,10 +352,19 @@ fn parse_repeat(src: &mut TtIter<'_, Span>) -> Result<(Option<Separator>, Repeat
_ => true,
};
match tt {
- tt::Leaf::Ident(_) | tt::Leaf::Literal(_) if has_sep => {
- return Err(ParseError::InvalidRepeat);
- }
- tt::Leaf::Ident(ident) => separator = Separator::Ident(ident.clone()),
+ tt::Leaf::Ident(ident) => match separator {
+ Separator::Puncts(puncts) if puncts.is_empty() => {
+ separator = Separator::Ident(ident.clone());
+ }
+ Separator::Puncts(puncts) => match puncts.as_slice() {
+ [tt::Punct { char: '\'', .. }] => {
+ separator = Separator::Lifetime(puncts[0], ident.clone());
+ }
+ _ => return Err(ParseError::InvalidRepeat),
+ },
+ _ => return Err(ParseError::InvalidRepeat),
+ },
+ tt::Leaf::Literal(_) if has_sep => return Err(ParseError::InvalidRepeat),
tt::Leaf::Literal(lit) => separator = Separator::Literal(lit.clone()),
tt::Leaf::Punct(punct) => {
let repeat_kind = match punct.char {