Unnamed repository; edit this file 'description' to name the repository.
fix: Fix macro transcriber emitting incorrect lifetime tokens
Lukas Wirth 2024-02-11
parent ddf105b · commit c990587
-rw-r--r--crates/hir-def/src/macro_expansion_tests/mbe/regression.rs54
-rw-r--r--crates/mbe/src/expander/transcriber.rs18
-rw-r--r--crates/mbe/src/syntax_bridge.rs6
-rw-r--r--crates/tt/src/lib.rs1
4 files changed, 73 insertions, 6 deletions
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 6717ee1aa5..4aad53c3bd 100644
--- a/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
+++ b/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
@@ -1090,3 +1090,57 @@ fn main() {
"#]],
);
}
+
+#[test]
+fn regression_16529() {
+ check(
+ r#"
+mod any {
+ #[macro_export]
+ macro_rules! nameable {
+ {
+ struct $name:ident[$a:lifetime]
+ } => {
+ $crate::any::nameable! {
+ struct $name[$a]
+ a
+ }
+ };
+ {
+ struct $name:ident[$a:lifetime]
+ a
+ } => {};
+ }
+ pub use nameable;
+
+ nameable! {
+ Name['a]
+ }
+}
+"#,
+ expect![[r#"
+mod any {
+ #[macro_export]
+ macro_rules! nameable {
+ {
+ struct $name:ident[$a:lifetime]
+ } => {
+ $crate::any::nameable! {
+ struct $name[$a]
+ a
+ }
+ };
+ {
+ struct $name:ident[$a:lifetime]
+ a
+ } => {};
+ }
+ pub use nameable;
+
+ /* error: unexpected token in input */$crate::any::nameable! {
+ struct $name[$a]a
+ }
+}
+"#]],
+ );
+}
diff --git a/crates/mbe/src/expander/transcriber.rs b/crates/mbe/src/expander/transcriber.rs
index 9291f799cc..6d3055da28 100644
--- a/crates/mbe/src/expander/transcriber.rs
+++ b/crates/mbe/src/expander/transcriber.rs
@@ -101,10 +101,20 @@ impl<S: Span> Bindings<S> {
})))
}
MetaVarKind::Lifetime => {
- Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
- text: SmolStr::new_static("'missing"),
- span,
- })))
+ Fragment::Tokens(tt::TokenTree::Subtree(tt::Subtree {
+ delimiter: tt::Delimiter::invisible_spanned(span),
+ token_trees: Box::new([
+ tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
+ char: '\'',
+ span,
+ spacing: tt::Spacing::Joint,
+ })),
+ tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
+ text: SmolStr::new_static("missing"),
+ span,
+ })),
+ ]),
+ }))
}
MetaVarKind::Literal => {
Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs
index bfc5d197f6..3c270e30a9 100644
--- a/crates/mbe/src/syntax_bridge.rs
+++ b/crates/mbe/src/syntax_bridge.rs
@@ -700,10 +700,12 @@ impl<S> SynToken<S> {
}
impl<SpanMap, S: std::fmt::Debug> SrcToken<Converter<SpanMap, S>, S> for SynToken<S> {
- fn kind(&self, ctx: &Converter<SpanMap, S>) -> SyntaxKind {
+ fn kind(&self, _ctx: &Converter<SpanMap, S>) -> SyntaxKind {
match self {
SynToken::Ordinary(token) => token.kind(),
- SynToken::Punct { .. } => SyntaxKind::from_char(self.to_char(ctx).unwrap()).unwrap(),
+ SynToken::Punct { token, offset: i } => {
+ SyntaxKind::from_char(token.text().chars().nth(*i).unwrap()).unwrap()
+ }
SynToken::Leaf(_) => {
never!();
SyntaxKind::ERROR
diff --git a/crates/tt/src/lib.rs b/crates/tt/src/lib.rs
index 9004bff53a..eec88f8068 100644
--- a/crates/tt/src/lib.rs
+++ b/crates/tt/src/lib.rs
@@ -152,6 +152,7 @@ pub struct Punct<S> {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Spacing {
Alone,
+ /// Whether the following token is joint to the current one.
Joint,
}