mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +00:00
fix(transformer/arrow-functions): visit arguments to super() call (#8494)
Follow-on after #8482. Fix an edge case in arrow functions transform when inserting `_this = this` after `super()`. It is possible (though bizarre) for `super()` to contain another `super()` call. This will throw an error when evaluating the outer `super()`, but it can still be observable in some cases. ```js let f; class S {} class C extends S { constructor(x) { super(super(), this.x = x, f = async () => this); } } try { new C(123) } catch {} const c = await f(); assert(c.x === 123); ``` So, before bailing out from searching for more `super()`s in class constructor, visit the `super()` call's arguments.
This commit is contained in:
parent
ca02c16f8f
commit
99635330c7
6 changed files with 65 additions and 14 deletions
|
|
@ -1313,18 +1313,27 @@ impl<'a> VisitMut<'a> for ConstructorBodyThisAfterSuperInserter<'a, '_> {
|
|||
/// `super();` -> `super(); _this = this;`
|
||||
fn visit_statements(&mut self, statements: &mut ArenaVec<'a, Statement<'a>>) {
|
||||
for (index, stmt) in statements.iter_mut().enumerate() {
|
||||
if matches!(stmt, Statement::ExpressionStatement(expr_stmt) if expr_stmt.expression.is_super_call_expression())
|
||||
{
|
||||
let assignment = self.create_assignment_to_this_temp_var();
|
||||
let assignment = self.ctx.ast.statement_expression(SPAN, assignment);
|
||||
statements.insert(index + 1, assignment);
|
||||
// `super();` found as top-level statement in this block of statements.
|
||||
// No need to continue visiting later statements, because `_this` is definitely assigned
|
||||
// to at this point - no need to assign to it again.
|
||||
// This means we don't visit the whole constructor in the common case where `super();`
|
||||
// appears as a top-level statement early in class constructor
|
||||
// `constructor() { super(); blah; blah; blah; }`.
|
||||
break;
|
||||
if let Statement::ExpressionStatement(expr_stmt) = stmt {
|
||||
if let Expression::CallExpression(call_expr) = &mut expr_stmt.expression {
|
||||
if matches!(&call_expr.callee, Expression::Super(_)) {
|
||||
// Visit arguments in `super(x, y, z)` call.
|
||||
// Required to handle edge case `super(super(), f = () => this)`.
|
||||
self.visit_arguments(&mut call_expr.arguments);
|
||||
|
||||
// Insert `_this = this;` after `super();`
|
||||
let assignment = self.create_assignment_to_this_temp_var();
|
||||
let assignment = self.ctx.ast.statement_expression(SPAN, assignment);
|
||||
statements.insert(index + 1, assignment);
|
||||
|
||||
// `super();` found as top-level statement in this block of statements.
|
||||
// No need to continue visiting later statements, because `_this` is definitely
|
||||
// assigned to at this point - no need to assign to it again.
|
||||
// This means we don't visit the whole constructor in the common case where
|
||||
// `super();` appears as a top-level statement early in class constructor
|
||||
// `constructor() { super(); blah; blah; blah; }`.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.visit_statement(stmt);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
commit: 54a8389f
|
||||
|
||||
Passed: 129/151
|
||||
Passed: 130/152
|
||||
|
||||
# All Passed:
|
||||
* babel-plugin-transform-class-static-block
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ commit: 54a8389f
|
|||
|
||||
node: v22.12.0
|
||||
|
||||
Passed: 3 of 5 (60.00%)
|
||||
Passed: 4 of 6 (66.67%)
|
||||
|
||||
Failures:
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
let f;
|
||||
|
||||
class S {}
|
||||
|
||||
class C extends S {
|
||||
constructor(x) {
|
||||
super(super(), this.x = x, f = async () => this);
|
||||
}
|
||||
}
|
||||
|
||||
try { new C(123) } catch {}
|
||||
|
||||
return f().then((c) => {
|
||||
expect(c).toBeInstanceOf(C);
|
||||
expect(c.x).toBe(123);
|
||||
});
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
let f;
|
||||
|
||||
class S {}
|
||||
|
||||
class C extends S {
|
||||
constructor(x) {
|
||||
super(super(), this.x = x, f = async () => this);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
let f;
|
||||
|
||||
class S {}
|
||||
|
||||
class C extends S {
|
||||
constructor(x) {
|
||||
var _this;
|
||||
super(
|
||||
(super(), _this = this),
|
||||
this.x = x,
|
||||
f = babelHelpers.asyncToGenerator(function* () {
|
||||
return _this;
|
||||
})
|
||||
);
|
||||
_this = this;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue