Skip to content

Commit c224a82

Browse files
committed
Do not await iterated value in for-await-of
1 parent 36c5803 commit c224a82

File tree

5 files changed

+259
-130
lines changed

5 files changed

+259
-130
lines changed

src/compiler/transformers/esnext.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ namespace ts {
416416
createLogicalNot(getDone)
417417
),
418418
/*incrementor*/ undefined,
419-
/*statement*/ convertForOfStatementHead(node, createDownlevelAwait(getValue))
419+
/*statement*/ convertForOfStatementHead(node, getValue)
420420
),
421421
/*location*/ node
422422
),
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/// <reference path="..\harness.ts" />
2+
3+
namespace ts {
4+
declare var Symbol: SymbolConstructor;
5+
6+
describe("forAwaitOfEvaluation", () => {
7+
const sourceFile = vpath.combine(vfs.srcFolder, "source.ts");
8+
9+
function compile(sourceText: string, options?: CompilerOptions) {
10+
const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false);
11+
fs.writeFileSync(sourceFile, sourceText);
12+
const compilerOptions: CompilerOptions = { target: ScriptTarget.ES5, module: ModuleKind.CommonJS, lib: ["lib.esnext.d.ts"], ...options };
13+
const host = new fakes.CompilerHost(fs, compilerOptions);
14+
return compiler.compileFiles(host, [sourceFile], compilerOptions);
15+
}
16+
17+
function noRequire(id: string) {
18+
throw new Error(`Module '${id}' could not be found.`);
19+
}
20+
21+
// tslint:disable-next-line:variable-name
22+
const FakeSymbol: SymbolConstructor = ((description?: string) => Symbol(description)) as any;
23+
(<any>FakeSymbol).prototype = Symbol.prototype;
24+
for (const key of Object.getOwnPropertyNames(Symbol)) {
25+
Object.defineProperty(FakeSymbol, key, Object.getOwnPropertyDescriptor(Symbol, key)!);
26+
}
27+
(<any>FakeSymbol).asyncIterator = (<any>FakeSymbol).asyncIterator || Symbol.for("Symbol.asyncIterator");
28+
29+
function evaluate(result: compiler.CompilationResult) {
30+
const output = result.getOutput(sourceFile, "js")!;
31+
assert.isDefined(output);
32+
33+
const evaluateText = `(function (module, exports, require, __dirname, __filename, Symbol) { ${output.text} })`;
34+
const evaluateThunk = eval(evaluateText) as (module: any, exports: any, require: (id: string) => any, dirname: string, filename: string, symbolConstructor: SymbolConstructor) => void;
35+
const module: { exports: any; } = { exports: {} };
36+
evaluateThunk(module, module.exports, noRequire, vpath.dirname(output.file), output.file, FakeSymbol);
37+
return module;
38+
}
39+
40+
it("sync (es5)", async () => {
41+
const module = evaluate(compile(`
42+
let i = 0;
43+
const iterator = {
44+
[Symbol.iterator]() { return this; },
45+
next() {
46+
switch (i++) {
47+
case 0: return { value: 1, done: false };
48+
case 1: return { value: Promise.resolve(2), done: false };
49+
case 2: return { value: new Promise<number>(resolve => setTimeout(resolve, 100, 3)), done: false };
50+
default: return { value: undefined: done: true };
51+
}
52+
}
53+
};
54+
export const output: any[] = [];
55+
export async function main() {
56+
for await (const item of iterator) {
57+
output.push(item);
58+
}
59+
}`));
60+
await module.exports.main();
61+
assert.strictEqual(module.exports.output[0], 1);
62+
assert.strictEqual(module.exports.output[1], 2);
63+
assert.strictEqual(module.exports.output[2], 3);
64+
});
65+
66+
it("sync (es2015)", async () => {
67+
const module = evaluate(compile(`
68+
let i = 0;
69+
const iterator = {
70+
[Symbol.iterator]() { return this; },
71+
next() {
72+
switch (i++) {
73+
case 0: return { value: 1, done: false };
74+
case 1: return { value: Promise.resolve(2), done: false };
75+
case 2: return { value: new Promise<number>(resolve => setTimeout(resolve, 100, 3)), done: false };
76+
default: return { value: undefined: done: true };
77+
}
78+
}
79+
};
80+
export const output: any[] = [];
81+
export async function main() {
82+
for await (const item of iterator) {
83+
output.push(item);
84+
}
85+
}`, { target: ScriptTarget.ES2015 }));
86+
await module.exports.main();
87+
assert.strictEqual(module.exports.output[0], 1);
88+
assert.strictEqual(module.exports.output[1], 2);
89+
assert.strictEqual(module.exports.output[2], 3);
90+
});
91+
92+
it("async (es5)", async () => {
93+
const module = evaluate(compile(`
94+
let i = 0;
95+
const iterator = {
96+
[Symbol.asyncIterator]() { return this; },
97+
async next() {
98+
switch (i++) {
99+
case 0: return { value: 1, done: false };
100+
case 1: return { value: Promise.resolve(2), done: false };
101+
case 2: return { value: new Promise<number>(resolve => setTimeout(resolve, 100, 3)), done: false };
102+
default: return { value: undefined: done: true };
103+
}
104+
}
105+
};
106+
export const output: any[] = [];
107+
export async function main() {
108+
for await (const item of iterator) {
109+
output.push(item);
110+
}
111+
}`));
112+
await module.exports.main();
113+
assert.strictEqual(module.exports.output[0], 1);
114+
assert.instanceOf(module.exports.output[1], Promise);
115+
assert.instanceOf(module.exports.output[2], Promise);
116+
});
117+
118+
it("async (es2015)", async () => {
119+
const module = evaluate(compile(`
120+
let i = 0;
121+
const iterator = {
122+
[Symbol.asyncIterator]() { return this; },
123+
async next() {
124+
switch (i++) {
125+
case 0: return { value: 1, done: false };
126+
case 1: return { value: Promise.resolve(2), done: false };
127+
case 2: return { value: new Promise<number>(resolve => setTimeout(resolve, 100, 3)), done: false };
128+
default: return { value: undefined: done: true };
129+
}
130+
}
131+
};
132+
export const output: any[] = [];
133+
export async function main() {
134+
for await (const item of iterator) {
135+
output.push(item);
136+
}
137+
}`, { target: ScriptTarget.ES2015 }));
138+
await module.exports.main();
139+
assert.strictEqual(module.exports.output[0], 1);
140+
assert.instanceOf(module.exports.output[1], Promise);
141+
assert.instanceOf(module.exports.output[2], Promise);
142+
});
143+
});
144+
}

