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
- Pair the node type with the operator class: LogicalExpr only for &&/||/??, BinExpr for everything else
- Fix transforms to change the node type when they change the operator class
- Validate the AST before babelify with a check that BinExpr/LogicalExpr ops are in the right class
- 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
- Reserve LogicalExpr for &&, ||, ?? only
- Make operator-rewriting transforms also fix the node type
- Validate AST shape before babelify in codemod pipelines
- Cover both node types in fixture tests for expression builders
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
- illegal conversion: Cannot convert {:?} to BinaryExprOp
- illegal conversion: Cannot convert {:?} to Prop
- illegal conversion: Cannot convert {:?} to Prop::KeyValue
- illegal conversion: Cannot convert {:?} to Expr::Lit
- illegal conversion: Cannot convert {:?} to key, value
AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17).
Data as JSON: /api/errors/9ef58a31be816998.
Report an issue: GitHub.