Skip to content

Commit 52a09b6

Browse files
committed
Add IteratorVoidReturnResult for optional 'value' when done
1 parent 3e824f1 commit 52a09b6

File tree

6 files changed

+692
-3
lines changed

6 files changed

+692
-3
lines changed

src/compiler/checker.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -905,6 +905,7 @@ namespace ts {
905905
let deferredGlobalGeneratorType: GenericType;
906906
let deferredGlobalIteratorYieldResultType: GenericType;
907907
let deferredGlobalIteratorReturnResultType: GenericType;
908+
let deferredGlobalIteratorVoidReturnResultType: ObjectType;
908909
let deferredGlobalAsyncIterableType: GenericType;
909910
let deferredGlobalAsyncIteratorType: GenericType;
910911
let deferredGlobalAsyncIterableIteratorType: GenericType;
@@ -12564,6 +12565,10 @@ namespace ts {
1256412565
return deferredGlobalIteratorReturnResultType || (deferredGlobalIteratorReturnResultType = getGlobalType("IteratorReturnResult" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType;
1256512566
}
1256612567

12568+
function getGlobalIteratorVoidReturnResultType(reportErrors: boolean) {
12569+
return deferredGlobalIteratorVoidReturnResultType || (deferredGlobalIteratorVoidReturnResultType = getGlobalType("IteratorVoidReturnResult" as __String, /*arity*/ 0, reportErrors)) || emptyObjectType;
12570+
}
12571+
1256712572
function getGlobalTypeOrUndefined(name: __String, arity = 0): ObjectType | undefined {
1256812573
const symbol = getGlobalSymbol(name, SymbolFlags.Type, /*diagnostic*/ undefined);
1256912574
return symbol && <GenericType>getTypeOfGlobalSymbol(symbol, arity);
@@ -34431,6 +34436,9 @@ namespace ts {
3443134436
const returnType = getTypeArguments(type as GenericType)[0];
3443234437
return setCachedIterationTypes(type, "iterationTypesOfIteratorResult", createIterationTypes(/*yieldType*/ undefined, returnType, /*nextType*/ undefined));
3443334438
}
34439+
if (isReferenceToType(type, getGlobalIteratorVoidReturnResultType(/*reportErrors*/ false))) {
34440+
return setCachedIterationTypes(type, "iterationTypesOfIteratorResult", createIterationTypes(/*yieldType*/ undefined, voidType, /*nextType*/ undefined));
34441+
}
3443434442

3443534443
// Choose any constituents that can produce the requested iteration type.
3443634444
const yieldIteratorResult = filterType(type, isYieldIteratorResult);

src/lib/es2015.iterable.d.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,15 @@ interface IteratorReturnResult<TReturn> {
1818
value: TReturn;
1919
}
2020

21-
type IteratorResult<T, TReturn = any> = IteratorYieldResult<T> | IteratorReturnResult<TReturn>;
21+
interface IteratorVoidReturnResult {
22+
done: true;
23+
value?: void;
24+
}
25+
26+
type IteratorResult<T, TReturn = any> =
27+
| IteratorYieldResult<T>
28+
| IteratorReturnResult<TReturn>
29+
| (TReturn extends void ? IteratorVoidReturnResult : never);
2230

2331
interface Iterator<T, TReturn = any, TNext = undefined> {
2432
// NOTE: 'next' is defined using a tuple to ensure we report the correct assignability errors in all places.
Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
=== tests/cases/compiler/iteratorVoidResult.ts ===
2+
// @strict
3+
4+
//
5+
// Iterators with 'void'
6+
//
7+
8+
const o1 = {
9+
>o1 : Symbol(o1, Decl(iteratorVoidResult.ts, 6, 5))
10+
11+
[Symbol.iterator]() {
12+
>[Symbol.iterator] : Symbol([Symbol.iterator], Decl(iteratorVoidResult.ts, 6, 12))
13+
>Symbol.iterator : Symbol(SymbolConstructor.iterator, Decl(lib.es2015.iterable.d.ts, --, --))
14+
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --))
15+
>iterator : Symbol(SymbolConstructor.iterator, Decl(lib.es2015.iterable.d.ts, --, --))
16+
17+
return {
18+
next(): IteratorResult<number, void> {
19+
>next : Symbol(next, Decl(iteratorVoidResult.ts, 8, 16))
20+
>IteratorResult : Symbol(IteratorResult, Decl(lib.es2015.iterable.d.ts, --, --))
21+
22+
return { done: true };
23+
>done : Symbol(done, Decl(iteratorVoidResult.ts, 10, 24))
24+
}
25+
};
26+
}
27+
};
28+
29+
// should still be iterable
30+
for (const _ of o1) {}
31+
>_ : Symbol(_, Decl(iteratorVoidResult.ts, 17, 10))
32+
>o1 : Symbol(o1, Decl(iteratorVoidResult.ts, 6, 5))
33+
34+
// should still be spreadable
35+
const a1 = [...o1];
36+
>a1 : Symbol(a1, Decl(iteratorVoidResult.ts, 20, 5))
37+
>o1 : Symbol(o1, Decl(iteratorVoidResult.ts, 6, 5))
38+
39+
// should still destructure
40+
const [e1] = o1;
41+
>e1 : Symbol(e1, Decl(iteratorVoidResult.ts, 23, 7))
42+
>o1 : Symbol(o1, Decl(iteratorVoidResult.ts, 6, 5))
43+
44+
// verify value of r1
45+
const r1 = o1[Symbol.iterator]().next();
46+
>r1 : Symbol(r1, Decl(iteratorVoidResult.ts, 26, 5))
47+
>o1[Symbol.iterator]().next : Symbol(next, Decl(iteratorVoidResult.ts, 8, 16))
48+
>o1 : Symbol(o1, Decl(iteratorVoidResult.ts, 6, 5))
49+
>Symbol.iterator : Symbol(SymbolConstructor.iterator, Decl(lib.es2015.iterable.d.ts, --, --))
50+
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --))
51+
>iterator : Symbol(SymbolConstructor.iterator, Decl(lib.es2015.iterable.d.ts, --, --))
52+
>next : Symbol(next, Decl(iteratorVoidResult.ts, 8, 16))
53+
54+
if (r1.done) r1.value;
55+
>r1.done : Symbol(done, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --))
56+
>r1 : Symbol(r1, Decl(iteratorVoidResult.ts, 26, 5))
57+
>done : Symbol(done, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --))
58+
>r1.value : Symbol(value, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --))
59+
>r1 : Symbol(r1, Decl(iteratorVoidResult.ts, 26, 5))
60+
>value : Symbol(value, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --))
61+
62+
(function* () {
63+
// verify result of yield*
64+
const x1 = yield * o1;
65+
>x1 : Symbol(x1, Decl(iteratorVoidResult.ts, 31, 9))
66+
>o1 : Symbol(o1, Decl(iteratorVoidResult.ts, 6, 5))
67+
68+
});
69+
70+
const o2 = {
71+
>o2 : Symbol(o2, Decl(iteratorVoidResult.ts, 34, 5))
72+
73+
[Symbol.iterator]() {
74+
>[Symbol.iterator] : Symbol([Symbol.iterator], Decl(iteratorVoidResult.ts, 34, 12))
75+
>Symbol.iterator : Symbol(SymbolConstructor.iterator, Decl(lib.es2015.iterable.d.ts, --, --))
76+
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --))
77+
>iterator : Symbol(SymbolConstructor.iterator, Decl(lib.es2015.iterable.d.ts, --, --))
78+
79+
return {
80+
next(): IteratorResult<number, number | void> {
81+
>next : Symbol(next, Decl(iteratorVoidResult.ts, 36, 16))
82+
>IteratorResult : Symbol(IteratorResult, Decl(lib.es2015.iterable.d.ts, --, --))
83+
84+
return { done: true };
85+
>done : Symbol(done, Decl(iteratorVoidResult.ts, 38, 24))
86+
}
87+
};
88+
}
89+
};
90+
91+
// should still be iterable
92+
for (const _ of o2) {}
93+
>_ : Symbol(_, Decl(iteratorVoidResult.ts, 45, 10))
94+
>o2 : Symbol(o2, Decl(iteratorVoidResult.ts, 34, 5))
95+
96+
// should still be spreadable
97+
const a2 = [...o2];
98+
>a2 : Symbol(a2, Decl(iteratorVoidResult.ts, 48, 5))
99+
>o2 : Symbol(o2, Decl(iteratorVoidResult.ts, 34, 5))
100+
101+
// should still destructure
102+
const [e2] = o2;
103+
>e2 : Symbol(e2, Decl(iteratorVoidResult.ts, 51, 7))
104+
>o2 : Symbol(o2, Decl(iteratorVoidResult.ts, 34, 5))
105+
106+
// verify value of r2
107+
const r2 = o2[Symbol.iterator]().next();
108+
>r2 : Symbol(r2, Decl(iteratorVoidResult.ts, 54, 5))
109+
>o2[Symbol.iterator]().next : Symbol(next, Decl(iteratorVoidResult.ts, 36, 16))
110+
>o2 : Symbol(o2, Decl(iteratorVoidResult.ts, 34, 5))
111+
>Symbol.iterator : Symbol(SymbolConstructor.iterator, Decl(lib.es2015.iterable.d.ts, --, --))
112+
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --))
113+
>iterator : Symbol(SymbolConstructor.iterator, Decl(lib.es2015.iterable.d.ts, --, --))
114+
>next : Symbol(next, Decl(iteratorVoidResult.ts, 36, 16))
115+
116+
if (r2.done) r2.value;
117+
>r2.done : Symbol(done, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --))
118+
>r2 : Symbol(r2, Decl(iteratorVoidResult.ts, 54, 5))
119+
>done : Symbol(done, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --))
120+
>r2.value : Symbol(value, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --))
121+
>r2 : Symbol(r2, Decl(iteratorVoidResult.ts, 54, 5))
122+
>value : Symbol(value, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --))
123+
124+
(function* () {
125+
// verify result of yield*
126+
const x2 = yield * o2;
127+
>x2 : Symbol(x2, Decl(iteratorVoidResult.ts, 59, 9))
128+
>o2 : Symbol(o2, Decl(iteratorVoidResult.ts, 34, 5))
129+
130+
});
131+
132+
//
133+
// AsyncIterators with 'void'
134+
//
135+
136+
async function main() {
137+
>main : Symbol(main, Decl(iteratorVoidResult.ts, 60, 3))
138+
139+
// should still be iterable
140+
for await (const _ of o1) {}
141+
>_ : Symbol(_, Decl(iteratorVoidResult.ts, 68, 20))
142+
>o1 : Symbol(o1, Decl(iteratorVoidResult.ts, 6, 5))
143+
144+
for await (const _ of o2) {}
145+
>_ : Symbol(_, Decl(iteratorVoidResult.ts, 69, 20))
146+
>o2 : Symbol(o2, Decl(iteratorVoidResult.ts, 34, 5))
147+
148+
const o3 = {
149+
>o3 : Symbol(o3, Decl(iteratorVoidResult.ts, 71, 9))
150+
151+
[Symbol.asyncIterator]() {
152+
>[Symbol.asyncIterator] : Symbol([Symbol.asyncIterator], Decl(iteratorVoidResult.ts, 71, 16))
153+
>Symbol.asyncIterator : Symbol(SymbolConstructor.asyncIterator, Decl(lib.es2018.asynciterable.d.ts, --, --))
154+
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --))
155+
>asyncIterator : Symbol(SymbolConstructor.asyncIterator, Decl(lib.es2018.asynciterable.d.ts, --, --))
156+
157+
return {
158+
async next(): Promise<IteratorResult<number, void>> {
159+
>next : Symbol(next, Decl(iteratorVoidResult.ts, 73, 20))
160+
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --))
161+
>IteratorResult : Symbol(IteratorResult, Decl(lib.es2015.iterable.d.ts, --, --))
162+
163+
return { done: true };
164+
>done : Symbol(done, Decl(iteratorVoidResult.ts, 75, 28))
165+
}
166+
};
167+
}
168+
};
169+
170+
// should still be iterable
171+
for await (const _ of o3) {}
172+
>_ : Symbol(_, Decl(iteratorVoidResult.ts, 82, 20))
173+
>o3 : Symbol(o3, Decl(iteratorVoidResult.ts, 71, 9))
174+
175+
// verify value of r3
176+
const r3 = await o3[Symbol.asyncIterator]().next();
177+
>r3 : Symbol(r3, Decl(iteratorVoidResult.ts, 85, 9))
178+
>o3[Symbol.asyncIterator]().next : Symbol(next, Decl(iteratorVoidResult.ts, 73, 20))
179+
>o3 : Symbol(o3, Decl(iteratorVoidResult.ts, 71, 9))
180+
>Symbol.asyncIterator : Symbol(SymbolConstructor.asyncIterator, Decl(lib.es2018.asynciterable.d.ts, --, --))
181+
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --))
182+
>asyncIterator : Symbol(SymbolConstructor.asyncIterator, Decl(lib.es2018.asynciterable.d.ts, --, --))
183+
>next : Symbol(next, Decl(iteratorVoidResult.ts, 73, 20))
184+
185+
if (r3.done) r3.value;
186+
>r3.done : Symbol(done, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --))
187+
>r3 : Symbol(r3, Decl(iteratorVoidResult.ts, 85, 9))
188+
>done : Symbol(done, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --))
189+
>r3.value : Symbol(value, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --))
190+
>r3 : Symbol(r3, Decl(iteratorVoidResult.ts, 85, 9))
191+
>value : Symbol(value, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --))
192+
193+
(async function* () {
194+
// verify result of yield*
195+
const x1 = yield * o3;
196+
>x1 : Symbol(x1, Decl(iteratorVoidResult.ts, 90, 13))
197+
>o3 : Symbol(o3, Decl(iteratorVoidResult.ts, 71, 9))
198+
199+
});
200+
201+
const o4 = {
202+
>o4 : Symbol(o4, Decl(iteratorVoidResult.ts, 93, 9))
203+
204+
[Symbol.asyncIterator]() {
205+
>[Symbol.asyncIterator] : Symbol([Symbol.asyncIterator], Decl(iteratorVoidResult.ts, 93, 16))
206+
>Symbol.asyncIterator : Symbol(SymbolConstructor.asyncIterator, Decl(lib.es2018.asynciterable.d.ts, --, --))
207+
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --))
208+
>asyncIterator : Symbol(SymbolConstructor.asyncIterator, Decl(lib.es2018.asynciterable.d.ts, --, --))
209+
210+
return {
211+
async next(): Promise<IteratorResult<number, number | void>> {
212+
>next : Symbol(next, Decl(iteratorVoidResult.ts, 95, 20))
213+
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --))
214+
>IteratorResult : Symbol(IteratorResult, Decl(lib.es2015.iterable.d.ts, --, --))
215+
216+
return { done: true };
217+
>done : Symbol(done, Decl(iteratorVoidResult.ts, 97, 28))
218+
}
219+
};
220+
}
221+
};
222+
223+
// should still be iterable
224+
for await (const _ of o4) {}
225+
>_ : Symbol(_, Decl(iteratorVoidResult.ts, 104, 20))
226+
>o4 : Symbol(o4, Decl(iteratorVoidResult.ts, 93, 9))
227+
228+
// verify value of r4
229+
const r4 = await o4[Symbol.asyncIterator]().next();
230+
>r4 : Symbol(r4, Decl(iteratorVoidResult.ts, 107, 9))
231+
>o4[Symbol.asyncIterator]().next : Symbol(next, Decl(iteratorVoidResult.ts, 95, 20))
232+
>o4 : Symbol(o4, Decl(iteratorVoidResult.ts, 93, 9))
233+
>Symbol.asyncIterator : Symbol(SymbolConstructor.asyncIterator, Decl(lib.es2018.asynciterable.d.ts, --, --))
234+
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --))
235+
>asyncIterator : Symbol(SymbolConstructor.asyncIterator, Decl(lib.es2018.asynciterable.d.ts, --, --))
236+
>next : Symbol(next, Decl(iteratorVoidResult.ts, 95, 20))
237+
238+
if (r4.done) r4.value;
239+
>r4.done : Symbol(done, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --))
240+
>r4 : Symbol(r4, Decl(iteratorVoidResult.ts, 107, 9))
241+
>done : Symbol(done, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --))
242+
>r4.value : Symbol(value, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --))
243+
>r4 : Symbol(r4, Decl(iteratorVoidResult.ts, 107, 9))
244+
>value : Symbol(value, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --))
245+
246+
(async function* () {
247+
// verify result of yield*
248+
const x4 = yield * o4;
249+
>x4 : Symbol(x4, Decl(iteratorVoidResult.ts, 112, 13))
250+
>o4 : Symbol(o4, Decl(iteratorVoidResult.ts, 93, 9))
251+
252+
});
253+
}
254+

0 commit comments

Comments
 (0)