Fix recursion in async-to-generator transforms

We're naming the inner generator function in the name of the
original async function. This means when people have recursive
await calls it refers to the generator version. Which is fine
if we had a `yield *` (delegate). However, if not it leads to
returning an unresolved generator object.

We can either capture all recursive calls and add a delegate, which
becomes really hard with expressions. I choose to have the name
reserved to the exposed function `retFunction`.

Fixes #2782
This commit is contained in:
Amjad Masad
2015-11-03 17:05:41 -08:00
parent 9eee677321
commit 2220167903
6 changed files with 21 additions and 19 deletions

View File

@@ -1,8 +1,8 @@
var foo = (function () {
var ref = babelHelpers.asyncToGenerator(function* bar() {
var ref = babelHelpers.asyncToGenerator(function* () {
console.log(bar);
});
return function foo() {
return function bar() {
return ref.apply(this, arguments);
};
})();

View File

@@ -1,5 +1,5 @@
let foo = (function () {
var ref = babelHelpers.asyncToGenerator(function* foo(bar) {});
var ref = babelHelpers.asyncToGenerator(function* (bar) {});
return function foo(_x) {
return ref.apply(this, arguments);
};

View File

@@ -1,5 +1,5 @@
let foo = (function () {
var ref = babelHelpers.asyncToGenerator(function* foo() {
var ref = babelHelpers.asyncToGenerator(function* () {
var wat = yield bar();
});
return function foo() {

View File

@@ -1,10 +1,10 @@
import { coroutine as _coroutine } from "bluebird";
var foo = (function () {
var ref = _coroutine(function* bar() {
var ref = _coroutine(function* () {
console.log(bar);
});
return function foo() {
return function bar() {
return ref.apply(this, arguments);
};
})();

View File

@@ -1,7 +1,7 @@
import { coroutine as _coroutine } from "bluebird";
let foo = (function () {
var ref = _coroutine(function* foo() {
var ref = _coroutine(function* () {
var wat = yield bar();
});

View File

@@ -46,6 +46,9 @@ function plainFunction(path: NodePath, callId: Object) {
node.async = false;
node.generator = true;
let asyncFnId = node.id;
node.id = null;
let built = t.callExpression(callId, [node]);
let container = buildWrapper({
FUNCTION: built,
@@ -57,25 +60,24 @@ function plainFunction(path: NodePath, callId: Object) {
if (path.isFunctionDeclaration()) {
let declar = t.variableDeclaration("let", [
t.variableDeclarator(
t.identifier(node.id.name),
t.identifier(asyncFnId.name),
t.callExpression(container, [])
)
]);
declar._blockHoist = true;
nameFunction({
node: retFunction,
parent: declar.declarations[0],
scope: path.scope
});
retFunction.id = asyncFnId;
path.replaceWith(declar);
} else {
nameFunction({
node: retFunction,
parent: path.parent,
scope: path.scope
});
if (asyncFnId && asyncFnId.name) {
retFunction.id = asyncFnId;
} else {
nameFunction({
node: retFunction,
parent: path.parent,
scope: path.scope
});
}
if (retFunction.id || node.params.length) {
// we have an inferred function id or params so we need this wrapper