Skip to content

Commit 3d09bc4

Browse files
committed
Switch to __await sentinel, better support for return values
1 parent 2dece39 commit 3d09bc4

11 files changed

+700
-773
lines changed

src/compiler/transformers/esnext.ts

Lines changed: 64 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -106,15 +106,11 @@ namespace ts {
106106
}
107107
}
108108

109-
function visitAwaitExpression(node: AwaitExpression) {
109+
function visitAwaitExpression(node: AwaitExpression): Expression {
110110
if (enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator) {
111-
const expression = visitNode(node.expression, visitor, isExpression);
112111
return setOriginalNode(
113112
setTextRange(
114-
createYield(
115-
/*asteriskToken*/ undefined,
116-
createArrayLiteral([createLiteral("await"), expression])
117-
),
113+
createYield(createAwaitHelper(context, visitNode(node.expression, visitor, isExpression))),
118114
/*location*/ node
119115
),
120116
node
@@ -124,21 +120,26 @@ namespace ts {
124120
}
125121

126122
function visitYieldExpression(node: YieldExpression) {
127-
if (enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator) {
123+
if (enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator && node.asteriskToken) {
128124
const expression = visitNode(node.expression, visitor, isExpression);
129-
const delegator = node.asteriskToken && updateYield(
130-
node,
131-
node.asteriskToken,
132-
createAsyncDelegatorHelper(context, expression, expression)
133-
);
134-
return updateYield(
135-
node,
136-
/*asteriskToken*/ undefined,
137-
createArrayLiteral(
138-
delegator ? [createLiteral("await"), delegator] :
139-
expression ? [createLiteral("yield"), expression] :
140-
[createLiteral("yield")]
141-
)
125+
return setOriginalNode(
126+
setTextRange(
127+
createYield(
128+
createAwaitHelper(context,
129+
updateYield(
130+
node,
131+
node.asteriskToken,
132+
createAsyncDelegatorHelper(
133+
context,
134+
createAsyncValuesHelper(context, expression, expression),
135+
expression
136+
)
137+
)
138+
)
139+
),
140+
node
141+
),
142+
node
142143
);
143144
}
144145
return visitEachChild(node, visitor, context);
@@ -350,23 +351,22 @@ namespace ts {
350351
);
351352
}
352353

354+
function awaitAsYield(expression: Expression) {
355+
return createYield(/*asteriskToken*/ undefined, enclosingFunctionFlags & FunctionFlags.Generator ? createAwaitHelper(context, expression) : expression);
356+
}
357+
353358
function transformForAwaitOfStatement(node: ForOfStatement, outermostLabeledStatement: LabeledStatement) {
354359
const expression = visitNode(node.expression, visitor, isExpression);
355360
const iterator = isIdentifier(expression) ? getGeneratedNameForNode(expression) : createTempVariable(/*recordTempVariable*/ undefined);
356361
const result = isIdentifier(expression) ? getGeneratedNameForNode(iterator) : createTempVariable(/*recordTempVariable*/ undefined);
357362
const errorRecord = createUniqueName("e");
358363
const catchVariable = getGeneratedNameForNode(errorRecord);
359364
const returnMethod = createTempVariable(/*recordTempVariable*/ undefined);
360-
const values = createAsyncValuesHelper(context, expression, /*location*/ node.expression);
361-
const next = createYield(
362-
/*asteriskToken*/ undefined,
363-
enclosingFunctionFlags & FunctionFlags.Generator
364-
? createArrayLiteral([
365-
createLiteral("await"),
366-
createCall(createPropertyAccess(iterator, "next" ), /*typeArguments*/ undefined, [])
367-
])
368-
: createCall(createPropertyAccess(iterator, "next" ), /*typeArguments*/ undefined, [])
369-
);
365+
const callValues = createAsyncValuesHelper(context, expression, /*location*/ node.expression);
366+
const callNext = createCall(createPropertyAccess(iterator, "next" ), /*typeArguments*/ undefined, []);
367+
const getDone = createPropertyAccess(result, "done");
368+
const getValue = createPropertyAccess(result, "value");
369+
const callReturn = createFunctionCall(returnMethod, iterator, []);
370370

371371
hoistVariableDeclaration(errorRecord);
372372
hoistVariableDeclaration(returnMethod);
@@ -377,16 +377,19 @@ namespace ts {
377377
/*initializer*/ setEmitFlags(
378378
setTextRange(
379379
createVariableDeclarationList([
380-
setTextRange(createVariableDeclaration(iterator, /*type*/ undefined, values), node.expression),
381-
createVariableDeclaration(result, /*type*/ undefined, next)
380+
setTextRange(createVariableDeclaration(iterator, /*type*/ undefined, callValues), node.expression),
381+
createVariableDeclaration(result)
382382
]),
383383
node.expression
384384
),
385385
EmitFlags.NoHoisting
386386
),
387-
/*condition*/ createLogicalNot(createPropertyAccess(result, "done")),
388-
/*incrementor*/ createAssignment(result, next),
389-
/*statement*/ convertForOfStatementHead(node, createPropertyAccess(result, "value"))
387+
/*condition*/ createComma(
388+
createAssignment(result, awaitAsYield(callNext)),
389+
createLogicalNot(getDone)
390+
),
391+
/*incrementor*/ undefined,
392+
/*statement*/ convertForOfStatementHead(node, awaitAsYield(getValue))
390393
),
391394
/*location*/ node
392395
),
@@ -424,26 +427,14 @@ namespace ts {
424427
createLogicalAnd(
425428
createLogicalAnd(
426429
result,
427-
createLogicalNot(
428-
createPropertyAccess(result, "done")
429-
)
430+
createLogicalNot(getDone)
430431
),
431432
createAssignment(
432433
returnMethod,
433434
createPropertyAccess(iterator, "return")
434435
)
435436
),
436-
createStatement(
437-
createYield(
438-
/*asteriskToken*/ undefined,
439-
enclosingFunctionFlags & FunctionFlags.Generator
440-
? createArrayLiteral([
441-
createLiteral("await"),
442-
createFunctionCall(returnMethod, iterator, [])
443-
])
444-
: createFunctionCall(returnMethod, iterator, [])
445-
)
446-
)
437+
createStatement(awaitAsYield(callReturn))
447438
),
448439
EmitFlags.SingleLine
449440
)
@@ -883,27 +874,39 @@ namespace ts {
883874
);
884875
}
885876

877+
const awaitHelper: EmitHelper = {
878+
name: "typescript:await",
879+
scoped: false,
880+
text: `
881+
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
882+
`
883+
};
884+
885+
function createAwaitHelper(context: TransformationContext, expression: Expression) {
886+
context.requestEmitHelper(awaitHelper);
887+
return createCall(createIdentifier("__await"), /*typeArguments*/ undefined, [expression]);
888+
}
889+
886890
const asyncGeneratorHelper: EmitHelper = {
887891
name: "typescript:asyncGenerator",
888892
scoped: false,
889893
text: `
890894
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
891895
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
892-
var g = generator.apply(thisArg, _arguments || []), q = [], c, i;
893-
return i = { next: verb("next"), "throw": verb("throw"), "return": verb("return") }, i[Symbol.asyncIterator] = function () { return this; }, i;
894-
function verb(n) { return function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]), next(); }); }; }
895-
function next() { if (!c && q.length) resume((c = q.shift())[0], c[1]); }
896-
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(c[3], e); } }
897-
function step(r) { r.done ? settle(c[2], r) : Promise.resolve(r.value[1]).then(r.value[0] === "yield" ? send : fulfill, reject); }
898-
function send(value) { settle(c[2], { value: value, done: false }); }
896+
var g = generator.apply(thisArg, _arguments || []), i, q = [];
897+
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
898+
function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
899+
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
900+
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
899901
function fulfill(value) { resume("next", value); }
900902
function reject(value) { resume("throw", value); }
901-
function settle(f, v) { c = void 0, f(v), next(); }
903+
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
902904
};
903905
`
904906
};
905907

906908
function createAsyncGeneratorHelper(context: TransformationContext, generatorFunc: FunctionExpression) {
909+
context.requestEmitHelper(awaitHelper);
907910
context.requestEmitHelper(asyncGeneratorHelper);
908911

909912
// Mark this node as originally an async function
@@ -925,16 +928,16 @@ namespace ts {
925928
scoped: false,
926929
text: `
927930
var __asyncDelegator = (this && this.__asyncDelegator) || function (o) {
928-
var i, f;
929-
return o = __asyncValues(o), i = { next: verb("next"), "throw": verb("throw"), "return": verb("return") }, i[Symbol.iterator] = function () { return this; }, i;
930-
function verb(n) { return o[n] && function (b) { return (f = !f) ? { value: ["await", new Promise(function(r) { r(o[n](b)); })], done: n === "return" } : b.done ? b : { value: ["yield", b.value], done: false }; }; }
931+
var i = { next: verb("next"), "throw": verb("throw"), "return": verb("return") }, p;
932+
return i[Symbol.iterator] = function () { return this; }, i;
933+
function verb(n) { return o[n] && function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : v; }; }
931934
};
932935
`
933936
};
934937

935938
function createAsyncDelegatorHelper(context: TransformationContext, expression: Expression, location?: TextRange) {
939+
context.requestEmitHelper(awaitHelper);
936940
context.requestEmitHelper(asyncDelegator);
937-
context.requestEmitHelper(asyncValues);
938941
return setTextRange(
939942
createCall(
940943
getHelperName("__asyncDelegator"),

0 commit comments

Comments
 (0)