fix(transformer/class-properties): handle nested super() calls (#8506)

Similar to #8494. Handle nested `super()` calls in class constructor e.g. `super(self = super())`. Very weird code, but legal!
This commit is contained in:
overlookmotel 2025-01-15 15:09:00 +00:00
parent 7066d1cc4f
commit 356f0c1a6a
6 changed files with 46 additions and 5 deletions

View file

@ -639,9 +639,16 @@ impl<'a, 'ctx> ConstructorBodySuperReplacer<'a, 'ctx> {
if let Statement::ExpressionStatement(expr_stmt) = stmt {
if let Expression::CallExpression(call_expr) = &mut expr_stmt.expression {
if let Expression::Super(super_) = &call_expr.callee {
let span = super_.span;
// Visit arguments in `super(x, y, z)` call.
// Required to handle edge case `super(self = super())`.
self.visit_arguments(&mut call_expr.arguments);
// Found `super()` as top-level statement
if self.super_binding.is_none() {
// This is the first `super()` found.
// This is the first `super()` found
// (and no further `super()` calls within `super()` call's arguments).
// So can just insert initializers after it - no need for `_super` function.
let insert_location =
InstanceInitsInsertLocation::ExistingConstructor(index + 1);
@ -652,7 +659,6 @@ impl<'a, 'ctx> ConstructorBodySuperReplacer<'a, 'ctx> {
// So we do need a `_super` function.
// But we don't need to look any further for any other `super()` calls,
// because calling `super()` after this would be an immediate error.
let span = super_.span;
self.replace_super(call_expr, span);
break 'outer;

View file

@ -1,6 +1,6 @@
commit: acbc09a8
Passed: 130/152
Passed: 131/153
# All Passed:
* babel-plugin-transform-class-static-block
@ -18,7 +18,7 @@ Passed: 130/152
* regexp
# babel-plugin-transform-class-properties (19/26)
# babel-plugin-transform-class-properties (20/27)
* private-field-resolve-to-method/input.js
x Output mismatch

View file

@ -2,7 +2,7 @@ commit: acbc09a8
node: v22.12.0
Passed: 4 of 6 (66.67%)
Passed: 5 of 7 (71.43%)
Failures:

View file

@ -0,0 +1,15 @@
let c;
class S {}
class C extends S {
prop = 123;
constructor() {
super(c = super());
}
}
try { new C() } catch {}
expect(c).toBeInstanceOf(C);
expect(c.prop).toBe(123);

View file

@ -0,0 +1,10 @@
let c;
class S {}
class C extends S {
prop = 123;
constructor() {
super(c = super());
}
}

View file

@ -0,0 +1,10 @@
let c;
class S {}
class C extends S {
constructor() {
var _super = (..._args) => (super(..._args), babelHelpers.defineProperty(this, "prop", 123), this);
_super(c = _super());
}
}