fix(transformer/class-properties): use UID for args in created class constructor (#7866)

When creating class constructor for a class which has super class, use UID `_args` for temp var (rather than `args`). This avoids shadowing a var called `args` used in an instance property initializer.

This diverges from Babel. Babel uses `args` unless it finds a var called `args` in an instance property initializer. But searching the AST of initializers can be fairly expensive, so it's better to skip it. The overrides for test fixtures included in this PR are just to account for that difference.
This commit is contained in:
overlookmotel 2024-12-14 04:18:48 +00:00
parent 0b67b37584
commit c0576faf80
14 changed files with 125 additions and 19 deletions

View file

@ -228,17 +228,12 @@ impl<'a, 'ctx> ClassProperties<'a, 'ctx> {
let has_super_class = class.super_class.is_some();
let mut stmts = ctx.ast.vec_with_capacity(inits.len() + usize::from(has_super_class));
// Add `super(...args);` statement and `...args` param if class has a super class.
// `constructor(...args) { super(...args); /* prop initialization */ }`
// TODO: One of initializers could access a var called `args` from outer scope.
// Use a UID `_args` instead of `args` here.
// Add `super(..._args);` statement and `..._args` param if class has a super class.
// `constructor(..._args) { super(..._args); /* prop initialization */ }`
let mut params_rest = None;
if has_super_class {
let args_binding = ctx.generate_binding(
Atom::from("args"),
constructor_scope_id,
SymbolFlags::FunctionScopedVariable,
);
let args_binding =
ctx.generate_uid("args", constructor_scope_id, SymbolFlags::FunctionScopedVariable);
params_rest = Some(
ctx.ast.alloc_binding_rest_element(SPAN, args_binding.create_binding_pattern(ctx)),
);

View file

@ -0,0 +1,6 @@
class A extends B {
constructor(..._args) {
super(..._args);
babelHelpers.defineProperty(this, "foo", super.bar);
}
}

View file

@ -0,0 +1,6 @@
class Foo extends Bar {
constructor(..._args) {
super(..._args);
this.bar = "foo";
}
}

View file

@ -0,0 +1,11 @@
class A {
foo() {
return "bar";
}
}
class B extends A {
constructor(..._args) {
super(..._args);
this.foo = super.foo();
}
}

View file

@ -0,0 +1,19 @@
var _prop = babelHelpers.classPrivateFieldLooseKey("prop");
class Foo {
constructor() {
Object.defineProperty(this, _prop, {
writable: true,
value: "foo"
});
}
}
var _prop2 = babelHelpers.classPrivateFieldLooseKey("prop");
class Bar extends Foo {
constructor(..._args) {
super(..._args);
Object.defineProperty(this, _prop2, {
writable: true,
value: "bar"
});
}
}

View file

@ -1,4 +1,4 @@
var _foo = /*#__PURE__*/babelHelpers.classPrivateFieldLooseKey("foo");
var _foo = babelHelpers.classPrivateFieldLooseKey("foo");
class Foo {
constructor() {
Object.defineProperty(this, _foo, {
@ -9,8 +9,8 @@ class Foo {
test() {
var _foo3;
let _this$foo;
var _foo2 = /*#__PURE__*/babelHelpers.classPrivateFieldLooseKey("foo");
class Nested extends (_foo3 = /*#__PURE__*/babelHelpers.classPrivateFieldLooseKey("foo"), _this$foo = babelHelpers.classPrivateFieldLooseBase(this, _foo3)[_foo3], class {
var _foo2 = babelHelpers.classPrivateFieldLooseKey("foo");
class Nested extends (_foo3 = babelHelpers.classPrivateFieldLooseKey("foo"), _this$foo = babelHelpers.classPrivateFieldLooseBase(this, _foo3)[_foo3], class {
constructor() {
Object.defineProperty(this, _foo3, {
writable: true,
@ -19,8 +19,8 @@ class Foo {
this[_this$foo] = 2;
}
}) {
constructor(...args) {
super(...args);
constructor(..._args) {
super(..._args);
Object.defineProperty(this, _foo2, {
writable: true,
value: 3

View file

@ -0,0 +1,13 @@
var _prop = new WeakMap();
class Foo {
constructor() {
babelHelpers.classPrivateFieldInitSpec(this, _prop, "foo");
}
}
var _prop2 = new WeakMap();
class Bar extends Foo {
constructor(..._args) {
super(..._args);
babelHelpers.classPrivateFieldInitSpec(this, _prop2, "bar");
}
}

View file

@ -0,0 +1,12 @@
class A {
foo() {
return "bar";
}
}
var _foo = new WeakMap();
class B extends A {
constructor(..._args) {
super(..._args);
babelHelpers.classPrivateFieldInitSpec(this, _foo, super.foo());
}
}

View file

@ -0,0 +1,6 @@
class Foo extends Bar {
constructor(..._args) {
super(..._args);
this.bar = "foo";
}
}

View file

@ -0,0 +1,11 @@
class A {
foo() {
return "bar";
}
}
class B extends A {
constructor(..._args) {
super(..._args);
this.foo = super.foo();
}
}

View file

@ -0,0 +1,6 @@
class Foo extends Bar {
constructor(..._args) {
super(..._args);
babelHelpers.defineProperty(this, "bar", "foo");
}
}

View file

@ -0,0 +1,11 @@
class A {
foo() {
return "bar";
}
}
class B extends A {
constructor(..._args) {
super(..._args);
babelHelpers.defineProperty(this, "foo", super.foo());
}
}

View file

@ -0,0 +1,13 @@
class Test {
constructor() {
var _Other;
class Other extends Test {
constructor(..._args) {
super(..._args);
babelHelpers.defineProperty(this, "a", () => super.test);
}
}
_Other = Other;
babelHelpers.defineProperty(Other, "a", () => babelHelpers.superPropGet(_Other, "test", _Other));
}
}

View file

@ -1,6 +1,6 @@
commit: 54a8389f
Passed: 581/927
Passed: 582/927
# All Passed:
* babel-plugin-transform-class-static-block
@ -276,7 +276,7 @@ x Output mismatch
x Output mismatch
# babel-plugin-transform-class-properties (193/264)
# babel-plugin-transform-class-properties (194/264)
* assumption-constantSuper/complex-super-class/input.js
x Output mismatch
@ -499,9 +499,6 @@ x Output mismatch
* regression/6153/input.js
x Output mismatch
* regression/7951/input.mjs
x Output mismatch
# babel-plugin-transform-nullish-coalescing-operator (5/12)
* assumption-noDocumentAll/transform/input.js