Skip to content

Macro is accepted by rustc but R-A complains "Expected token tree" #21148

@kythyria

Description

@kythyria

rust-analyzer version: 0.4.2697-standalone (71ddf07 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:

Image

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-macromacro expansionC-bugCategory: bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions