{"record":{"id":"9db8edeeade969b7","repo":"swc-project/swc","slug":"illegal-conversion-cannot-convert-to-express","errorCode":null,"errorMessage":"illegal conversion: Cannot convert {:?} to Expression - babel has no equivalent","messagePattern":"illegal conversion: Cannot convert (.+?) to Expression - babel has no equivalent","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/swc_estree_compat/src/babelify/expr.rs","lineNumber":184,"sourceCode":"            Expr::OptChain(_) => panic!(\n                \"illegal conversion: Cannot convert {:?} to ExprOutput - babel has no equivalent\",\n                &self\n            ),\n            Expr::Invalid(_) => panic!(\n                \"illegal conversion: Cannot convert {:?} to ExprOutput - babel has no equivalent\",\n                &self\n            ),\n            #[cfg(swc_ast_unknown)]\n            _ => panic!(\"unable to access unknown nodes\"),\n        }\n    }\n}\n\nimpl From<ExprOutput> for Expression {\n    fn from(o: ExprOutput) -> Self {\n        match o {\n            ExprOutput::Expr(expr) => *expr,\n            ExprOutput::Private(_) => panic!(\n                \"illegal conversion: Cannot convert {:?} to Expression - babel has no equivalent\",\n                &o\n            ),\n        }\n    }\n}\n\nimpl From<ExprOutput> for BinaryExprLeft {\n    fn from(o: ExprOutput) -> Self {\n        match o {\n            ExprOutput::Expr(e) => BinaryExprLeft::Expr(e),\n            ExprOutput::Private(p) => BinaryExprLeft::Private(p),\n        }\n    }\n}\n\nimpl From<ExprOutput> for ObjectKey {\n    fn from(o: ExprOutput) -> Self {","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/swc-project/swc/blob/5176682b65416c6b5de6b47379ae1588ea3ecb3f/crates/swc_estree_compat/src/babelify/expr.rs#L166-L202","documentation":"babelify of expressions returns ExprOutput — either a normal Expression or a PrivateName (`#foo`). Babel's Expression union has no PrivateName member, so `From<ExprOutput> for Expression` (expr.rs:180-189) panics when a PrivateName lands in a slot typed as a plain Expression (object property values, call arguments, etc.). Babel only permits private names in two expression contexts: the left side of `#x in obj` and member properties like `this.#x`.","triggerScenarios":"Babelifying an AST where a PrivateName appears as a general expression value — practically only from plugins/codemods or hand-built ASTs, since the parser rejects `#x` in value positions (BinaryExprLeft, in contrast, is converted losslessly at expr.rs:192+).","commonSituations":"Codemods moving private names around; AST fixtures exercising private class members.","solutions":["Keep private names only in `#x in obj` left-side or member-property positions.","Fix the producer (plugin/builder) that placed a PrivateName into a plain expression slot.","Pre-scan the AST for PrivateName in Expression-typed positions and reject with a span."],"exampleFix":"// before: private name in a value slot (invalid)\nProp::KeyValue(KeyValueProp { key: k, value: Expr::PrivateName(p) })\n\n// after: keep it in a supported position\nExpr::Bin(BinExpr { op: op!(in), left: Box::new(Expr::PrivateName(p)), right, .. })","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"// PrivateName is only legal as `#x in obj` left side or member property.\nfn has_private_name_in_value(program: &Program) -> bool {\n    struct Scan(bool);\n    impl Visit for Scan {\n        fn visit_expr(&mut self, e: &Expr) {\n            if let Expr::PrivateName(_) = e {\n                // reaching generic expression traversal at all means it is\n                // outside the supported positions\n                self.0 = true;\n            }\n            e.visit_children_with(self);\n        }\n        fn visit_member_expr(&mut self, m: &MemberExpr) {\n            m.obj.visit_with(self); // PrivateName member props handled elsewhere\n        }\n    }\n    let mut s = Scan(false);\n    program.visit_with(&mut s);\n    s.0\n}","tryCatchPattern":null,"preventionTips":["Keep `#x` usages limited to `#x in obj` and `this.#x` member accesses.","In plugins, never emit Expr::PrivateName into argument/value slots.","Test private-member code paths through the converter explicitly."],"tags":["swc","estree","babelify","private-name","panic"],"backgroundTag":"ast-conversion-unsupported-node","analyzedSha":"5176682b65416c6b5de6b47379ae1588ea3ecb3f","analyzedAt":"2026-08-17T16:16:52.067Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}