Fix tdz checks in transform-block-scoping plugin (#9498)
* Better tdz tests - Use jest's expect.toThrow/expect.not.toThrow - Add input/output tests * Fix basic tdz (a = 2; let a) Fixes #6848 * Make _guessExecutionStatusRelativeTo more robust * Add tests * Return less "unkown" execution status * "function" execution status does not exist * Fix recursive functions * Update helper version * "finally" blocks are always executed * Typo
This commit is contained in:
@@ -16,7 +16,7 @@ export default declare((api, opts) => {
|
||||
throw new Error(`.throwIfClosureRequired must be a boolean, or undefined`);
|
||||
}
|
||||
if (typeof tdzEnabled !== "boolean") {
|
||||
throw new Error(`.throwIfClosureRequired must be a boolean, or undefined`);
|
||||
throw new Error(`.tdz must be a boolean, or undefined`);
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -33,11 +33,13 @@ export default declare((api, opts) => {
|
||||
|
||||
for (let i = 0; i < node.declarations.length; i++) {
|
||||
const decl = node.declarations[i];
|
||||
if (decl.init) {
|
||||
const assign = t.assignmentExpression("=", decl.id, decl.init);
|
||||
assign._ignoreBlockScopingTDZ = true;
|
||||
nodes.push(t.expressionStatement(assign));
|
||||
}
|
||||
const assign = t.assignmentExpression(
|
||||
"=",
|
||||
decl.id,
|
||||
decl.init || scope.buildUndefinedNode(),
|
||||
);
|
||||
assign._ignoreBlockScopingTDZ = true;
|
||||
nodes.push(t.expressionStatement(assign));
|
||||
decl.init = this.addHelper("temporalUndefined");
|
||||
}
|
||||
|
||||
@@ -181,6 +183,8 @@ const letReferenceBlockVisitor = traverse.visitors.merge([
|
||||
// simply rename the variables.
|
||||
if (state.loopDepth > 0) {
|
||||
path.traverse(letReferenceFunctionVisitor, state);
|
||||
} else {
|
||||
path.traverse(tdzVisitor, state);
|
||||
}
|
||||
return path.skip();
|
||||
},
|
||||
@@ -756,7 +760,7 @@ class BlockScoping {
|
||||
closurify: false,
|
||||
loopDepth: 0,
|
||||
tdzEnabled: this.tdzEnabled,
|
||||
addHelper: name => this.addHelper(name),
|
||||
addHelper: name => this.state.addHelper(name),
|
||||
};
|
||||
|
||||
if (isInLoop(this.blockPath)) {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { types as t } from "@babel/core";
|
||||
import { types as t, template } from "@babel/core";
|
||||
|
||||
function getTDZStatus(refPath, bindingPath) {
|
||||
const executionStatus = bindingPath._guessExecutionStatusRelativeTo(refPath);
|
||||
|
||||
if (executionStatus === "before") {
|
||||
return "inside";
|
||||
} else if (executionStatus === "after") {
|
||||
return "outside";
|
||||
} else if (executionStatus === "after") {
|
||||
return "inside";
|
||||
} else {
|
||||
return "maybe";
|
||||
}
|
||||
@@ -41,7 +41,7 @@ export const visitor = {
|
||||
if (bindingPath.isFunctionDeclaration()) return;
|
||||
|
||||
const status = getTDZStatus(path, bindingPath);
|
||||
if (status === "inside") return;
|
||||
if (status === "outside") return;
|
||||
|
||||
if (status === "maybe") {
|
||||
const assert = buildTDZAssert(node, state);
|
||||
@@ -57,19 +57,8 @@ export const visitor = {
|
||||
} else {
|
||||
path.replaceWith(assert);
|
||||
}
|
||||
} else if (status === "outside") {
|
||||
path.replaceWith(
|
||||
t.throwStatement(
|
||||
t.inherits(
|
||||
t.newExpression(t.identifier("ReferenceError"), [
|
||||
t.stringLiteral(
|
||||
`${node.name} is not defined - temporal dead zone`,
|
||||
),
|
||||
]),
|
||||
node,
|
||||
),
|
||||
),
|
||||
);
|
||||
} else if (status === "inside") {
|
||||
path.replaceWith(template.ast`${state.addHelper("tdz")}("${node.name}")`);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -87,14 +76,14 @@ export const visitor = {
|
||||
const id = ids[name];
|
||||
|
||||
if (isReference(id, path.scope, state)) {
|
||||
nodes.push(buildTDZAssert(id, state));
|
||||
nodes.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
if (nodes.length) {
|
||||
node._ignoreBlockScopingTDZ = true;
|
||||
nodes.push(node);
|
||||
path.replaceWithMultiple(nodes.map(t.expressionStatement));
|
||||
path.replaceWithMultiple(nodes.map(n => t.expressionStatement(n)));
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user