From f52b1db821223d411ae57a9220e35da4a8ce5d7f Mon Sep 17 00:00:00 2001 From: Dunqing <29533304+Dunqing@users.noreply.github.com> Date: Tue, 10 Dec 2024 10:35:04 +0000 Subject: [PATCH] fix(transformer/class-properties): output is not the same with Babel when callee has optional (#7748) Part of https://github.com/oxc-project/oxc/pull/7749. It is just an output mismatch problem, not affecting runtime behavior. --- .../src/es2022/class_properties/private.rs | 39 +++++++++++++------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/crates/oxc_transformer/src/es2022/class_properties/private.rs b/crates/oxc_transformer/src/es2022/class_properties/private.rs index 93b256a000b47..84a0ccbee4509 100644 --- a/crates/oxc_transformer/src/es2022/class_properties/private.rs +++ b/crates/oxc_transformer/src/es2022/class_properties/private.rs @@ -1299,22 +1299,37 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { ) -> Expression<'a> { let Expression::CallExpression(call) = expr else { unreachable!() }; - let callee = &mut call.callee; // `Foo?.bar()?.zoo?.()` - // ^^^^^^^^^^^^^^^^^ callee is a member expression // ^^^^^^^^^^^ object - let object = callee.to_member_expression_mut().object_mut(); + // ^^^^^^^^^^^^^^^^^ callee is a member expression + let callee = &mut call.callee; + let callee_member = callee.to_member_expression_mut(); + let is_optional_callee = callee_member.optional(); + let object = callee_member.object_mut(); let context = if let Some(result) = self.transform_chain_element_recursively(object, ctx) { - // `o?.Foo.#self.getSelf?.().#m?.();` -> `(_ref = o === null || o === void 0 ? void 0 : (_babelHelpers$assertC = - // babelHelpers.assertClassBrand(Foo, o.Foo, _self)._).getSelf)` - // ^^^^^^^^^^^^^^^^^^^^^^ to make sure get `getSelf` call has a proper context, we need to assign - // the parent of callee (i.e `o?.Foo.#self`) to a temp variable, - // and then use it as a first argument of `_ref.call`. - let (assignment, context) = self.duplicate_object(ctx.ast.move_expression(object), ctx); - *object = assignment; - *callee = Self::wrap_conditional_check(result, ctx.ast.move_expression(callee), ctx); - context + if is_optional_callee { + // `o?.Foo.#self?.getSelf?.().#x;` -> `(_ref$getSelf = (_ref2 = _ref = o === null || o === void 0 ? + // ^^ is optional void 0 : babelHelpers.assertClassBrand(Foo, o.Foo, _self)._)` + *object = + Self::wrap_conditional_check(result, ctx.ast.move_expression(object), ctx); + let (assignment, context) = + self.duplicate_object(ctx.ast.move_expression(object), ctx); + *object = assignment; + context + } else { + // `o?.Foo.#self.getSelf?.().#m?.();` -> `(_ref = o === null || o === void 0 ? void 0 : (_babelHelpers$assertC = + // babelHelpers.assertClassBrand(Foo, o.Foo, _self)._).getSelf)` + // ^^^^^^^^^^^^^^^^^^^^^^ to make sure get `getSelf` call has a proper context, we need to assign + // the parent of callee (i.e `o?.Foo.#self`) to a temp variable, + // and then use it as a first argument of `_ref.call`. + let (assignment, context) = + self.duplicate_object(ctx.ast.move_expression(object), ctx); + *object = assignment; + *callee = + Self::wrap_conditional_check(result, ctx.ast.move_expression(callee), ctx); + context + } } else { // `Foo?.bar()?.zoo?.().#x;` -> `(_Foo$bar$zoo = (_Foo$bar = Foo?.bar())?.zoo)` // ^^^^^^^^^^^^^^^^ this is a optional function call, to make sure it has a proper context,