tests/baselines/reference/emitter.forAwait.es2015.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ function f1() {
6363
let y;
6464
try {
6565
for (var y_1 = __asyncValues(y), y_1_1; y_1_1 = yield y_1.next(), !y_1_1.done;) {
66-
const x = yield y_1_1.value;
66+
const x = y_1_1.value;
6767
}
6868
}
6969
catch (e_1_1) { e_1 = { error: e_1_1 }; }
@@ -97,7 +97,7 @@ function f2() {
9797
let x, y;
9898
try {
9999
for (var y_1 = __asyncValues(y), y_1_1; y_1_1 = yield y_1.next(), !y_1_1.done;) {
100-
x = yield y_1_1.value;
100+
x = y_1_1.value;
101101
}
102102
}
103103
catch (e_1_1) { e_1 = { error: e_1_1 }; }
@@ -135,7 +135,7 @@ function f3() {
135135
let y;
136136
try {
137137
for (var y_1 = __asyncValues(y), y_1_1; y_1_1 = yield __await(y_1.next()), !y_1_1.done;) {
138-
const x = yield yield __await(__await(y_1_1.value));
138+
const x = y_1_1.value;
139139
}
140140
}
141141
catch (e_1_1) { e_1 = { error: e_1_1 }; }
@@ -173,7 +173,7 @@ function f4() {
173173
let x, y;
174174
try {
175175
for (var y_1 = __asyncValues(y), y_1_1; y_1_1 = yield __await(y_1.next()), !y_1_1.done;) {
176-
x = yield yield __await(__await(y_1_1.value));
176+
x = y_1_1.value;
177177
}
178178
}
179179
catch (e_1_1) { e_1 = { error: e_1_1 }; }
@@ -208,7 +208,7 @@ function f5() {
208208
let y;
209209
try {
210210
outer: for (var y_1 = __asyncValues(y), y_1_1; y_1_1 = yield y_1.next(), !y_1_1.done;) {
211-
const x = yield y_1_1.value;
211+
const x = y_1_1.value;
212212
continue outer;
213213
}
214214
}
@@ -248,7 +248,7 @@ function f6() {
248248
let y;
249249
try {
250250
outer: for (var y_1 = __asyncValues(y), y_1_1; y_1_1 = yield __await(y_1.next()), !y_1_1.done;) {
251-
const x = yield yield __await(__await(y_1_1.value));
251+
const x = y_1_1.value;
252252
continue outer;
253253
}
254254
}

tests/baselines/reference/emitter.forAwait.es2017.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ async function f1() {
5454
let y;
5555
try {
5656
for (var y_1 = __asyncValues(y), y_1_1; y_1_1 = await y_1.next(), !y_1_1.done;) {
57-
const x = await y_1_1.value;
57+
const x = y_1_1.value;
5858
}
5959
}
6060
catch (e_1_1) { e_1 = { error: e_1_1 }; }
@@ -78,7 +78,7 @@ async function f2() {
7878
let x, y;
7979
try {
8080
for (var y_1 = __asyncValues(y), y_1_1; y_1_1 = await y_1.next(), !y_1_1.done;) {
81-
x = await y_1_1.value;
81+
x = y_1_1.value;
8282
}
8383
}
8484
catch (e_1_1) { e_1 = { error: e_1_1 }; }
@@ -115,7 +115,7 @@ function f3() {
115115
let y;
116116
try {
117117
for (var y_1 = __asyncValues(y), y_1_1; y_1_1 = yield __await(y_1.next()), !y_1_1.done;) {
118-
const x = yield yield __await(__await(y_1_1.value));
118+
const x = y_1_1.value;
119119
}
120120
}
121121
catch (e_1_1) { e_1 = { error: e_1_1 }; }
@@ -153,7 +153,7 @@ function f4() {
153153
let x, y;
154154
try {
155155
for (var y_1 = __asyncValues(y), y_1_1; y_1_1 = yield __await(y_1.next()), !y_1_1.done;) {
156-
x = yield yield __await(__await(y_1_1.value));
156+
x = y_1_1.value;
157157
}
158158
}
159159
catch (e_1_1) { e_1 = { error: e_1_1 }; }
@@ -179,7 +179,7 @@ async function f5() {
179179
let y;
180180
try {
181181
outer: for (var y_1 = __asyncValues(y), y_1_1; y_1_1 = await y_1.next(), !y_1_1.done;) {
182-
const x = await y_1_1.value;
182+
const x = y_1_1.value;
183183
continue outer;
184184
}
185185
}
@@ -218,7 +218,7 @@ function f6() {
218218
let y;
219219
try {
220220
outer: for (var y_1 = __asyncValues(y), y_1_1; y_1_1 = yield __await(y_1.next()), !y_1_1.done;) {
221-
const x = yield yield __await(__await(y_1_1.value));
221+
const x = y_1_1.value;
222222
continue outer;
223223
}
224224
}

0 commit comments

Comments
 (0)