Skip __awaiter this captures
This commit is contained in:
parent
443e1b9053
commit
cf7ba79f81
|
@ -191,13 +191,22 @@ function serializeCapturedObjectAsync(obj: any, resolve: (v: AsyncEnvironmentEnt
|
|||
// expected to be the usual V8-serialized function expression text.
|
||||
function computeFreeVariables(funcstr: string): string[] {
|
||||
Log.debug(`Computing free variables for function: ${funcstr}`);
|
||||
if (funcstr.indexOf("[native code]") !== -1) {
|
||||
throw new Error(`Cannot serialize native code function: "${funcstr}"`);
|
||||
}
|
||||
|
||||
let opts: acorn.Options = {
|
||||
ecmaVersion: 8,
|
||||
sourceType: "script",
|
||||
};
|
||||
let parser = new acorn.Parser(opts, funcstr);
|
||||
let program: estree.Program = parser.parse();
|
||||
let program: estree.Program;
|
||||
try {
|
||||
program = parser.parse();
|
||||
}
|
||||
catch (err) {
|
||||
throw new Error(`Could not parse function: ${err}\n${funcstr}`);
|
||||
}
|
||||
|
||||
// Now that we've parsed the program, compute the free variables, and return them.
|
||||
return new FreeVariableComputer().compute(program);
|
||||
|
@ -237,6 +246,7 @@ class FreeVariableComputer {
|
|||
ThisExpression: this.visitThisExpression.bind(this),
|
||||
BlockStatement: this.visitBlockStatement.bind(this),
|
||||
CatchClause: this.visitCatchClause.bind(this),
|
||||
CallExpression: this.visitCallExpression.bind(this),
|
||||
FunctionDeclaration: this.visitFunctionDeclaration.bind(this),
|
||||
FunctionExpression: this.visitBaseFunction.bind(this),
|
||||
ArrowFunctionExpression: this.visitBaseFunction.bind(this),
|
||||
|
@ -348,6 +358,22 @@ class FreeVariableComputer {
|
|||
this.scope.pop();
|
||||
}
|
||||
|
||||
private visitCallExpression(node: estree.SimpleCallExpression, state: any, cb: walkCallback): void {
|
||||
// Most call expressions are normal. But we must special case one kind of function:
|
||||
// TypeScript's __awaiter functions. They are of the form `__awaiter(this, void 0, void 0, function* (){})`,
|
||||
// which will cause us to attempt to capture and serialize the entire surrounding function in
|
||||
// which any lambda is created (thanks to `this`). That spirals into craziness, and bottoms out on native
|
||||
// functions which we cannot serialize. We only want to capture `this` if the user code mentioned it.
|
||||
cb(node.callee, state);
|
||||
let isAwaiterCall: boolean =
|
||||
(node.callee.type === "Identifier" && (node.callee as estree.Identifier).name === "__awaiter");
|
||||
for (let i = 0; i < node.arguments.length; i++) {
|
||||
if (i > 0 || !isAwaiterCall) {
|
||||
cb(node.arguments[i], state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private visitVariableDeclaration(node: estree.VariableDeclaration, state: any, cb: walkCallback): void {
|
||||
for (let decl of node.declarations) {
|
||||
// If the declaration is an identifier, it isn't a free variable, for whatever scope it
|
||||
|
|
Loading…
Reference in a new issue