{"record":{"id":"81b35b1737985e2e","repo":"swc-project/swc","slug":"illegal-conversion-cannot-convert-to-binarye","errorCode":null,"errorMessage":"illegal conversion: Cannot convert {:?} to BinaryExprOp","messagePattern":"illegal conversion: Cannot convert (.+?) to BinaryExprOp","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/swc_estree_compat/src/babelify/operators.rs","lineNumber":17,"sourceCode":"use serde::{Deserialize, Serialize};\nuse swc_ecma_ast::{AssignOp, BinaryOp, UnaryOp, UpdateOp};\nuse swc_estree_ast::{BinaryExprOp, LogicalExprOp, UnaryExprOp, UpdateExprOp};\n\nuse crate::babelify::{Babelify, Context};\n\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub enum BinaryOpOutput {\n    BinOp(BinaryExprOp),\n    LogicOp(LogicalExprOp),\n}\n\nimpl From<BinaryOpOutput> for BinaryExprOp {\n    fn from(o: BinaryOpOutput) -> Self {\n        match o {\n            BinaryOpOutput::BinOp(op) => op,\n            BinaryOpOutput::LogicOp(_) => panic!(\n                \"illegal conversion: Cannot convert {:?} to BinaryExprOp\",\n                &o\n            ),\n        }\n    }\n}\n\nimpl From<BinaryOpOutput> for LogicalExprOp {\n    fn from(o: BinaryOpOutput) -> Self {\n        match o {\n            BinaryOpOutput::LogicOp(op) => op,\n            BinaryOpOutput::BinOp(_) => panic!(\n                \"illegal conversion: Cannot convert {:?} to LogicalExprOp\",\n                &o\n            ),\n        }\n    }\n}","sourceCodeStart":1,"sourceCodeEnd":35,"githubUrl":"https://github.com/swc-project/swc/blob/5176682b65416c6b5de6b47379ae1588ea3ecb3f/crates/swc_estree_compat/src/babelify/operators.rs#L1-L35","documentation":"SWC unifies all binary and logical operators into one BinaryOp enum, but Babel splits them across two node types: BinaryExpression (arithmetic/comparison/bitwise/in/instanceof) and LogicalExpression (&&, ||, ??). BinaryOpOutput carries either a BinOp or a LogicOp, and this From impl converts it to BinaryExprOp, panicking if the value holds the logical kind. The panic means a BinExpr node was built whose operator is logical — a shape the SWC parser never produces, so it originates from programmatic AST construction or a transform.","triggerScenarios":"Constructing a swc_ecma_ast BinExpr with op set to LogicalAnd/LogicalOr/NullishCoalescing (or mutating a BinExpr's op to a logical one) and babelifying it — the `.into()` on the babelified op hits the mismatch.","commonSituations":"Codemods and transforms that flip or swap operators in place; AST-building helpers/macros (e.g. swc_ecma_quote-style constructors) choosing BinExpr for `a || b`; deserializing hand-made ASTs from other tools.","solutions":["Use LogicalExpr (not BinExpr) when the operator is &&, ||, or ??","If a transform rewrites operators, have it swap the node type (BinExpr <-> LogicalExpr) together with the op","Validate before babelify: every BinExpr op must be non-logical, every LogicalExpr op must be logical","Fall back to catch_unwind around babelify to surface a clear error"],"exampleFix":"// before\nBinExpr {\n    op: BinaryOp::LogicalOr,\n    left,\n    right,\n}\n\n// after\nLogicalExpr {\n    op: BinaryOp::LogicalOr,\n    left,\n    right,\n}","handlingStrategy":"type-guard","validationCode":"fn bin_exprs_consistent(program: &Program) -> Result<(), String> {\n    for e in exprs(program) {\n        if let Expr::Bin(b) = e {\n            if matches!(b.op, BinaryOp::LogicalAnd | BinaryOp::LogicalOr | BinaryOp::NullishCoalescing) {\n                return Err(format!(\"BinExpr with logical op {:?} at {:?}\", b.op, b.span));\n            }\n        }\n    }\n    Ok(())\n}","typeGuard":"fn op_is_binary(o: BinaryOp) -> bool {\n    !matches!(o, BinaryOp::LogicalAnd | BinaryOp::LogicalOr | BinaryOp::NullishCoalescing)\n}","tryCatchPattern":"let out = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| program.babelify(&ctx)))\n    .map_err(|_| anyhow::anyhow!(\"illegal conversion: logical operator used in BinaryExpression\"))?;","preventionTips":["Never put &&, ||, or ?? in a BinExpr node","When rewriting operators, switch node type (BinExpr <-> LogicalExpr) in the same step","Assert op-class consistency in transform unit tests","Prefer building expressions via helpers that choose the node type from the operator"],"tags":["swc","babelify","panic","binary-expression","operator-mismatch","illegal-conversion"],"backgroundTag":"operator-kind-mismatch","analyzedSha":"5176682b65416c6b5de6b47379ae1588ea3ecb3f","analyzedAt":"2026-08-17T16:16:52.067Z","contentChangedAt":"2026-08-17T16:16:52.067Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}