From a05a53b2a28d4bd4e6abc0c70cfa01301ae1e79b Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Mon, 5 Jun 2017 16:57:50 -0700 Subject: [PATCH] Fix for..await emit for es2017 --- src/compiler/transformers/esnext.ts | 12 +- .../reference/emitter.forAwait.es2017.js | 143 ++++++++++++++++++ .../reference/emitter.forAwait.es2017.symbols | 50 ++++++ .../reference/emitter.forAwait.es2017.types | 50 ++++++ .../forAwait/emitter.forAwait.es2017.ts | 26 ++++ 5 files changed, 276 insertions(+), 5 deletions(-) create mode 100644 tests/baselines/reference/emitter.forAwait.es2017.js create mode 100644 tests/baselines/reference/emitter.forAwait.es2017.symbols create mode 100644 tests/baselines/reference/emitter.forAwait.es2017.types create mode 100644 tests/cases/conformance/emitter/es2017/forAwait/emitter.forAwait.es2017.ts diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 6e2f70b5c35..a3aa0139aa4 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -351,8 +351,10 @@ namespace ts { ); } - function awaitAsYield(expression: Expression) { - return createYield(/*asteriskToken*/ undefined, enclosingFunctionFlags & FunctionFlags.Generator ? createAwaitHelper(context, expression) : expression); + function createDownlevelAwait(expression: Expression) { + return enclosingFunctionFlags & FunctionFlags.Generator + ? createYield(/*asteriskToken*/ undefined, createAwaitHelper(context, expression)) + : createAwait(expression); } function transformForAwaitOfStatement(node: ForOfStatement, outermostLabeledStatement: LabeledStatement) { @@ -385,11 +387,11 @@ namespace ts { EmitFlags.NoHoisting ), /*condition*/ createComma( - createAssignment(result, awaitAsYield(callNext)), + createAssignment(result, createDownlevelAwait(callNext)), createLogicalNot(getDone) ), /*incrementor*/ undefined, - /*statement*/ convertForOfStatementHead(node, awaitAsYield(getValue)) + /*statement*/ convertForOfStatementHead(node, createDownlevelAwait(getValue)) ), /*location*/ node ), @@ -434,7 +436,7 @@ namespace ts { createPropertyAccess(iterator, "return") ) ), - createStatement(awaitAsYield(callReturn)) + createStatement(createDownlevelAwait(callReturn)) ), EmitFlags.SingleLine ) diff --git a/tests/baselines/reference/emitter.forAwait.es2017.js b/tests/baselines/reference/emitter.forAwait.es2017.js new file mode 100644 index 00000000000..eb953781ab3 --- /dev/null +++ b/tests/baselines/reference/emitter.forAwait.es2017.js @@ -0,0 +1,143 @@ +//// [tests/cases/conformance/emitter/es2017/forAwait/emitter.forAwait.es2017.ts] //// + +//// [file1.ts] +async function f1() { + let y: any; + for await (const x of y) { + } +} +//// [file2.ts] +async function f2() { + let x: any, y: any; + for await (x of y) { + } +} +//// [file3.ts] +async function* f3() { + let y: any; + for await (const x of y) { + } +} +//// [file4.ts] +async function* f4() { + let x: any, y: any; + for await (x of y) { + } +} + +//// [file1.js] +var __asyncValues = (this && this.__asyncIterator) || function (o) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var m = o[Symbol.asyncIterator]; + return m ? m.call(o) : typeof __values === "function" ? __values(o) : o[Symbol.iterator](); +}; +async function f1() { + let y; + try { + for (var y_1 = __asyncValues(y), y_1_1; y_1_1 = await y_1.next(), !y_1_1.done;) { + const x = await y_1_1.value; + } + } + catch (e_1_1) { e_1 = { error: e_1_1 }; } + finally { + try { + if (y_1_1 && !y_1_1.done && (_a = y_1.return)) await _a.call(y_1); + } + finally { if (e_1) throw e_1.error; } + } + var e_1, _a; +} +//// [file2.js] +var __asyncValues = (this && this.__asyncIterator) || function (o) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var m = o[Symbol.asyncIterator]; + return m ? m.call(o) : typeof __values === "function" ? __values(o) : o[Symbol.iterator](); +}; +async function f2() { + let x, y; + try { + for (var y_1 = __asyncValues(y), y_1_1; y_1_1 = await y_1.next(), !y_1_1.done;) { + x = await y_1_1.value; + } + } + catch (e_1_1) { e_1 = { error: e_1_1 }; } + finally { + try { + if (y_1_1 && !y_1_1.done && (_a = y_1.return)) await _a.call(y_1); + } + finally { if (e_1) throw e_1.error; } + } + var e_1, _a; +} +//// [file3.js] +var __asyncValues = (this && this.__asyncIterator) || function (o) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var m = o[Symbol.asyncIterator]; + return m ? m.call(o) : typeof __values === "function" ? __values(o) : o[Symbol.iterator](); +}; +var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); } +var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var g = generator.apply(thisArg, _arguments || []), i, q = []; + return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; + 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); }); }; } + function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } + function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } + function fulfill(value) { resume("next", value); } + function reject(value) { resume("throw", value); } + function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } +}; +function f3() { + return __asyncGenerator(this, arguments, function* f3_1() { + let y; + try { + for (var y_1 = __asyncValues(y), y_1_1; y_1_1 = yield __await(y_1.next()), !y_1_1.done;) { + const x = yield __await(y_1_1.value); + } + } + catch (e_1_1) { e_1 = { error: e_1_1 }; } + finally { + try { + if (y_1_1 && !y_1_1.done && (_a = y_1.return)) yield __await(_a.call(y_1)); + } + finally { if (e_1) throw e_1.error; } + } + var e_1, _a; + }); +} +//// [file4.js] +var __asyncValues = (this && this.__asyncIterator) || function (o) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var m = o[Symbol.asyncIterator]; + return m ? m.call(o) : typeof __values === "function" ? __values(o) : o[Symbol.iterator](); +}; +var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); } +var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var g = generator.apply(thisArg, _arguments || []), i, q = []; + return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; + 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); }); }; } + function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } + function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } + function fulfill(value) { resume("next", value); } + function reject(value) { resume("throw", value); } + function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } +}; +function f4() { + return __asyncGenerator(this, arguments, function* f4_1() { + let x, y; + try { + for (var y_1 = __asyncValues(y), y_1_1; y_1_1 = yield __await(y_1.next()), !y_1_1.done;) { + x = yield __await(y_1_1.value); + } + } + catch (e_1_1) { e_1 = { error: e_1_1 }; } + finally { + try { + if (y_1_1 && !y_1_1.done && (_a = y_1.return)) yield __await(_a.call(y_1)); + } + finally { if (e_1) throw e_1.error; } + } + var e_1, _a; + }); +} diff --git a/tests/baselines/reference/emitter.forAwait.es2017.symbols b/tests/baselines/reference/emitter.forAwait.es2017.symbols new file mode 100644 index 00000000000..a08e31f5553 --- /dev/null +++ b/tests/baselines/reference/emitter.forAwait.es2017.symbols @@ -0,0 +1,50 @@ +=== tests/cases/conformance/emitter/es2017/forAwait/file1.ts === +async function f1() { +>f1 : Symbol(f1, Decl(file1.ts, 0, 0)) + + let y: any; +>y : Symbol(y, Decl(file1.ts, 1, 7)) + + for await (const x of y) { +>x : Symbol(x, Decl(file1.ts, 2, 20)) +>y : Symbol(y, Decl(file1.ts, 1, 7)) + } +} +=== tests/cases/conformance/emitter/es2017/forAwait/file2.ts === +async function f2() { +>f2 : Symbol(f2, Decl(file2.ts, 0, 0)) + + let x: any, y: any; +>x : Symbol(x, Decl(file2.ts, 1, 7)) +>y : Symbol(y, Decl(file2.ts, 1, 15)) + + for await (x of y) { +>x : Symbol(x, Decl(file2.ts, 1, 7)) +>y : Symbol(y, Decl(file2.ts, 1, 15)) + } +} +=== tests/cases/conformance/emitter/es2017/forAwait/file3.ts === +async function* f3() { +>f3 : Symbol(f3, Decl(file3.ts, 0, 0)) + + let y: any; +>y : Symbol(y, Decl(file3.ts, 1, 7)) + + for await (const x of y) { +>x : Symbol(x, Decl(file3.ts, 2, 20)) +>y : Symbol(y, Decl(file3.ts, 1, 7)) + } +} +=== tests/cases/conformance/emitter/es2017/forAwait/file4.ts === +async function* f4() { +>f4 : Symbol(f4, Decl(file4.ts, 0, 0)) + + let x: any, y: any; +>x : Symbol(x, Decl(file4.ts, 1, 7)) +>y : Symbol(y, Decl(file4.ts, 1, 15)) + + for await (x of y) { +>x : Symbol(x, Decl(file4.ts, 1, 7)) +>y : Symbol(y, Decl(file4.ts, 1, 15)) + } +} diff --git a/tests/baselines/reference/emitter.forAwait.es2017.types b/tests/baselines/reference/emitter.forAwait.es2017.types new file mode 100644 index 00000000000..0d886cca4cc --- /dev/null +++ b/tests/baselines/reference/emitter.forAwait.es2017.types @@ -0,0 +1,50 @@ +=== tests/cases/conformance/emitter/es2017/forAwait/file1.ts === +async function f1() { +>f1 : () => Promise + + let y: any; +>y : any + + for await (const x of y) { +>x : any +>y : any + } +} +=== tests/cases/conformance/emitter/es2017/forAwait/file2.ts === +async function f2() { +>f2 : () => Promise + + let x: any, y: any; +>x : any +>y : any + + for await (x of y) { +>x : any +>y : any + } +} +=== tests/cases/conformance/emitter/es2017/forAwait/file3.ts === +async function* f3() { +>f3 : () => AsyncIterableIterator + + let y: any; +>y : any + + for await (const x of y) { +>x : any +>y : any + } +} +=== tests/cases/conformance/emitter/es2017/forAwait/file4.ts === +async function* f4() { +>f4 : () => AsyncIterableIterator + + let x: any, y: any; +>x : any +>y : any + + for await (x of y) { +>x : any +>y : any + } +} diff --git a/tests/cases/conformance/emitter/es2017/forAwait/emitter.forAwait.es2017.ts b/tests/cases/conformance/emitter/es2017/forAwait/emitter.forAwait.es2017.ts new file mode 100644 index 00000000000..f2d1f46873d --- /dev/null +++ b/tests/cases/conformance/emitter/es2017/forAwait/emitter.forAwait.es2017.ts @@ -0,0 +1,26 @@ +// @target: es2017 +// @lib: esnext +// @filename: file1.ts +async function f1() { + let y: any; + for await (const x of y) { + } +} +// @filename: file2.ts +async function f2() { + let x: any, y: any; + for await (x of y) { + } +} +// @filename: file3.ts +async function* f3() { + let y: any; + for await (const x of y) { + } +} +// @filename: file4.ts +async function* f4() { + let x: any, y: any; + for await (x of y) { + } +} \ No newline at end of file