Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize the use of assertThisInitialized after super() #16345

Merged
merged 3 commits into from Mar 14, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -18,7 +18,7 @@ let Outer = /*#__PURE__*/function (_Hello) {
babelHelpers.classCallCheck(this, Outer);
_this = babelHelpers.callSuper(this, Outer);
var _A = /*#__PURE__*/new WeakMap();
_computedKey = babelHelpers.toPropertyKey(babelHelpers.get((_thisSuper = babelHelpers.assertThisInitialized(_this), babelHelpers.getPrototypeOf(Outer.prototype)), "toString", _thisSuper).call(_thisSuper));
_computedKey = babelHelpers.toPropertyKey(babelHelpers.get((_thisSuper = _this, babelHelpers.getPrototypeOf(Outer.prototype)), "toString", _thisSuper).call(_thisSuper));
let Inner = /*#__PURE__*/function (_computedKey4, _computedKey5) {
function Inner() {
babelHelpers.classCallCheck(this, Inner);
Expand Down
Expand Up @@ -24,7 +24,7 @@ let Outer = /*#__PURE__*/function (_Hello) {
_init_extra_hello(this);
});
_Inner = Inner;
[_init_hello, _init_extra_hello] = babelHelpers.applyDecs2311(_Inner, [], [[babelHelpers.get((_thisSuper = babelHelpers.assertThisInitialized(_this), babelHelpers.getPrototypeOf(Outer.prototype)), "dec", _thisSuper), 0, "hello"]]).e;
[_init_hello, _init_extra_hello] = babelHelpers.applyDecs2311(_Inner, [], [[babelHelpers.get((_thisSuper = _this, babelHelpers.getPrototypeOf(Outer.prototype)), "dec", _thisSuper), 0, "hello"]]).e;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be great to avoid the _thisSuper variable and just use _this, but I'm not sure if that's actually possible.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I submitted a new commit, not sure if this is OK, but it currently passes the existing tests. :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The thisSuper was introduced in #11480, to ensure the this binding is resolved before the computed property is evaluated. As long as we have called _assertThisInitialized on the this expression before, it seems okay to remove the thisSuper.

return babelHelpers.possibleConstructorReturn(_this, new Inner());
}
babelHelpers.inherits(Outer, _Hello);
Expand Down
Expand Up @@ -17,7 +17,7 @@ let Outer = /*#__PURE__*/function (_Hello) {
var _thisSuper, _this;
babelHelpers.classCallCheck(this, Outer);
_this = babelHelpers.callSuper(this, Outer);
_babelHelpers$get$cal = babelHelpers.get((_thisSuper = babelHelpers.assertThisInitialized(_this), babelHelpers.getPrototypeOf(Outer.prototype)), "toString", _thisSuper).call(_thisSuper);
_babelHelpers$get$cal = babelHelpers.get((_thisSuper = _this, babelHelpers.getPrototypeOf(Outer.prototype)), "toString", _thisSuper).call(_thisSuper);
let Inner = /*#__PURE__*/babelHelpers.createClass(function Inner() {
babelHelpers.classCallCheck(this, Inner);
babelHelpers.defineProperty(this, _babelHelpers$get$cal, 'hello');
Expand Down
Expand Up @@ -16,7 +16,7 @@ var Bar = /*#__PURE__*/function (_Foo2) {
var _this;
babelHelpers.classCallCheck(this, Bar);
_this = babelHelpers.callSuper(this, Bar, [...args]);
Object.defineProperty(babelHelpers.assertThisInitialized(_this), _prop2, {
Object.defineProperty(_this, _prop2, {
writable: true,
value: "bar"
});
Expand Down
Expand Up @@ -6,7 +6,7 @@ let Child = /*#__PURE__*/function (_Parent) {
var _this;
babelHelpers.classCallCheck(this, Child);
_this = babelHelpers.callSuper(this, Child);
Object.defineProperty(babelHelpers.assertThisInitialized(_this), _scopedFunctionWithThis, {
Object.defineProperty(_this, _scopedFunctionWithThis, {
writable: true,
value: function () {
_this.name = {};
Expand Down
Expand Up @@ -20,7 +20,7 @@ var Foo = /*#__PURE__*/function () {
var _this;
babelHelpers.classCallCheck(this, Nested);
_this = babelHelpers.callSuper(this, Nested, [...args]);
Object.defineProperty(babelHelpers.assertThisInitialized(_this), _foo2, {
Object.defineProperty(_this, _foo2, {
writable: true,
value: 3
});
Expand Down
Expand Up @@ -19,7 +19,7 @@ var Foo = /*#__PURE__*/function () {
var _this;
babelHelpers.classCallCheck(this, Nested);
_this = babelHelpers.callSuper(this, Nested, [...args]);
Object.defineProperty(babelHelpers.assertThisInitialized(_this), _foo2, {
Object.defineProperty(_this, _foo2, {
writable: true,
value: 3
});
Expand Down
Expand Up @@ -6,7 +6,7 @@ var Foo = /*#__PURE__*/function (_Bar) {
var _this;
babelHelpers.classCallCheck(this, Foo);
_this = babelHelpers.callSuper(this, Foo);
Object.defineProperty(babelHelpers.assertThisInitialized(_this), _bar, {
Object.defineProperty(_this, _bar, {
writable: true,
value: "foo"
});
Expand Down
Expand Up @@ -13,7 +13,7 @@ let Bar = /*#__PURE__*/function (_Foo2) {
var _this;
babelHelpers.classCallCheck(this, Bar);
_this = babelHelpers.callSuper(this, Bar, [...args]);
babelHelpers.classPrivateFieldInitSpec(babelHelpers.assertThisInitialized(_this), _prop2, "bar");
babelHelpers.classPrivateFieldInitSpec(_this, _prop2, "bar");
return _this;
}
babelHelpers.inherits(Bar, _Foo2);
Expand Down
Expand Up @@ -6,7 +6,7 @@ let Child = /*#__PURE__*/function (_Parent) {
var _this;
babelHelpers.classCallCheck(this, Child);
_this = babelHelpers.callSuper(this, Child);
babelHelpers.classPrivateFieldInitSpec(babelHelpers.assertThisInitialized(_this), _scopedFunctionWithThis, () => {
babelHelpers.classPrivateFieldInitSpec(_this, _scopedFunctionWithThis, () => {
_this.name = {};
});
return _this;
Expand Down
Expand Up @@ -17,7 +17,7 @@ let Foo = /*#__PURE__*/function () {
var _this;
babelHelpers.classCallCheck(this, Nested);
_this = babelHelpers.callSuper(this, Nested, [...args]);
babelHelpers.classPrivateFieldInitSpec(babelHelpers.assertThisInitialized(_this), _foo2, 3);
babelHelpers.classPrivateFieldInitSpec(_this, _foo2, 3);
return _this;
}
babelHelpers.inherits(Nested, _ref);
Expand Down
Expand Up @@ -16,7 +16,7 @@ let Foo = /*#__PURE__*/function () {
var _this;
babelHelpers.classCallCheck(this, Nested);
_this = babelHelpers.callSuper(this, Nested, [...args]);
babelHelpers.classPrivateFieldInitSpec(babelHelpers.assertThisInitialized(_this), _foo2, 3);
babelHelpers.classPrivateFieldInitSpec(_this, _foo2, 3);
return _this;
}
babelHelpers.inherits(Nested, _ref);
Expand Down
Expand Up @@ -19,7 +19,7 @@ let B = /*#__PURE__*/function (_A) {
var _thisSuper, _this;
babelHelpers.classCallCheck(this, B);
_this = babelHelpers.callSuper(this, B, [...args]);
babelHelpers.classPrivateFieldInitSpec(babelHelpers.assertThisInitialized(_this), _foo, babelHelpers.get((_thisSuper = babelHelpers.assertThisInitialized(_this), babelHelpers.getPrototypeOf(B.prototype)), "foo", _thisSuper).call(_thisSuper));
babelHelpers.classPrivateFieldInitSpec(_this, _foo, babelHelpers.get((_thisSuper = _this, babelHelpers.getPrototypeOf(B.prototype)), "foo", _thisSuper).call(_thisSuper));
return _this;
}
babelHelpers.inherits(B, _A);
Expand Down
Expand Up @@ -6,7 +6,7 @@ let Foo = /*#__PURE__*/function (_Bar) {
var _this;
babelHelpers.classCallCheck(this, Foo);
_this = babelHelpers.callSuper(this, Foo);
babelHelpers.classPrivateFieldInitSpec(babelHelpers.assertThisInitialized(_this), _bar, "foo");
babelHelpers.classPrivateFieldInitSpec(_this, _bar, "foo");
return _this;
}
babelHelpers.inherits(Foo, _Bar);
Expand Down
Expand Up @@ -18,7 +18,7 @@ var B = /*#__PURE__*/function (_A) {
var _thisSuper, _this;
babelHelpers.classCallCheck(this, B);
_this = babelHelpers.callSuper(this, B, [...args]);
_this.foo = babelHelpers.get((_thisSuper = babelHelpers.assertThisInitialized(_this), babelHelpers.getPrototypeOf(B.prototype)), "foo", _thisSuper).call(_thisSuper);
_this.foo = babelHelpers.get((_thisSuper = _this, babelHelpers.getPrototypeOf(B.prototype)), "foo", _thisSuper).call(_thisSuper);
return _this;
}
babelHelpers.inherits(B, _A);
Expand Down
Expand Up @@ -5,7 +5,7 @@ var Foo = /*#__PURE__*/function (_Bar) {
var _this;
babelHelpers.classCallCheck(this, Foo);
_this = babelHelpers.callSuper(this, Foo, [...args]);
babelHelpers.defineProperty(babelHelpers.assertThisInitialized(_this), "bar", "foo");
babelHelpers.defineProperty(_this, "bar", "foo");
return _this;
}
babelHelpers.inherits(Foo, _Bar);
Expand Down
Expand Up @@ -5,7 +5,7 @@ var Child = /*#__PURE__*/function (_Parent) {
var _this;
babelHelpers.classCallCheck(this, Child);
_this = babelHelpers.callSuper(this, Child);
babelHelpers.defineProperty(babelHelpers.assertThisInitialized(_this), "scopedFunctionWithThis", function () {
babelHelpers.defineProperty(_this, "scopedFunctionWithThis", function () {
_this.name = {};
});
return _this;
Expand Down
Expand Up @@ -18,7 +18,7 @@ var B = /*#__PURE__*/function (_A) {
var _thisSuper, _this;
babelHelpers.classCallCheck(this, B);
_this = babelHelpers.callSuper(this, B, [...args]);
babelHelpers.defineProperty(babelHelpers.assertThisInitialized(_this), "foo", babelHelpers.get((_thisSuper = babelHelpers.assertThisInitialized(_this), babelHelpers.getPrototypeOf(B.prototype)), "foo", _thisSuper).call(_thisSuper));
babelHelpers.defineProperty(_this, "foo", babelHelpers.get((_thisSuper = _this, babelHelpers.getPrototypeOf(B.prototype)), "foo", _thisSuper).call(_thisSuper));
return _this;
}
babelHelpers.inherits(B, _A);
Expand Down
Expand Up @@ -5,7 +5,7 @@ var Foo = /*#__PURE__*/function (_Bar) {
var _this;
babelHelpers.classCallCheck(this, Foo);
_this = babelHelpers.callSuper(this, Foo);
babelHelpers.defineProperty(babelHelpers.assertThisInitialized(_this), "bar", "foo");
babelHelpers.defineProperty(_this, "bar", "foo");
return _this;
}
babelHelpers.inherits(Foo, _Bar);
Expand Down
Expand Up @@ -11,8 +11,8 @@ var Test = /*#__PURE__*/babelHelpers.createClass(function Test() {
args[_key] = arguments[_key];
}
_this = babelHelpers.callSuper(this, Other, [].concat(args));
babelHelpers.defineProperty(babelHelpers.assertThisInitialized(_this), "a", function () {
return babelHelpers.get((_thisSuper = babelHelpers.assertThisInitialized(_this), babelHelpers.getPrototypeOf(Other.prototype)), "test", _thisSuper);
babelHelpers.defineProperty(_this, "a", function () {
return babelHelpers.get((_thisSuper = _this, babelHelpers.getPrototypeOf(Other.prototype)), "test", _thisSuper);
});
return _this;
}
Expand Down
57 changes: 43 additions & 14 deletions packages/babel-plugin-transform-classes/src/transformClass.ts
Expand Up @@ -398,10 +398,15 @@ export default function transformClass(
const path = classState.userConstructorPath;
const body = path.get("body");

const constructorBody = path.get("body");

let maxGuaranteedSuperBeforeIndex = constructorBody.node.body.length;

path.traverse(findThisesVisitor);

let thisRef = function () {
const ref = path.scope.generateDeclaredUidIdentifier("this");
maxGuaranteedSuperBeforeIndex++;
thisRef = () => t.cloneNode(ref);
return ref;
};
Expand All @@ -413,15 +418,6 @@ export default function transformClass(
);
};

for (const thisPath of classState.superThises) {
const { node, parentPath } = thisPath;
if (parentPath.isMemberExpression({ object: node })) {
thisPath.replaceWith(thisRef());
continue;
}
thisPath.replaceWith(buildAssertThisInitialized());
}

const bareSupers: NodePath<t.CallExpression>[] = [];
path.traverse(
traverse.visitors.merge([
Expand All @@ -437,15 +433,18 @@ export default function transformClass(
]),
);

let guaranteedSuperBeforeFinish = !!bareSupers.length;

for (const bareSuper of bareSupers) {
wrapSuperCall(bareSuper, classState.superName, thisRef, body);

if (guaranteedSuperBeforeFinish) {
if (maxGuaranteedSuperBeforeIndex >= 0) {
let lastParentPath: NodePath;
bareSuper.find(function (parentPath) {
// hit top so short circuit
if (parentPath === path) {
if (parentPath === constructorBody) {
maxGuaranteedSuperBeforeIndex = Math.min(
maxGuaranteedSuperBeforeIndex,
lastParentPath.key as number,
);
return true;
}

Expand All @@ -454,13 +453,40 @@ export default function transformClass(
parentPath.isConditional() ||
parentPath.isArrowFunctionExpression()
) {
guaranteedSuperBeforeFinish = false;
maxGuaranteedSuperBeforeIndex = -1;
return true;
}

lastParentPath = parentPath;
});
}
}

for (const thisPath of classState.superThises) {
const { node, parentPath } = thisPath;
if (parentPath.isMemberExpression({ object: node })) {
thisPath.replaceWith(thisRef());
continue;
}

let thisIndex: number;
thisPath.find(function (parentPath) {
if (parentPath.parentPath === constructorBody) {
thisIndex = parentPath.key as number;
return true;
}
});

if (
maxGuaranteedSuperBeforeIndex != -1 &&
thisIndex > maxGuaranteedSuperBeforeIndex
) {
thisPath.replaceWith(thisRef());
} else {
thisPath.replaceWith(buildAssertThisInitialized());
}
}

let wrapReturn;

if (classState.isLoose) {
Expand All @@ -486,6 +512,9 @@ export default function transformClass(
// if we have a return as the last node in the body then we've already caught that
// return
const bodyPaths = body.get("body");
const guaranteedSuperBeforeFinish =
maxGuaranteedSuperBeforeIndex !== -1 &&
maxGuaranteedSuperBeforeIndex < bodyPaths.length;
if (!bodyPaths.length || !bodyPaths.pop().isReturnStatement()) {
body.pushContainer(
"body",
Expand Down
Expand Up @@ -7,11 +7,11 @@ var Test = /*#__PURE__*/function (_Foo) {
babelHelpers.classCallCheck(this, Test);
woops.super.test();
_this = babelHelpers.callSuper(this, Test);
_Foo.prototype.test.call(babelHelpers.assertThisInitialized(_this));
_Foo.prototype.test.call(_this);
_this = babelHelpers.callSuper(this, Test, arguments);
_this = babelHelpers.callSuper(this, Test, ["test"].concat(Array.prototype.slice.call(arguments)));
_Foo.prototype.test.apply(babelHelpers.assertThisInitialized(_this), arguments);
(_Foo$prototype$test = _Foo.prototype.test).call.apply(_Foo$prototype$test, [babelHelpers.assertThisInitialized(_this), "test"].concat(Array.prototype.slice.call(arguments)));
_Foo.prototype.test.apply(_this, arguments);
(_Foo$prototype$test = _Foo.prototype.test).call.apply(_Foo$prototype$test, [_this, "test"].concat(Array.prototype.slice.call(arguments)));
return _this;
}
babelHelpers.inherits(Test, _Foo);
Expand Down
Expand Up @@ -6,7 +6,7 @@ var Test = /*#__PURE__*/function (_Foo) {
babelHelpers.classCallCheck(this, Test);
_this = babelHelpers.callSuper(this, Test);
_Foo.prototype.test.whatever();
_Foo.prototype.test.call(babelHelpers.assertThisInitialized(_this));
_Foo.prototype.test.call(_this);
return _this;
}
babelHelpers.inherits(Test, _Foo);
Expand Down
Expand Up @@ -5,7 +5,7 @@ var Test = /*#__PURE__*/function (_Foo) {
var _this;
babelHelpers.classCallCheck(this, Test);
_this = _Foo.call(this) || this;
babelHelpers.assertThisInitialized(_this);
_this;
_this.prop = 1;
return _this;
}
Expand Down
Expand Up @@ -6,11 +6,11 @@ var Test = /*#__PURE__*/function (_Foo) {
var _this;
woops.super.test();
_this = _Foo.call(this) || this;
_Foo.prototype.test.call(babelHelpers.assertThisInitialized(_this));
_Foo.prototype.test.call(_this);
_this = _Foo.apply(this, arguments) || this;
_this = _Foo.call.apply(_Foo, [this, "test"].concat(Array.prototype.slice.call(arguments))) || this;
_Foo.prototype.test.apply(babelHelpers.assertThisInitialized(_this), arguments);
(_Foo$prototype$test = _Foo.prototype.test).call.apply(_Foo$prototype$test, [babelHelpers.assertThisInitialized(_this), "test"].concat(Array.prototype.slice.call(arguments)));
_Foo.prototype.test.apply(_this, arguments);
(_Foo$prototype$test = _Foo.prototype.test).call.apply(_Foo$prototype$test, [_this, "test"].concat(Array.prototype.slice.call(arguments)));
return _this;
}
babelHelpers.inheritsLoose(Test, _Foo);
Expand Down
Expand Up @@ -5,7 +5,7 @@ var Test = /*#__PURE__*/function (_Foo) {
var _this;
_this = _Foo.call(this) || this;
_Foo.prototype.test.whatever();
_Foo.prototype.test.call(babelHelpers.assertThisInitialized(_this));
_Foo.prototype.test.call(_this);
return _this;
}
babelHelpers.inheritsLoose(Test, _Foo);
Expand Down
@@ -0,0 +1,6 @@
class Foo extends Bar {
constructor() {
if (dynamic()) super();
this;
}
}
@@ -0,0 +1,3 @@
{
"plugins": ["transform-classes"]
}
@@ -0,0 +1,13 @@
let Foo = /*#__PURE__*/function (_Bar) {
"use strict";

function Foo() {
var _this;
babelHelpers.classCallCheck(this, Foo);
if (dynamic()) _this = babelHelpers.callSuper(this, Foo);
babelHelpers.assertThisInitialized(_this);
return babelHelpers.assertThisInitialized(_this);
}
babelHelpers.inherits(Foo, _Bar);
return babelHelpers.createClass(Foo);
}(Bar);
@@ -0,0 +1,5 @@
class Foo extends Bar {
constructor() {
super(this);
}
}
@@ -0,0 +1,3 @@
{
"plugins": ["transform-classes"]
}
@@ -0,0 +1,11 @@
let Foo = /*#__PURE__*/function (_Bar) {
"use strict";

function Foo() {
var _this;
babelHelpers.classCallCheck(this, Foo);
return _this = babelHelpers.callSuper(this, Foo, [babelHelpers.assertThisInitialized(_this)]);
}
babelHelpers.inherits(Foo, _Bar);
return babelHelpers.createClass(Foo);
}(Bar);
@@ -0,0 +1,6 @@
class Foo extends Bar {
constructor() {
this;
super();
}
}