Skip to content

Commit

Permalink
Do not await iterated value in for-await-of
Browse files Browse the repository at this point in the history
  • Loading branch information
rbuckton committed Jun 7, 2018
1 parent 53b599b commit 505677b
Show file tree
Hide file tree
Showing 5 changed files with 259 additions and 130 deletions.
2 changes: 1 addition & 1 deletion src/compiler/transformers/esnext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ namespace ts {
createLogicalNot(getDone)
),
/*incrementor*/ undefined,
/*statement*/ convertForOfStatementHead(node, createDownlevelAwait(getValue))
/*statement*/ convertForOfStatementHead(node, getValue)
),
/*location*/ node
),
Expand Down
144 changes: 144 additions & 0 deletions src/harness/unittests/forAwaitOfEvaluation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/// <reference path="..\harness.ts" />

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.`);
}

// tslint:disable-next-line:variable-name
const FakeSymbol: SymbolConstructor = ((description?: string) => Symbol(description)) as any;
(<any>FakeSymbol).prototype = Symbol.prototype;
for (const key of Object.getOwnPropertyNames(Symbol)) {
Object.defineProperty(FakeSymbol, key, Object.getOwnPropertyDescriptor(Symbol, key)!);
}
(<any>FakeSymbol).asyncIterator = (<any>FakeSymbol).asyncIterator || Symbol.for("Symbol.asyncIterator");

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<number>(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<number>(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<number>(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<number>(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);
});
});
}
12 changes: 6 additions & 6 deletions tests/baselines/reference/emitter.forAwait.es2015.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 }; }
Expand Down Expand Up @@ -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 }; }
Expand Down Expand Up @@ -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 }; }
Expand Down Expand Up @@ -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 }; }
Expand Down Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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;
}
}
Expand Down
12 changes: 6 additions & 6 deletions tests/baselines/reference/emitter.forAwait.es2017.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 }; }
Expand All @@ -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 }; }
Expand Down Expand Up @@ -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 }; }
Expand Down Expand Up @@ -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 }; }
Expand All @@ -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;
}
}
Expand Down Expand Up @@ -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;
}
}
Expand Down
Loading

0 comments on commit 505677b

Please sign in to comment.