Skip to content

Commit 7d3f387

Browse files
authored
Properly handle AsyncGeneratorUnwrapYieldResumption (#56150)
1 parent ac75a5e commit 7d3f387

25 files changed

+285
-179
lines changed

src/compiler/factory/emitHelpers.ts

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -854,17 +854,18 @@ export const asyncGeneratorHelper: UnscopedEmitHelper = {
854854
scoped: false,
855855
dependencies: [awaitHelper],
856856
text: `
857-
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
858-
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
859-
var g = generator.apply(thisArg, _arguments || []), i, q = [];
860-
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
861-
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); }); }; }
862-
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
863-
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
864-
function fulfill(value) { resume("next", value); }
865-
function reject(value) { resume("throw", value); }
866-
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
867-
};`,
857+
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
858+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
859+
var g = generator.apply(thisArg, _arguments || []), i, q = [];
860+
return i = {}, verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;
861+
function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }
862+
function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }
863+
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
864+
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
865+
function fulfill(value) { resume("next", value); }
866+
function reject(value) { resume("throw", value); }
867+
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
868+
};`,
868869
};
869870

870871
/** @internal */

src/testRunner/unittests/evaluation/asyncGenerator.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,25 @@ describe("unittests:: evaluation:: asyncGeneratorEvaluation", () => {
6262
{ done: true, value: undefined },
6363
]);
6464
});
65+
it("pass promise to gen.return()", async () => {
66+
const result = evaluator.evaluateTypeScript(
67+
`
68+
export const output = [];
69+
async function* fn() {
70+
yield* [1]
71+
return 3
72+
}
73+
export async function main() {
74+
const it = fn();
75+
output.push(await it.next());
76+
output.push(await it.return(Promise.resolve(2)));
77+
}`,
78+
{ target: ts.ScriptTarget.ES2017 },
79+
);
80+
await result.main();
81+
assert.deepEqual(result.output, [
82+
{ done: false, value: 1 },
83+
{ done: true, value: 2 },
84+
]);
85+
});
6586
});

tests/baselines/reference/asyncImportNestedYield.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,9 @@ var __await = (this && this.__await) || function (v) { return this instanceof __
3737
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
3838
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
3939
var g = generator.apply(thisArg, _arguments || []), i, q = [];
40-
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
41-
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); }); }; }
40+
return i = {}, verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;
41+
function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }
42+
function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }
4243
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
4344
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
4445
function fulfill(value) { resume("next", value); }

tests/baselines/reference/awaitUsingDeclarations.1(target=es2015).js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,9 @@ var __await = (this && this.__await) || function (v) { return this instanceof __
158158
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
159159
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
160160
var g = generator.apply(thisArg, _arguments || []), i, q = [];
161-
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
162-
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); }); }; }
161+
return i = {}, verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;
162+
function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }
163+
function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }
163164
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
164165
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
165166
function fulfill(value) { resume("next", value); }

tests/baselines/reference/awaitUsingDeclarations.1(target=es2017).js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,9 @@ var __await = (this && this.__await) || function (v) { return this instanceof __
149149
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
150150
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
151151
var g = generator.apply(thisArg, _arguments || []), i, q = [];
152-
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
153-
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); }); }; }
152+
return i = {}, verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;
153+
function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }
154+
function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }
154155
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
155156
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
156157
function fulfill(value) { resume("next", value); }

tests/baselines/reference/awaitUsingDeclarations.1(target=es5).js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,9 @@ var __await = (this && this.__await) || function (v) { return this instanceof __
185185
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
186186
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
187187
var g = generator.apply(thisArg, _arguments || []), i, q = [];
188-
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
189-
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); }); }; }
188+
return i = {}, verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;
189+
function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }
190+
function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }
190191
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
191192
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
192193
function fulfill(value) { resume("next", value); }

tests/baselines/reference/blockScopedVariablesUseBeforeDef.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,9 @@ var __await = (this && this.__await) || function (v) { return this instanceof __
198198
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
199199
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
200200
var g = generator.apply(thisArg, _arguments || []), i, q = [];
201-
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
202-
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); }); }; }
201+
return i = {}, verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;
202+
function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }
203+
function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }
203204
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
204205
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
205206
function fulfill(value) { resume("next", value); }

tests/baselines/reference/dependentDestructuredVariables.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -451,8 +451,9 @@ var __await = (this && this.__await) || function (v) { return this instanceof __
451451
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
452452
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
453453
var g = generator.apply(thisArg, _arguments || []), i, q = [];
454-
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
455-
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); }); }; }
454+
return i = {}, verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;
455+
function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }
456+
function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }
456457
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
457458
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
458459
function fulfill(value) { resume("next", value); }

0 commit comments

Comments
 (0)