rust-lang / rust-lang/rust-analyzer
Macro is accepted by rustc but R-A complains "Expected token tree"
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 16.9k
- Forks
- 2.2k
- Avg merge
- 1d 12h
- Merged PRs (30d)
- 72
Description
rust-analyzer version: 0.4.2697-standalone (71ddf07c1c 2025-11-26)
rustc version: rustc 1.91.1 (ed61e7d7e 2025-11-07)
editor or extension: VSCode 1.98.2, R-A extension 0.4.2697 (pre-release channel)
I originally saw the problem in https://codeberg.org/T0mstone/qq/src/commit/ec0f111f3e098c832011db3c1dc6ec7d3c479b31/src/lib.rs#L544 , which compiles just fine--and the test passes--but R-A complains of expected token tree.
Hand-reduced version that still exhibits the problem
pub enum QuoteEither<L, R> {
Left(L),
Right(R),
}
pub struct QuoteBuilder<T>(T);
impl QuoteBuilder<()> {
pub fn new() -> Self {
Self(())
}
}
impl<T> QuoteBuilder<T> {
pub fn chain<U>(self, u: U) -> QuoteBuilder<(T, U)> {
QuoteBuilder((self.0, u))
}
}
pub struct Literal(pub &'static str);
#[macro_export]
macro_rules! qq {
($($t:tt)*) => {
$crate::qq_impl!($crate::QuoteBuilder::new(), $($t)*)
};
}
#[macro_export]
macro_rules! qq_impl {
($b:expr, /* end */) => { $b.0 };
($b:expr, ~match $e:tt { $($p:pat $(if $g:expr)? => {$($body:tt)*}$(,)?)* } $($r:tt)*) => {
$crate::qq_impl!(
$b.chain($crate::qq_match_enum!{$e x {} {} $($p $(if $g)? => {$($body)*})*}),
$($r)*
)
};
($b:expr, $i:ident $($r:tt)*) => {
$crate::qq_impl!(
$b.chain($crate::Literal(::std::stringify!($i))),
$($r)*
)
};
($b:expr, = $($r:tt)*) => {
$crate::qq_impl!(
$b.chain($crate::Literal("=")),
$($r)*
)
};
($b:expr, $t:tt $($r:tt)*) => {
$crate::qq_impl!(
$b.chain($crate::Literal($crate::__private::stringify!($t))),
$($r)*
)
};
}
#[macro_export]
macro_rules! qq_match_enum {
($e:tt $_x:ident {} {} /* empty */) => {
match $e {}
};
($e:tt $x:ident {$($p:pat $(if $g:expr)? => $v:expr,)*} {$($wrap:stmt;)*} $pf:pat $(if $gf:expr)? => {$($body:tt)*}$(,)? /* end */) => {
match $e {
$($p $(if $g)? => $v,)*
$pf $(if $gf)? => {
let $x = $crate::qq!($($body)*);
$($wrap)*
$x
}
}
};
($e:tt $x:ident {$($prev:tt)*} {$($wrap:stmt;)*} $p:pat $(if $g:expr)? => {$($body:tt)*}$(,)? $($r:tt)+) => {
$crate::qq_match_enum!{$e $x
{$($prev)* $p $(if $g)? => {
let $x = $crate::QuoteEither::Left($crate::qq!($($body)*));
$($wrap)*
$x
},}
{$($wrap;)* let $x = $crate::QuoteEither::Right($x);}
$($r)+
}
};
}
#[allow(unused)]
fn repetition_and_match() {
let a = 3u8;
let _e = qq!(let y = ~match a { 1 => { a }, 2 => { b }, _ => { x = c } } );
}
In addition, the span given to VSC for the error is a little strange, even after editor restarts:
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the hand-reduced Rust macro example in the issue and compare rustc's result with rust-analyzer's expected token tree diagnostic and reported span. Trace the macro-parsing path that handles the nested qq_impl! and qq_match_enum! invocations; done means the valid example has no false diagnostic and the error span is correct when a real error exists.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100