swc-project/swc · error

illegal conversion: Cannot convert {:?} to LogicalExprOp

Error message

illegal conversion: Cannot convert {:?} to LogicalExprOp

What it means

The mirror of the BinaryExprOp conversion: this From impl converts a BinaryOpOutput into LogicalExprOp and panics when the value holds the BinOp kind. Babel represents `a && b` as LogicalExpression and arithmetic/comparison operations as BinaryExpression, so babelifying a LogicalExpr whose operator is non-logical (e.g. `+`) is an inconsistent AST that cannot be converted. The SWC parser never emits this mismatch; it comes from AST construction or transforms that pair the wrong node type with an operator.

Source

Thrown at crates/swc_estree_compat/src/babelify/operators.rs:29

}

impl From<BinaryOpOutput> for BinaryExprOp {
    fn from(o: BinaryOpOutput) -> Self {
        match o {
            BinaryOpOutput::BinOp(op) => op,
            BinaryOpOutput::LogicOp(_) => panic!(
                "illegal conversion: Cannot convert {:?} to BinaryExprOp",
                &o
            ),
        }
    }
}

impl From<BinaryOpOutput> for LogicalExprOp {
    fn from(o: BinaryOpOutput) -> Self {
        match o {
            BinaryOpOutput::LogicOp(op) => op,
            BinaryOpOutput::BinOp(_) => panic!(
                "illegal conversion: Cannot convert {:?} to LogicalExprOp",
                &o
            ),
        }
    }
}

impl Babelify for BinaryOp {
    type Output = BinaryOpOutput;

    fn babelify(self, _ctx: &Context) -> Self::Output {
        match self {
            BinaryOp::EqEq => BinaryOpOutput::BinOp(BinaryExprOp::Equal),
            BinaryOp::NotEq => BinaryOpOutput::BinOp(BinaryExprOp::NotEqual),
            BinaryOp::EqEqEq => BinaryOpOutput::BinOp(BinaryExprOp::StrictEqual),
            BinaryOp::NotEqEq => BinaryOpOutput::BinOp(BinaryExprOp::StrictNotEqual),
            BinaryOp::Lt => BinaryOpOutput::BinOp(BinaryExprOp::LessThan),
            BinaryOp::LtEq => BinaryOpOutput::BinOp(BinaryExprOp::LessThanOrEqual),

View on GitHub (pinned to 5176682b65)

Solutions

  1. Pair the node type with the operator class: LogicalExpr only for &&/||/??, BinExpr for everything else
  2. Fix transforms to change the node type when they change the operator class
  3. Validate the AST before babelify with a check that BinExpr/LogicalExpr ops are in the right class
  4. Wrap the conversion in catch_unwind as a last-resort guard

Example fix

// before
LogicalExpr {
    op: BinaryOp::Add,
    left,
    right,
}

// after
BinExpr {
    op: BinaryOp::Add,
    left,
    right,
}
Defensive patterns

Strategy: type-guard

Validate before calling

fn logical_exprs_consistent(program: &Program) -> Result<(), String> {
    for e in exprs(program) {
        if let Expr::Logical(l) = e {
            if !matches!(l.op, BinaryOp::LogicalAnd | BinaryOp::LogicalOr | BinaryOp::NullishCoalescing) {
                return Err(format!("LogicalExpr with non-logical op {:?} at {:?}", l.op, l.span));
            }
        }
    }
    Ok(())
}

Type guard

fn op_is_logical(o: BinaryOp) -> bool {
    matches!(o, BinaryOp::LogicalAnd | BinaryOp::LogicalOr | BinaryOp::NullishCoalescing)
}

Try / catch

let out = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| program.babelify(&ctx)))
    .map_err(|_| anyhow::anyhow!("illegal conversion: non-logical operator used in LogicalExpression"))?;

Prevention

When it happens

Trigger: Constructing a swc_ecma_ast LogicalExpr with op set to a non-logical operator such as Add or Eq (or rewriting a LogicalExpr's op in place) and then babelifying the expression.

Common situations: Operator-rewriting codemods that keep the node type fixed; AST builder utilities defaulting to LogicalExpr; hand-written test fixtures with inconsistent node/op pairings.

Related errors


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