diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts
index a0ab03a973112..db6069fd5ac9f 100644
--- a/src/compiler/transformers/esnext.ts
+++ b/src/compiler/transformers/esnext.ts
@@ -416,7 +416,7 @@ namespace ts {
createLogicalNot(getDone)
),
/*incrementor*/ undefined,
- /*statement*/ convertForOfStatementHead(node, createDownlevelAwait(getValue))
+ /*statement*/ convertForOfStatementHead(node, getValue)
),
/*location*/ node
),
diff --git a/src/harness/unittests/forAwaitOfEvaluation.ts b/src/harness/unittests/forAwaitOfEvaluation.ts
new file mode 100644
index 0000000000000..339e0ca664b9b
--- /dev/null
+++ b/src/harness/unittests/forAwaitOfEvaluation.ts
@@ -0,0 +1,148 @@
+///
+
+namespace ts {
+ declare var Symbol: SymbolConstructor;
+
+ describe("forAwaitOfEvaluation", () => {
+ const sourceFile = vpath.combine(vfs.srcFolder, "source.ts");
+
+ function compile(sourceText: string, options?: CompilerOptions) {
+ const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false);
+ fs.writeFileSync(sourceFile, sourceText);
+ const compilerOptions: CompilerOptions = { target: ScriptTarget.ES5, module: ModuleKind.CommonJS, lib: ["lib.esnext.d.ts"], ...options };
+ const host = new fakes.CompilerHost(fs, compilerOptions);
+ return compiler.compileFiles(host, [sourceFile], compilerOptions);
+ }
+
+ function noRequire(id: string) {
+ throw new Error(`Module '${id}' could not be found.`);
+ }
+
+ // Define a custom "Symbol" constructor to attach missing built-in symbols without
+ // modifying the global "Symbol" constructor
+ // tslint:disable-next-line:variable-name
+ const FakeSymbol: SymbolConstructor = ((description?: string) => Symbol(description)) as any;
+ (FakeSymbol).prototype = Symbol.prototype;
+ for (const key of Object.getOwnPropertyNames(Symbol)) {
+ Object.defineProperty(FakeSymbol, key, Object.getOwnPropertyDescriptor(Symbol, key)!);
+ }
+
+ // Add "asyncIterator" if missing
+ if (!hasProperty(FakeSymbol, "asyncIterator")) Object.defineProperty(FakeSymbol, "asyncIterator", { value: Symbol.for("Symbol.asyncIterator"), configurable: true });
+
+ function evaluate(result: compiler.CompilationResult) {
+ const output = result.getOutput(sourceFile, "js")!;
+ assert.isDefined(output);
+
+ const evaluateText = `(function (module, exports, require, __dirname, __filename, Symbol) { ${output.text} })`;
+ const evaluateThunk = eval(evaluateText) as (module: any, exports: any, require: (id: string) => any, dirname: string, filename: string, symbolConstructor: SymbolConstructor) => void;
+ const module: { exports: any; } = { exports: {} };
+ evaluateThunk(module, module.exports, noRequire, vpath.dirname(output.file), output.file, FakeSymbol);
+ return module;
+ }
+
+ it("sync (es5)", async () => {
+ const module = evaluate(compile(`
+ let i = 0;
+ const iterator = {
+ [Symbol.iterator]() { return this; },
+ next() {
+ switch (i++) {
+ case 0: return { value: 1, done: false };
+ case 1: return { value: Promise.resolve(2), done: false };
+ case 2: return { value: new Promise(resolve => setTimeout(resolve, 100, 3)), done: false };
+ default: return { value: undefined: done: true };
+ }
+ }
+ };
+ export const output: any[] = [];
+ export async function main() {
+ for await (const item of iterator) {
+ output.push(item);
+ }
+ }`));
+ await module.exports.main();
+ assert.strictEqual(module.exports.output[0], 1);
+ assert.strictEqual(module.exports.output[1], 2);
+ assert.strictEqual(module.exports.output[2], 3);
+ });
+
+ it("sync (es2015)", async () => {
+ const module = evaluate(compile(`
+ let i = 0;
+ const iterator = {
+ [Symbol.iterator]() { return this; },
+ next() {
+ switch (i++) {
+ case 0: return { value: 1, done: false };
+ case 1: return { value: Promise.resolve(2), done: false };
+ case 2: return { value: new Promise(resolve => setTimeout(resolve, 100, 3)), done: false };
+ default: return { value: undefined: done: true };
+ }
+ }
+ };
+ export const output: any[] = [];
+ export async function main() {
+ for await (const item of iterator) {
+ output.push(item);
+ }
+ }`, { target: ScriptTarget.ES2015 }));
+ await module.exports.main();
+ assert.strictEqual(module.exports.output[0], 1);
+ assert.strictEqual(module.exports.output[1], 2);
+ assert.strictEqual(module.exports.output[2], 3);
+ });
+
+ it("async (es5)", async () => {
+ const module = evaluate(compile(`
+ let i = 0;
+ const iterator = {
+ [Symbol.asyncIterator]() { return this; },
+ async next() {
+ switch (i++) {
+ case 0: return { value: 1, done: false };
+ case 1: return { value: Promise.resolve(2), done: false };
+ case 2: return { value: new Promise(resolve => setTimeout(resolve, 100, 3)), done: false };
+ default: return { value: undefined: done: true };
+ }
+ }
+ };
+ export const output: any[] = [];
+ export async function main() {
+ for await (const item of iterator) {
+ output.push(item);
+ }
+ }`));
+ await module.exports.main();
+ assert.strictEqual(module.exports.output[0], 1);
+ assert.instanceOf(module.exports.output[1], Promise);
+ assert.instanceOf(module.exports.output[2], Promise);
+ });
+
+ it("async (es2015)", async () => {
+ const module = evaluate(compile(`
+ let i = 0;
+ const iterator = {
+ [Symbol.asyncIterator]() { return this; },
+ async next() {
+ switch (i++) {
+ case 0: return { value: 1, done: false };
+ case 1: return { value: Promise.resolve(2), done: false };
+ case 2: return { value: new Promise(resolve => setTimeout(resolve, 100, 3)), done: false };
+ default: return { value: undefined: done: true };
+ }
+ }
+ };
+ export const output: any[] = [];
+ export async function main() {
+ for await (const item of iterator) {
+ output.push(item);
+ }
+ }`, { target: ScriptTarget.ES2015 }));
+ await module.exports.main();
+ assert.strictEqual(module.exports.output[0], 1);
+ assert.instanceOf(module.exports.output[1], Promise);
+ assert.instanceOf(module.exports.output[2], Promise);
+ });
+ });
+}
\ No newline at end of file
diff --git a/tests/baselines/reference/emitter.forAwait.es2015.js b/tests/baselines/reference/emitter.forAwait.es2015.js
index 6a29e7fad0a50..6260870471b13 100644
--- a/tests/baselines/reference/emitter.forAwait.es2015.js
+++ b/tests/baselines/reference/emitter.forAwait.es2015.js
@@ -63,7 +63,7 @@ function f1() {
let y;
try {
for (var y_1 = __asyncValues(y), y_1_1; y_1_1 = yield y_1.next(), !y_1_1.done;) {
- const x = yield y_1_1.value;
+ const x = y_1_1.value;
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
@@ -97,7 +97,7 @@ function f2() {
let x, y;
try {
for (var y_1 = __asyncValues(y), y_1_1; y_1_1 = yield y_1.next(), !y_1_1.done;) {
- x = yield y_1_1.value;
+ x = y_1_1.value;
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
@@ -135,7 +135,7 @@ function f3() {
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 yield __await(__await(y_1_1.value));
+ const x = y_1_1.value;
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
@@ -173,7 +173,7 @@ function f4() {
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 yield __await(__await(y_1_1.value));
+ x = y_1_1.value;
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
@@ -208,7 +208,7 @@ function f5() {
let y;
try {
outer: for (var y_1 = __asyncValues(y), y_1_1; y_1_1 = yield y_1.next(), !y_1_1.done;) {
- const x = yield y_1_1.value;
+ const x = y_1_1.value;
continue outer;
}
}
@@ -248,7 +248,7 @@ function f6() {
let y;
try {
outer: for (var y_1 = __asyncValues(y), y_1_1; y_1_1 = yield __await(y_1.next()), !y_1_1.done;) {
- const x = yield yield __await(__await(y_1_1.value));
+ const x = y_1_1.value;
continue outer;
}
}
diff --git a/tests/baselines/reference/emitter.forAwait.es2017.js b/tests/baselines/reference/emitter.forAwait.es2017.js
index 63e833e81d22d..dd0e8aede2bb8 100644
--- a/tests/baselines/reference/emitter.forAwait.es2017.js
+++ b/tests/baselines/reference/emitter.forAwait.es2017.js
@@ -54,7 +54,7 @@ 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;
+ const x = y_1_1.value;
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
@@ -78,7 +78,7 @@ 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;
+ x = y_1_1.value;
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
@@ -115,7 +115,7 @@ function f3() {
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 yield __await(__await(y_1_1.value));
+ const x = y_1_1.value;
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
@@ -153,7 +153,7 @@ function f4() {
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 yield __await(__await(y_1_1.value));
+ x = y_1_1.value;
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
@@ -179,7 +179,7 @@ async function f5() {
let y;
try {
outer: 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;
+ const x = y_1_1.value;
continue outer;
}
}
@@ -218,7 +218,7 @@ function f6() {
let y;
try {
outer: for (var y_1 = __asyncValues(y), y_1_1; y_1_1 = yield __await(y_1.next()), !y_1_1.done;) {
- const x = yield yield __await(__await(y_1_1.value));
+ const x = y_1_1.value;
continue outer;
}
}
diff --git a/tests/baselines/reference/emitter.forAwait.es5.js b/tests/baselines/reference/emitter.forAwait.es5.js
index a303b659cb0f7..f264820d3b1f2 100644
--- a/tests/baselines/reference/emitter.forAwait.es5.js
+++ b/tests/baselines/reference/emitter.forAwait.es5.js
@@ -90,35 +90,33 @@ function f1() {
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
- _b.trys.push([0, 6, 7, 12]);
+ _b.trys.push([0, 5, 6, 11]);
y_1 = __asyncValues(y);
_b.label = 1;
case 1: return [4 /*yield*/, y_1.next()];
case 2:
- if (!(y_1_1 = _b.sent(), !y_1_1.done)) return [3 /*break*/, 5];
- return [4 /*yield*/, y_1_1.value];
- case 3:
- x = _b.sent();
- _b.label = 4;
- case 4: return [3 /*break*/, 1];
- case 5: return [3 /*break*/, 12];
- case 6:
+ if (!(y_1_1 = _b.sent(), !y_1_1.done)) return [3 /*break*/, 4];
+ x = y_1_1.value;
+ _b.label = 3;
+ case 3: return [3 /*break*/, 1];
+ case 4: return [3 /*break*/, 11];
+ case 5:
e_1_1 = _b.sent();
e_1 = { error: e_1_1 };
- return [3 /*break*/, 12];
- case 7:
- _b.trys.push([7, , 10, 11]);
- if (!(y_1_1 && !y_1_1.done && (_a = y_1.return))) return [3 /*break*/, 9];
+ return [3 /*break*/, 11];
+ case 6:
+ _b.trys.push([6, , 9, 10]);
+ if (!(y_1_1 && !y_1_1.done && (_a = y_1.return))) return [3 /*break*/, 8];
return [4 /*yield*/, _a.call(y_1)];
- case 8:
+ case 7:
_b.sent();
- _b.label = 9;
- case 9: return [3 /*break*/, 11];
- case 10:
+ _b.label = 8;
+ case 8: return [3 /*break*/, 10];
+ case 9:
if (e_1) throw e_1.error;
return [7 /*endfinally*/];
- case 11: return [7 /*endfinally*/];
- case 12: return [2 /*return*/];
+ case 10: return [7 /*endfinally*/];
+ case 11: return [2 /*return*/];
}
});
});
@@ -172,35 +170,33 @@ function f2() {
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
- _b.trys.push([0, 6, 7, 12]);
+ _b.trys.push([0, 5, 6, 11]);
y_1 = __asyncValues(y);
_b.label = 1;
case 1: return [4 /*yield*/, y_1.next()];
case 2:
- if (!(y_1_1 = _b.sent(), !y_1_1.done)) return [3 /*break*/, 5];
- return [4 /*yield*/, y_1_1.value];
- case 3:
- x = _b.sent();
- _b.label = 4;
- case 4: return [3 /*break*/, 1];
- case 5: return [3 /*break*/, 12];
- case 6:
+ if (!(y_1_1 = _b.sent(), !y_1_1.done)) return [3 /*break*/, 4];
+ x = y_1_1.value;
+ _b.label = 3;
+ case 3: return [3 /*break*/, 1];
+ case 4: return [3 /*break*/, 11];
+ case 5:
e_1_1 = _b.sent();
e_1 = { error: e_1_1 };
- return [3 /*break*/, 12];
- case 7:
- _b.trys.push([7, , 10, 11]);
- if (!(y_1_1 && !y_1_1.done && (_a = y_1.return))) return [3 /*break*/, 9];
+ return [3 /*break*/, 11];
+ case 6:
+ _b.trys.push([6, , 9, 10]);
+ if (!(y_1_1 && !y_1_1.done && (_a = y_1.return))) return [3 /*break*/, 8];
return [4 /*yield*/, _a.call(y_1)];
- case 8:
+ case 7:
_b.sent();
- _b.label = 9;
- case 9: return [3 /*break*/, 11];
- case 10:
+ _b.label = 8;
+ case 8: return [3 /*break*/, 10];
+ case 9:
if (e_1) throw e_1.error;
return [7 /*endfinally*/];
- case 11: return [7 /*endfinally*/];
- case 12: return [2 /*return*/];
+ case 10: return [7 /*endfinally*/];
+ case 11: return [2 /*return*/];
}
});
});
@@ -258,36 +254,33 @@ function f3() {
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
- _b.trys.push([0, 7, 8, 13]);
+ _b.trys.push([0, 5, 6, 11]);
y_1 = __asyncValues(y);
_b.label = 1;
case 1: return [4 /*yield*/, __await(y_1.next())];
case 2:
- if (!(y_1_1 = _b.sent(), !y_1_1.done)) return [3 /*break*/, 6];
- return [4 /*yield*/, __await(__await(y_1_1.value))];
- case 3: return [4 /*yield*/, _b.sent()];
- case 4:
- x = _b.sent();
- _b.label = 5;
- case 5: return [3 /*break*/, 1];
- case 6: return [3 /*break*/, 13];
- case 7:
+ if (!(y_1_1 = _b.sent(), !y_1_1.done)) return [3 /*break*/, 4];
+ x = y_1_1.value;
+ _b.label = 3;
+ case 3: return [3 /*break*/, 1];
+ case 4: return [3 /*break*/, 11];
+ case 5:
e_1_1 = _b.sent();
e_1 = { error: e_1_1 };
- return [3 /*break*/, 13];
- case 8:
- _b.trys.push([8, , 11, 12]);
- if (!(y_1_1 && !y_1_1.done && (_a = y_1.return))) return [3 /*break*/, 10];
+ return [3 /*break*/, 11];
+ case 6:
+ _b.trys.push([6, , 9, 10]);
+ if (!(y_1_1 && !y_1_1.done && (_a = y_1.return))) return [3 /*break*/, 8];
return [4 /*yield*/, __await(_a.call(y_1))];
- case 9:
+ case 7:
_b.sent();
- _b.label = 10;
- case 10: return [3 /*break*/, 12];
- case 11:
+ _b.label = 8;
+ case 8: return [3 /*break*/, 10];
+ case 9:
if (e_1) throw e_1.error;
return [7 /*endfinally*/];
- case 12: return [7 /*endfinally*/];
- case 13: return [2 /*return*/];
+ case 10: return [7 /*endfinally*/];
+ case 11: return [2 /*return*/];
}
});
});
@@ -345,36 +338,33 @@ function f4() {
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
- _b.trys.push([0, 7, 8, 13]);
+ _b.trys.push([0, 5, 6, 11]);
y_1 = __asyncValues(y);
_b.label = 1;
case 1: return [4 /*yield*/, __await(y_1.next())];
case 2:
- if (!(y_1_1 = _b.sent(), !y_1_1.done)) return [3 /*break*/, 6];
- return [4 /*yield*/, __await(__await(y_1_1.value))];
- case 3: return [4 /*yield*/, _b.sent()];
- case 4:
- x = _b.sent();
- _b.label = 5;
- case 5: return [3 /*break*/, 1];
- case 6: return [3 /*break*/, 13];
- case 7:
+ if (!(y_1_1 = _b.sent(), !y_1_1.done)) return [3 /*break*/, 4];
+ x = y_1_1.value;
+ _b.label = 3;
+ case 3: return [3 /*break*/, 1];
+ case 4: return [3 /*break*/, 11];
+ case 5:
e_1_1 = _b.sent();
e_1 = { error: e_1_1 };
- return [3 /*break*/, 13];
- case 8:
- _b.trys.push([8, , 11, 12]);
- if (!(y_1_1 && !y_1_1.done && (_a = y_1.return))) return [3 /*break*/, 10];
+ return [3 /*break*/, 11];
+ case 6:
+ _b.trys.push([6, , 9, 10]);
+ if (!(y_1_1 && !y_1_1.done && (_a = y_1.return))) return [3 /*break*/, 8];
return [4 /*yield*/, __await(_a.call(y_1))];
- case 9:
+ case 7:
_b.sent();
- _b.label = 10;
- case 10: return [3 /*break*/, 12];
- case 11:
+ _b.label = 8;
+ case 8: return [3 /*break*/, 10];
+ case 9:
if (e_1) throw e_1.error;
return [7 /*endfinally*/];
- case 12: return [7 /*endfinally*/];
- case 13: return [2 /*return*/];
+ case 10: return [7 /*endfinally*/];
+ case 11: return [2 /*return*/];
}
});
});
@@ -429,35 +419,33 @@ function f5() {
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
- _b.trys.push([0, 6, 7, 12]);
+ _b.trys.push([0, 5, 6, 11]);
y_1 = __asyncValues(y);
_b.label = 1;
case 1: return [4 /*yield*/, y_1.next()];
case 2:
- if (!(y_1_1 = _b.sent(), !y_1_1.done)) return [3 /*break*/, 5];
- return [4 /*yield*/, y_1_1.value];
- case 3:
- x = _b.sent();
- return [3 /*break*/, 4];
- case 4: return [3 /*break*/, 1];
- case 5: return [3 /*break*/, 12];
- case 6:
+ if (!(y_1_1 = _b.sent(), !y_1_1.done)) return [3 /*break*/, 4];
+ x = y_1_1.value;
+ return [3 /*break*/, 3];
+ case 3: return [3 /*break*/, 1];
+ case 4: return [3 /*break*/, 11];
+ case 5:
e_1_1 = _b.sent();
e_1 = { error: e_1_1 };
- return [3 /*break*/, 12];
- case 7:
- _b.trys.push([7, , 10, 11]);
- if (!(y_1_1 && !y_1_1.done && (_a = y_1.return))) return [3 /*break*/, 9];
+ return [3 /*break*/, 11];
+ case 6:
+ _b.trys.push([6, , 9, 10]);
+ if (!(y_1_1 && !y_1_1.done && (_a = y_1.return))) return [3 /*break*/, 8];
return [4 /*yield*/, _a.call(y_1)];
- case 8:
+ case 7:
_b.sent();
- _b.label = 9;
- case 9: return [3 /*break*/, 11];
- case 10:
+ _b.label = 8;
+ case 8: return [3 /*break*/, 10];
+ case 9:
if (e_1) throw e_1.error;
return [7 /*endfinally*/];
- case 11: return [7 /*endfinally*/];
- case 12: return [2 /*return*/];
+ case 10: return [7 /*endfinally*/];
+ case 11: return [2 /*return*/];
}
});
});
@@ -516,36 +504,33 @@ function f6() {
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
- _b.trys.push([0, 7, 8, 13]);
+ _b.trys.push([0, 5, 6, 11]);
y_1 = __asyncValues(y);
_b.label = 1;
case 1: return [4 /*yield*/, __await(y_1.next())];
case 2:
- if (!(y_1_1 = _b.sent(), !y_1_1.done)) return [3 /*break*/, 6];
- return [4 /*yield*/, __await(__await(y_1_1.value))];
- case 3: return [4 /*yield*/, _b.sent()];
- case 4:
- x = _b.sent();
- return [3 /*break*/, 5];
- case 5: return [3 /*break*/, 1];
- case 6: return [3 /*break*/, 13];
- case 7:
+ if (!(y_1_1 = _b.sent(), !y_1_1.done)) return [3 /*break*/, 4];
+ x = y_1_1.value;
+ return [3 /*break*/, 3];
+ case 3: return [3 /*break*/, 1];
+ case 4: return [3 /*break*/, 11];
+ case 5:
e_1_1 = _b.sent();
e_1 = { error: e_1_1 };
- return [3 /*break*/, 13];
- case 8:
- _b.trys.push([8, , 11, 12]);
- if (!(y_1_1 && !y_1_1.done && (_a = y_1.return))) return [3 /*break*/, 10];
+ return [3 /*break*/, 11];
+ case 6:
+ _b.trys.push([6, , 9, 10]);
+ if (!(y_1_1 && !y_1_1.done && (_a = y_1.return))) return [3 /*break*/, 8];
return [4 /*yield*/, __await(_a.call(y_1))];
- case 9:
+ case 7:
_b.sent();
- _b.label = 10;
- case 10: return [3 /*break*/, 12];
- case 11:
+ _b.label = 8;
+ case 8: return [3 /*break*/, 10];
+ case 9:
if (e_1) throw e_1.error;
return [7 /*endfinally*/];
- case 12: return [7 /*endfinally*/];
- case 13: return [2 /*return*/];
+ case 10: return [7 /*endfinally*/];
+ case 11: return [2 /*return*/];
}
});
});