swc-project/swc · error · anyhow::Error

{err:?}

Error message

{err:?}

What it means

Compile-time error from swc_ecma_quote_macros: the tokens passed to a quote_*! macro could not be parsed as the expected Rust type T (an SWC AST node). The anyhow error wraps the parser's debug-formatted error and the with_context layer adds 'failed to parse input as `<T>`'. It fires during proc-macro expansion, so it breaks the build of the crate using the macro.

Source

Thrown at crates/swc_ecma_quote_macros/src/ret_type.rs:75

fn parse<T>(
    input_str: &str,
    op: &mut dyn FnMut(&mut Parser<Lexer>) -> PResult<T>,
) -> Result<BoxWrapper, Error>
where
    T: ToCode,
{
    let cm = Lrc::new(SourceMap::default());
    let fm = cm.new_source_file(FileName::Anon.into(), input_str.to_string());

    let lexer = Lexer::new(
        Default::default(),
        EsVersion::Es2020,
        StringInput::from(&*fm),
        None,
    );
    let mut parser = Parser::new_from(lexer);
    op(&mut parser)
        .map_err(|err| anyhow!("{err:?}"))
        .with_context(|| format!("failed to parse input as `{}`", type_name::<T>()))
        .map(|val| BoxWrapper(Box::new(val)))
}

fn extract_generic<'a>(name: &str, ty: &'a Type) -> Option<&'a Type> {
    if let Type::Path(p) = ty {
        let last = p.path.segments.last().unwrap();

        if !last.arguments.is_empty() && last.ident == name {
            match &last.arguments {
                PathArguments::AngleBracketed(tps) => {
                    let arg = tps.args.first().unwrap();

                    match arg {
                        GenericArgument::Type(arg) => return Some(arg),
                        _ => unimplemented!("generic parameter other than type"),
                    }
                }

View on GitHub (pinned to d7d7434666)

Solutions

  1. Make the quoted content exactly one valid instance of the macro's target type (one expression for quote_expr!, one statement for quote_stmt!, ...)
  2. Wrap multiple items appropriately or split into several macro invocations
  3. Check the macro name against the content - statements/declarations do not parse as expressions
  4. Read the {err:?} payload: it names the unexpected token

Example fix

// before: two expressions inside quote_expr!
let e = quote_expr!(&ctx, foo() bar());

// after: a single expression
let e = quote_expr!(&ctx, foo());
Defensive patterns

Strategy: validation

Validate before calling

// Rust: validate quoted snippets during development with a test
// that expands the macro and asserts it parses
#[test]
fn quoted_snippets_parse() {
    let _ = quote_expr!(&ctx, foo() + 1);   // compile of the test itself is the validation
    let _ = quote_stmt!(&ctx, let x = 1;);
}

Prevention

When it happens

Trigger: Using quote_expr!, quote_stmt!, quote_ident!, quote_type!, etc. with token soup that is not a valid single production of the target AST type - e.g. two expressions where one is expected, statements passed to quote_expr!, reserved words used as identifiers, or TS-only syntax inside a macro targeting an ECMAScript node.

Common situations: Writing transforms that embed JS snippets via quote macros; refactoring a quoted snippet so it is no longer a single valid expression/statement; copy-pasting multiline JS into a macro that expects one node.

Related errors


AI-assisted analysis of swc-project/swc@d7d7434666 (2026-08-16). Data as JSON: /api/errors/591daaa4cc970730. Report an issue: GitHub.