Fix duplicated assertThisInitialized calls in constructors (#9458)

This commit is contained in:
Rubén Norte
2019-02-07 22:01:46 +00:00
committed by Nicolò Ribaudo
parent d1514f57bd
commit 045d019149
25 changed files with 69 additions and 87 deletions

View File

@@ -32,25 +32,6 @@ const verifyConstructorVisitor = traverse.visitors.merge([
);
}
},
ThisExpression(path, state) {
if (!state.isDerived) return;
const { node, parentPath } = path;
if (parentPath.isMemberExpression({ object: node })) {
// In cases like this.foo or this[foo], there is no need to add
// assertThisInitialized, since they already throw if this is
// undefined.
return;
}
const assertion = t.callExpression(
state.file.addHelper("assertThisInitialized"),
[node],
);
path.replaceWith(assertion);
path.skip();
},
},
]);
@@ -84,7 +65,6 @@ export default function transformClass(
instancePropRefs: {},
staticPropBody: [],
body: [],
bareSupers: new Set(),
superThises: [],
pushedConstructor: false,
pushedInherits: false,
@@ -217,34 +197,22 @@ export default function transformClass(
replaceSupers.replace();
// TODO this needs to be cleaned up. But, one step at a time.
const state = {
returns: [],
bareSupers: new Set(),
};
const superReturns = [];
path.traverse(
traverse.visitors.merge([
environmentVisitor,
{
ReturnStatement(path, state) {
ReturnStatement(path) {
if (!path.getFunctionParent().isArrowFunctionExpression()) {
state.returns.push(path);
}
},
Super(path, state) {
const { node, parentPath } = path;
if (parentPath.isCallExpression({ callee: node })) {
state.bareSupers.add(parentPath);
superReturns.push(path);
}
},
},
]),
state,
);
if (isConstructor) {
pushConstructor(state, node, path);
pushConstructor(superReturns, node, path);
} else {
pushMethod(node, path);
}
@@ -378,15 +346,43 @@ export default function transformClass(
path.traverse(findThisesVisitor);
let guaranteedSuperBeforeFinish = !!classState.bareSupers.size;
let thisRef = function() {
const ref = path.scope.generateDeclaredUidIdentifier("this");
thisRef = () => t.cloneNode(ref);
return ref;
};
for (const bareSuper of classState.bareSupers) {
for (const thisPath of classState.superThises) {
const { node, parentPath } = thisPath;
if (parentPath.isMemberExpression({ object: node })) {
thisPath.replaceWith(thisRef());
continue;
}
thisPath.replaceWith(
t.callExpression(classState.file.addHelper("assertThisInitialized"), [
thisRef(),
]),
);
}
const bareSupers = new Set();
path.traverse(
traverse.visitors.merge([
environmentVisitor,
{
Super(path) {
const { node, parentPath } = path;
if (parentPath.isCallExpression({ callee: node })) {
bareSupers.add(parentPath);
}
},
},
]),
);
let guaranteedSuperBeforeFinish = !!bareSupers.size;
for (const bareSuper of bareSupers) {
wrapSuperCall(bareSuper, classState.superName, thisRef, body);
if (guaranteedSuperBeforeFinish) {
@@ -408,19 +404,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(
t.callExpression(classState.file.addHelper("assertThisInitialized"), [
thisRef(),
]),
);
}
let wrapReturn;
if (classState.isLoose) {
@@ -535,7 +518,7 @@ export default function transformClass(
* Replace the constructor body of our class.
*/
function pushConstructor(
replaceSupers,
superReturns,
method: { type: "ClassMethod" },
path: NodePath,
) {
@@ -548,8 +531,7 @@ export default function transformClass(
userConstructorPath: path,
userConstructor: method,
hasConstructor: true,
bareSupers: replaceSupers.bareSupers,
superReturns: replaceSupers.returns,
superReturns,
});
const { construct } = classState;