swc-project/swc · error

swc does not support tuple expressions

Error message

swc does not support tuple expressions

What it means

Swcify in swc_estree_compat converts swc_estree_ast nodes into swc_ecma_ast nodes. TupleExpression (the `#[1, 2]` literal from the Records & Tuples proposal) does not exist in SWC's AST, so the impl uses `Output = Never` and panics on conversion. SWC cannot express this proposal syntax at all.

Source

Thrown at crates/swc_estree_compat/src/swcify/expr.rs:1138

    fn swcify(self, _: &Context) -> Self::Output {
        panic!("swc does not support `PipelinePrimaryTopicReference`")
    }
}

impl Swcify for RecordExpression {
    type Output = Never;

    fn swcify(self, _: &Context) -> Self::Output {
        panic!("swc does not support record expressions")
    }
}

impl Swcify for TupleExpression {
    type Output = Never;

    fn swcify(self, _: &Context) -> Self::Output {
        panic!("swc does not support tuple expressions")
    }
}

impl Swcify for ModuleExpression {
    type Output = Never;

    fn swcify(self, _: &Context) -> Self::Output {
        panic!("swc does not support module expressions")
    }
}

impl Swcify for TSAsExpression {
    type Output = TsAsExpr;

    fn swcify(self, ctx: &Context) -> Self::Output {
        TsAsExpr {
            span: ctx.span(&self.base),
            expr: self.expression.swcify(ctx),

View on GitHub (pinned to 5176682b65)

Solutions

  1. Disable the record-and-tuple syntax plugin in the upstream parser so `#[...]` literals never appear
  2. Pre-lower tuples to arrays (or run a babel transform that compiles them) before swcify
  3. Use swc_ecma_parser to parse the original source instead of converting a foreign ESTree AST
  4. Reject input early by scanning the ESTree JSON for `type: "TupleExpression"`

Example fix

// before
const pair = #[1, 2];    // babel w/ record-and-tuple syntax
ast.swcify(&ctx);         // panics: swc does not support tuple expressions

// after
const pair = [1, 2];     // plain array literal
ast.swcify(&ctx);         // ok
Defensive patterns

Strategy: type-guard

Validate before calling

let mut bad = Vec::new();
find_unsupported(&estree_json, &mut bad); // same walk as error 200
if bad.iter().any(|t| t == "TupleExpression") {
    return Err("tuple literals (#[...]) are not supported by swcify".into());
}

Type guard

fn is_unsupported_estree_type(t: &str) -> bool {
    matches!(
        t,
        "TupleExpression" | "RecordExpression" | "PipelinePrimaryTopicReference"
            | "BindExpression" | "DoExpression" | "ModuleExpression"
    )
}

Try / catch

let out = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
    estree_expr.swcify(&ctx)
}));
if out.is_err() {
    return Err("swcify cannot convert this ESTree tree (tuple/record syntax present)".into());
}

Prevention

When it happens

Trigger: Calling `.swcify(ctx)` on an ESTree tree containing a TupleExpression node, produced when source with `#[...]` tuple literals is parsed with @babel/plugin-syntax-record-and-tuple or an equivalent ESTree parser plugin before conversion to SWC.

Common situations: Babel-to-SWC interop where proposal syntax was not lowered first; enabling experimental parser plugins in a shared config that also feeds swc_estree_compat; test fixtures containing tuple expressions.

Related errors


AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17). Data as JSON: /api/errors/0f5e174162998e02. Report an issue: GitHub.