From 63b2501d275c88f435cdef0efbfacc017855f5da Mon Sep 17 00:00:00 2001 From: Dunqing Date: Wed, 8 Jan 2025 15:05:14 +0800 Subject: [PATCH] fix(transformer/arrow-functions): do not transform super that inside nested non-async method --- .../src/common/arrow_function_converter.rs | 34 ++++++++++++++++--- .../snapshots/oxc.snap.md | 8 +++-- .../test/fixtures/super/nested-claas/input.js | 18 ++++++++++ .../fixtures/super/nested-claas/output.js | 27 +++++++++++++++ .../test/fixtures/super/nested/input.js | 3 ++ .../test/fixtures/super/nested/output.js | 3 ++ 6 files changed, 86 insertions(+), 7 deletions(-) create mode 100644 tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/nested-claas/input.js create mode 100644 tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/nested-claas/output.js diff --git a/crates/oxc_transformer/src/common/arrow_function_converter.rs b/crates/oxc_transformer/src/common/arrow_function_converter.rs index 42d7138301021f..0e7374efb0b245 100644 --- a/crates/oxc_transformer/src/common/arrow_function_converter.rs +++ b/crates/oxc_transformer/src/common/arrow_function_converter.rs @@ -93,7 +93,7 @@ use rustc_hash::{FxBuildHasher, FxHashSet}; use oxc_allocator::{Box as ArenaBox, Vec as ArenaVec}; use oxc_ast::{ast::*, visit::walk_mut::walk_expression, VisitMut, NONE}; -use oxc_data_structures::stack::{NonEmptyStack, SparseStack, Stack}; +use oxc_data_structures::stack::{NonEmptyStack, SparseStack}; use oxc_semantic::{ReferenceFlags, SymbolId}; use oxc_span::{CompactStr, GetSpan, SPAN}; use oxc_syntax::{ @@ -144,7 +144,7 @@ pub struct ArrowFunctionConverter<'a> { renamed_arguments_symbol_ids: FxHashSet, // TODO(improve-on-babel): `FxHashMap` would suffice here. Iteration order is not important. // Only using `FxIndexMap` for predictable iteration order to match Babel's output. - super_methods_stack: Stack, SuperMethodInfo<'a>>>, + super_methods_stack: SparseStack, SuperMethodInfo<'a>>>, } impl ArrowFunctionConverter<'_> { @@ -164,7 +164,7 @@ impl ArrowFunctionConverter<'_> { constructor_super_stack: NonEmptyStack::new(false), arguments_needs_transform_stack: NonEmptyStack::new(false), renamed_arguments_symbol_ids: FxHashSet::default(), - super_methods_stack: Stack::new(), + super_methods_stack: SparseStack::new(), } } } @@ -208,9 +208,33 @@ impl<'a> Traverse<'a> for ArrowFunctionConverter<'a> { self.this_var_stack.push(None); self.arguments_var_stack.push(None); self.constructor_super_stack.push(false); - if self.is_async_only() && func.r#async && Self::is_class_method_like_ancestor(ctx.parent()) + + if self.is_async_only() + && (func.r#async || + // is used to confirm if it is a nested class method. + self.super_methods_stack.len() != 0) + && Self::is_class_method_like_ancestor(ctx.parent()) { - self.super_methods_stack.push(FxIndexMap::default()); + // Only `super` that inside async methods need to be transformed, if it is a + // nested class method and it is not async, we still need to push a `None` to + // `self.super_methods_stack`, because if we don't get a `FxIndexMap` from + // `self.super_methods_stack.last_mut()`, that means we don't need to transform. + // See how to transform `super` in `self.transform_member_expression_for_super` + // + // ```js + // class Outer { + // async method() { + // class Inner extends Outer { + // normal() { + // // `super.value` should not be transformed, because it is not in an async method + // super.value + // } + // } + // } + // } + // ``` + let super_methods = if func.r#async { Some(FxIndexMap::default()) } else { None }; + self.super_methods_stack.push(super_methods); } } diff --git a/tasks/transform_conformance/snapshots/oxc.snap.md b/tasks/transform_conformance/snapshots/oxc.snap.md index 8c4c1e30b1e2b4..167bfce8e293f8 100644 --- a/tasks/transform_conformance/snapshots/oxc.snap.md +++ b/tasks/transform_conformance/snapshots/oxc.snap.md @@ -1,6 +1,6 @@ commit: 54a8389f -Passed: 123/141 +Passed: 122/141 # All Passed: * babel-plugin-transform-class-static-block @@ -9,7 +9,6 @@ Passed: 123/141 * babel-plugin-transform-optional-catch-binding * babel-plugin-transform-async-generator-functions * babel-plugin-transform-object-rest-spread -* babel-plugin-transform-async-to-generator * babel-plugin-transform-exponentiation-operator * babel-plugin-transform-arrow-functions * babel-preset-typescript @@ -46,6 +45,11 @@ after transform: SymbolId(0): [ReferenceId(0), ReferenceId(2), ReferenceId(6), R rebuilt : SymbolId(0): [ReferenceId(0), ReferenceId(2), ReferenceId(6), ReferenceId(10)] +# babel-plugin-transform-async-to-generator (17/18) +* super/nested/input.js +x Output mismatch + + # babel-plugin-transform-typescript (2/10) * class-property-definition/input.ts Unresolved references mismatch: diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/nested-claas/input.js b/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/nested-claas/input.js new file mode 100644 index 00000000000000..fc4aecdb6464c5 --- /dev/null +++ b/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/nested-claas/input.js @@ -0,0 +1,18 @@ +class Root {} +class Outer extends Root { + value = 0 + async method() { + () => super.value; + + class Inner extends Outer { + normal() { + console.log(super.value); + } + async method() { + () => super.value; + } + }; + + () => super.value; + } +}; diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/nested-claas/output.js b/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/nested-claas/output.js new file mode 100644 index 00000000000000..adf407c2734f5d --- /dev/null +++ b/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/nested-claas/output.js @@ -0,0 +1,27 @@ +class Root {} +class Outer extends Root { + constructor(...args) { + super(...args); + babelHelpers.defineProperty(this, "value", 0); + } + method() { + var _superprop_getValue = () => super.value; + return babelHelpers.asyncToGenerator(function* () { + () => _superprop_getValue(); + class Inner extends Outer { + normal() { + console.log(super.value); + } + method() { + var _superprop_getValue2 = () => super.value; + return babelHelpers.asyncToGenerator(function* () { + () => _superprop_getValue2(); + })(); + } + } + ; + () => _superprop_getValue(); + })(); + } +} +; \ No newline at end of file diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/nested/input.js b/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/nested/input.js index a1a511671b7b95..94dc1ecfef3ab8 100644 --- a/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/nested/input.js +++ b/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/nested/input.js @@ -5,6 +5,9 @@ const outer = { const inner = { value: 0, + normal() { + console.log(super.value); + }, async method() { () => super.value; } diff --git a/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/nested/output.js b/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/nested/output.js index 16c7b41c9fa559..e89939ac3ccbf9 100644 --- a/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/nested/output.js +++ b/tasks/transform_conformance/tests/babel-plugin-transform-async-to-generator/test/fixtures/super/nested/output.js @@ -8,6 +8,9 @@ const outer = { const inner = { value: 0, + normal() { + console.log(super.value); + }, method() { var _superprop_getValue2 = () => super.value; return babelHelpers.asyncToGenerator(function* () {