opt out of tail recursion optimisation if the owner id has been reassigned - fixes #744
This commit is contained in:
parent
56a953df64
commit
db93c52182
@ -64,11 +64,16 @@ TailCallTransformer.prototype.run = function () {
|
||||
var scope = this.scope;
|
||||
var node = this.node;
|
||||
|
||||
// only tail recursion can be optimized as for now,
|
||||
// so we can skip anonymous functions entirely
|
||||
// only tail recursion can be optimized as for now, so we can skip anonymous
|
||||
// functions entirely
|
||||
var ownerId = this.ownerId;
|
||||
if (!ownerId) return;
|
||||
|
||||
// check if the ownerId has been reassigned, if it has then it's not safe to
|
||||
// perform optimisations
|
||||
var ownerIdInfo = this.scope.getBindingInfo(ownerId.name);
|
||||
if (!ownerIdInfo || ownerIdInfo.reassigned) return;
|
||||
|
||||
// traverse the function and look for tail recursion
|
||||
scope.traverse(node, firstPass, this);
|
||||
|
||||
|
||||
@ -229,6 +229,14 @@ Scope.prototype.registerDeclaration = function (node) {
|
||||
}
|
||||
};
|
||||
|
||||
Scope.prototype.registerBindingReassignment = function (node) {
|
||||
var ids = t.getBindingIdentifiers(node);
|
||||
for (var name in ids) {
|
||||
var info = this.getBindingInfo(name);
|
||||
if (info) info.reassigned = true;
|
||||
}
|
||||
};
|
||||
|
||||
Scope.prototype.registerBinding = function (kind, node) {
|
||||
if (!kind) throw new ReferenceError("no `kind`");
|
||||
|
||||
@ -241,6 +249,7 @@ Scope.prototype.registerBinding = function (kind, node) {
|
||||
|
||||
this.bindings[name] = {
|
||||
typeAnnotation: this.getTypeAnnotation(name, id, node),
|
||||
reassigned: false,
|
||||
identifier: id,
|
||||
scope: this,
|
||||
kind: kind
|
||||
@ -302,6 +311,8 @@ var programReferenceVisitor = {
|
||||
state.addGlobal(node);
|
||||
} else if (t.isLabeledStatement(node)) {
|
||||
state.addGlobal(node);
|
||||
} else if (t.isAssignmentExpression(node)) {
|
||||
scope.registerBindingReassignment(node);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
13
test/fixtures/transformation/es6-tail-call/ignore-reassigned/actual.js
vendored
Normal file
13
test/fixtures/transformation/es6-tail-call/ignore-reassigned/actual.js
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
// we need to deopt `test` if it's reassigned as we can't be certain of it's
|
||||
// state, ie. it could have been rebound or dereferenced
|
||||
|
||||
function test(exit) {
|
||||
if (exit) {
|
||||
return this.x;
|
||||
}
|
||||
return test(true);
|
||||
}
|
||||
|
||||
test = test.bind({ x: "yay" });
|
||||
|
||||
console.log(test());
|
||||
15
test/fixtures/transformation/es6-tail-call/ignore-reassigned/expected.js
vendored
Normal file
15
test/fixtures/transformation/es6-tail-call/ignore-reassigned/expected.js
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
"use strict";
|
||||
|
||||
// we need to deopt `test` if it's reassigned as we can't be certain of it's
|
||||
// state, ie. it could have been rebound or dereferenced
|
||||
|
||||
function test(exit) {
|
||||
if (exit) {
|
||||
return this.x;
|
||||
}
|
||||
return test(true);
|
||||
}
|
||||
|
||||
test = test.bind({ x: "yay" });
|
||||
|
||||
console.log(test());
|
||||
Loading…
x
Reference in New Issue
Block a user