From 02c7724281a7c16474addb91f69e86b9c2305fb3 Mon Sep 17 00:00:00 2001 From: Dunqing Date: Wed, 25 Dec 2024 09:48:04 +0800 Subject: [PATCH] feat(transformer/class-properties): transform callee that is referred to a private method --- .../es2022/class_properties/private_field.rs | 39 ++++++---- .../snapshots/babel.snap.md | 19 +---- .../snapshots/babel_exec.snap.md | 78 +++++++++---------- 3 files changed, 63 insertions(+), 73 deletions(-) diff --git a/crates/oxc_transformer/src/es2022/class_properties/private_field.rs b/crates/oxc_transformer/src/es2022/class_properties/private_field.rs index 09501076d8993..85270a563ef6a 100644 --- a/crates/oxc_transformer/src/es2022/class_properties/private_field.rs +++ b/crates/oxc_transformer/src/es2022/class_properties/private_field.rs @@ -206,9 +206,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { return; } - let Some((callee, object)) = self.transform_private_field_callee(field_expr, ctx) else { - return; - }; + let (callee, object) = self.transform_private_field_callee(field_expr, ctx); Self::substitute_callee_and_insert_context(call_expr, callee, object, ctx); } @@ -260,7 +258,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { &mut self, field_expr: &mut PrivateFieldExpression<'a>, ctx: &mut TraverseCtx<'a>, - ) -> Option<(Expression<'a>, Expression<'a>)> { + ) -> (Expression<'a>, Expression<'a>) { let ResolvedPrivateProp { prop_binding, class_bindings, @@ -270,12 +268,15 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { is_declaration, } = self.classes_stack.find_private_prop(&field_expr.field); + let prop_ident = prop_binding.create_read_expression(ctx); + if is_method || is_accessor { - return None; + return ( + self.create_assert_class_brand_for_private_method(prop_ident, ctx), + ctx.ast.expression_this(SPAN), + ); }; - let prop_ident = prop_binding.create_read_expression(ctx); - // `(object.#method)()` // ^^^^^^^^^^^^^^^^ is a parenthesized expression let object = ctx.ast.move_expression(field_expr.object.get_inner_expression_mut()); @@ -330,7 +331,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { (get_call, object2) }; - Some(replacement) + replacement } /// Transform assignment to private field. @@ -1152,7 +1153,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { if matches!(ctx.ancestor(1), Ancestor::CallExpressionCallee(_)) { // `(Foo?.#m)();` -> `(Foo === null || Foo === void 0 ? void 0 : _m._.bind(Foo))();` // ^^^^^^^^^^^^ is a call expression, we need to bind the proper context - *expr = self.transform_bindable_private_field(field_expr, ctx).unwrap(); + *expr = self.transform_bindable_private_field(field_expr, ctx); } else { self.transform_private_field_expression(expr, ctx); } @@ -1573,7 +1574,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { ); Some(Expression::from(replacement)) } else { - self.transform_bindable_private_field(field_expr, ctx) + Some(self.transform_bindable_private_field(field_expr, ctx)) } } @@ -1581,8 +1582,8 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { &mut self, field_expr: &mut PrivateFieldExpression<'a>, ctx: &mut TraverseCtx<'a>, - ) -> Option> { - let (callee, context) = self.transform_private_field_callee(field_expr, ctx)?; + ) -> Expression<'a> { + let (callee, context) = self.transform_private_field_callee(field_expr, ctx); // Return `.bind(object)`, to be substituted as tag of tagged template expression let callee = Expression::from(ctx.ast.member_expression_static( @@ -1592,7 +1593,7 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { false, )); let arguments = ctx.ast.vec1(Argument::from(context)); - Some(ctx.ast.expression_call(field_expr.span, callee, NONE, arguments, false)) + ctx.ast.expression_call(field_expr.span, callee, NONE, arguments, false) } /// Transform private field in assignment pattern. @@ -1785,6 +1786,18 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> { ) } + /// `_assertClassBrand(_Class_brand, object, _prop)` + #[inline] + fn create_assert_class_brand_for_private_method( + &self, + value_or_prop_ident: Expression<'a>, + ctx: &mut TraverseCtx<'a>, + ) -> Expression<'a> { + let class_ident = self.current_class().bindings.brand().create_read_expression(ctx); + let object = ctx.ast.expression_this(SPAN); + self.create_assert_class_brand(class_ident, object, value_or_prop_ident, ctx) + } + /// `_assertClassBrand(Class, object, _prop)._` fn create_assert_class_brand_underscore( &self, diff --git a/tasks/transform_conformance/snapshots/babel.snap.md b/tasks/transform_conformance/snapshots/babel.snap.md index 4ba2cd443c1e0..e7752d07b284d 100644 --- a/tasks/transform_conformance/snapshots/babel.snap.md +++ b/tasks/transform_conformance/snapshots/babel.snap.md @@ -1,6 +1,6 @@ commit: 54a8389f -Passed: 623/1095 +Passed: 628/1095 # All Passed: * babel-plugin-transform-logical-assignment-operators @@ -462,7 +462,7 @@ x Output mismatch x Output mismatch -# babel-plugin-transform-private-methods (8/148) +# babel-plugin-transform-private-methods (13/148) * accessors/arguments/input.js x Output mismatch @@ -565,15 +565,6 @@ x Output mismatch * misc/multiple/input.js x Output mismatch -* private-method/assignment/input.js -x Output mismatch - -* private-method/async/input.js -x Output mismatch - -* private-method/before-fields/input.js -x Output mismatch - * private-method/class-binding/input.js x Output mismatch @@ -589,9 +580,6 @@ x Output mismatch * private-method/exfiltrated/input.js x Output mismatch -* private-method/generator/input.js -x Output mismatch - * private-method/read-only/input.js x Output mismatch @@ -601,9 +589,6 @@ x Output mismatch * private-method/super/input.js x Output mismatch -* private-method/tagged-template/input.js -x Output mismatch - * private-method-loose/assignment/input.js x Output mismatch diff --git a/tasks/transform_conformance/snapshots/babel_exec.snap.md b/tasks/transform_conformance/snapshots/babel_exec.snap.md index 1c60618169299..df3224a0c7a50 100644 --- a/tasks/transform_conformance/snapshots/babel_exec.snap.md +++ b/tasks/transform_conformance/snapshots/babel_exec.snap.md @@ -2,7 +2,7 @@ commit: 54a8389f node: v22.12.0 -Passed: 215 of 362 (59.39%) +Passed: 225 of 362 (62.15%) Failures: @@ -62,9 +62,6 @@ TypeError: e.has is not a function at Function.method (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-class-properties-test-fixtures-private-static-shadow-exec.test.js:12:11) at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-class-properties-test-fixtures-private-static-shadow-exec.test.js:16:14 -./fixtures/babel/babel-plugin-transform-class-properties-test-fixtures-private-tagged-template-exec.test.js -Private field '#tag' must be declared in an enclosing class - ./fixtures/babel/babel-plugin-transform-class-properties-test-fixtures-public-computed-toPrimitive-exec.test.js AssertionError: expected [Function] to throw error including '@@toPrimitive must return a primitive…' but got 'Cannot convert object to primitive va…' at Proxy. (./node_modules/.pnpm/@vitest+expect@2.1.2/node_modules/@vitest/expect/dist/index.js:1438:21) @@ -98,7 +95,9 @@ AssertionError: expected [Function Base] to be undefined // Object.is equality Private field '#bar' must be declared in an enclosing class ./fixtures/babel/babel-plugin-transform-class-static-block-test-fixtures-integration-private-methods-access-exec.test.js -Private field '#foo' must be declared in an enclosing class +ReferenceError: _Foo_brand is not defined + at getFoo (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-class-static-block-test-fixtures-integration-private-methods-access-exec.test.js:17:35) + at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-class-static-block-test-fixtures-integration-private-methods-access-exec.test.js:18:9 ./fixtures/babel/babel-plugin-transform-optional-chaining-test-fixtures-assumption-noDocumentAll-parenthesized-expression-member-call-exec.test.js TypeError: Cannot read properties of undefined (reading 'x') @@ -196,23 +195,15 @@ Private field '#privateFieldValue' must be declared in an enclosing class ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-set-only-getter-exec.test.js Private field '#privateFieldValue' must be declared in an enclosing class -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-tagged-template-exec.test.js -Private field '#tag' must be declared in an enclosing class - ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-updates-bigint-exec.test.js Private field '#privateFieldValue' must be declared in an enclosing class ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-accessors-updates-exec.test.js Private field '#privateFieldValue' must be declared in an enclosing class -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-assignment-exec.test.js -Private field '#privateMethod' must be declared in an enclosing class - -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-before-fields-exec.test.js -Private field '#method' must be declared in an enclosing class - ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-class-binding-exec.test.js -Private field '#getA' must be declared in an enclosing class +AssertionError: expected null to be [Function A] // Object.is equality + at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-class-binding-exec.test.js:20:28 ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-context-exec.test.js Private field '#getStatus' must be declared in an enclosing class @@ -220,9 +211,6 @@ Private field '#getStatus' must be declared in an enclosing class ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-exfiltrated-exec.test.js Private field '#privateMethod' must be declared in an enclosing class -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-generator-exec.test.js -Private field '#foo' must be declared in an enclosing class - ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-loose-assignment-exec.test.js Private field '#privateMethod' must be declared in an enclosing class @@ -268,14 +256,9 @@ Private field '#foo' must be declared in an enclosing class ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-privateFieldsAsProperties-super-exec.test.js Invalid access to super -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-privateFieldsAsSymbols-assignment-exec.test.js -Private field '#privateMethod' must be declared in an enclosing class - -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-privateFieldsAsSymbols-before-fields-exec.test.js -Private field '#method' must be declared in an enclosing class - ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-privateFieldsAsSymbols-class-binding-exec.test.js -Private field '#getA' must be declared in an enclosing class +AssertionError: expected null to be [Function A] // Object.is equality + at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-privateFieldsAsSymbols-class-binding-exec.test.js:20:28 ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-privateFieldsAsSymbols-context-exec.test.js Private field '#getStatus' must be declared in an enclosing class @@ -283,9 +266,6 @@ Private field '#getStatus' must be declared in an enclosing class ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-privateFieldsAsSymbols-exfiltrated-exec.test.js Private field '#privateMethod' must be declared in an enclosing class -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-privateFieldsAsSymbols-generator-exec.test.js -Private field '#foo' must be declared in an enclosing class - ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-privateFieldsAsSymbols-super-exec.test.js Invalid access to super @@ -295,26 +275,26 @@ Private field '#method' must be declared in an enclosing class ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-reassignment-exec.test.js Private field '#privateFieldValue' must be declared in an enclosing class -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-scopable-exec.test.js -Private field '#privateMethodA' must be declared in an enclosing class - ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-super-exec.test.js Invalid access to super -./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-method-tagged-template-exec.test.js -Private field '#tag' must be declared in an enclosing class - ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-basic-exec.test.js -Private field '#privateStaticMethod' must be declared in an enclosing class +ReferenceError: _Cl_brand is not defined + at new Cl (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-basic-exec.test.js:21:38) + at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-basic-exec.test.js:28:9 ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-class-check-exec.test.js -Private field '#privateStaticMethod' must be declared in an enclosing class +ReferenceError: _Cl_brand is not defined + at new Cl (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-class-check-exec.test.js:8:38) + at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-class-check-exec.test.js:17:13 ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-exfiltrated-exec.test.js Private field '#privateStaticMethod' must be declared in an enclosing class ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-generator-exec.test.js -Private field '#foo' must be declared in an enclosing class +ReferenceError: _Cl_brand is not defined + at new Cl (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-generator-exec.test.js:8:38) + at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-generator-exec.test.js:18:14 ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-loose-basic-exec.test.js Private field '#privateStaticMethod' must be declared in an enclosing class @@ -365,22 +345,30 @@ Invalid access to super Invalid access to super ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsSymbols-basic-exec.test.js -Private field '#privateStaticMethod' must be declared in an enclosing class +ReferenceError: _Cl_brand is not defined + at new Cl (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsSymbols-basic-exec.test.js:21:38) + at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsSymbols-basic-exec.test.js:28:9 ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsSymbols-class-check-exec.test.js -Private field '#privateStaticMethod' must be declared in an enclosing class +ReferenceError: _Cl_brand is not defined + at new Cl (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsSymbols-class-check-exec.test.js:8:38) + at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsSymbols-class-check-exec.test.js:17:13 ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsSymbols-exfiltrated-exec.test.js Private field '#privateStaticMethod' must be declared in an enclosing class ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsSymbols-generator-exec.test.js -Private field '#foo' must be declared in an enclosing class +ReferenceError: _Cl_brand is not defined + at new Cl (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsSymbols-generator-exec.test.js:8:38) + at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsSymbols-generator-exec.test.js:18:14 ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsSymbols-reassignment-exec.test.js Private field '#privateStaticMethod' must be declared in an enclosing class ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsSymbols-scopable-exec.test.js -Private field '#privateMethodA' must be declared in an enclosing class +ReferenceError: _Cl_brand is not defined + at new Cl (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsSymbols-scopable-exec.test.js:8:38) + at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsSymbols-scopable-exec.test.js:22:9 ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-privateFieldsAsSymbols-super-exec.test.js Invalid access to super @@ -395,13 +383,17 @@ Private field '#method' must be declared in an enclosing class Private field '#privateStaticMethod' must be declared in an enclosing class ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-scopable-exec.test.js -Private field '#privateMethodA' must be declared in an enclosing class +ReferenceError: _Cl_brand is not defined + at new Cl (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-scopable-exec.test.js:8:38) + at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-scopable-exec.test.js:22:9 ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-super-exec.test.js Invalid access to super ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-tagged-template-exec.test.js -Private field '#tag' must be declared in an enclosing class +ReferenceError: _Foo_brand is not defined + at Function.getReceiver (./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-tagged-template-exec.test.js:11:29) + at ./tasks/transform_conformance/fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-tagged-template-exec.test.js:17:13 ./fixtures/babel/babel-plugin-transform-private-methods-test-fixtures-private-static-method-this-exec.test.js Invalid access to super