Skip to content

Commit 2a90a73

Browse files
authored
Fixed an issue with "slow" sync iteration types spoiling cached value for async ones (#62676)
1 parent 11ee01b commit 2a90a73

File tree

4 files changed

+285
-11
lines changed

4 files changed

+285
-11
lines changed

src/compiler/checker.ts

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45924,7 +45924,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4592445924
let noCache = false;
4592545925

4592645926
if (use & IterationUse.AllowsAsyncIterablesFlag) {
45927-
const iterationTypes = getIterationTypesOfIterableCached(type, asyncIterationTypesResolver) ||
45927+
let iterationTypes = getIterationTypesOfIterableCached(type, asyncIterationTypesResolver) ||
4592845928
getIterationTypesOfIterableFast(type, asyncIterationTypesResolver);
4592945929
if (iterationTypes) {
4593045930
if (iterationTypes === noIterationTypes && errorNode) {
@@ -45937,6 +45937,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4593745937
iterationTypes;
4593845938
}
4593945939
}
45940+
iterationTypes = getIterationTypesOfIterableSlow(type, asyncIterationTypesResolver, errorNode, errorOutputContainer, noCache);
45941+
if (iterationTypes !== noIterationTypes) {
45942+
return iterationTypes;
45943+
}
4594045944
}
4594145945

4594245946
if (use & IterationUse.AllowsSyncIterablesFlag) {
@@ -45960,17 +45964,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4596045964
}
4596145965
}
4596245966
}
45963-
}
4596445967

45965-
if (use & IterationUse.AllowsAsyncIterablesFlag) {
45966-
const iterationTypes = getIterationTypesOfIterableSlow(type, asyncIterationTypesResolver, errorNode, errorOutputContainer, noCache);
45967-
if (iterationTypes !== noIterationTypes) {
45968-
return iterationTypes;
45969-
}
45970-
}
45971-
45972-
if (use & IterationUse.AllowsSyncIterablesFlag) {
45973-
let iterationTypes = getIterationTypesOfIterableSlow(type, syncIterationTypesResolver, errorNode, errorOutputContainer, noCache);
45968+
iterationTypes = getIterationTypesOfIterableSlow(type, syncIterationTypesResolver, errorNode, errorOutputContainer, noCache);
4597445969
if (iterationTypes !== noIterationTypes) {
4597545970
if (use & IterationUse.AllowsAsyncIterablesFlag) {
4597645971
iterationTypes = getAsyncFromSyncIterationTypes(iterationTypes, errorNode);
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
//// [tests/cases/compiler/forAwaitForIntersection1.ts] ////
2+
3+
=== forAwaitForIntersection1.ts ===
4+
type Stream1<T_Sync, T_Async> = Iterable<T_Sync> & AsyncIterable<T_Async>;
5+
>Stream1 : Symbol(Stream1, Decl(forAwaitForIntersection1.ts, 0, 0))
6+
>T_Sync : Symbol(T_Sync, Decl(forAwaitForIntersection1.ts, 0, 13))
7+
>T_Async : Symbol(T_Async, Decl(forAwaitForIntersection1.ts, 0, 20))
8+
>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --))
9+
>T_Sync : Symbol(T_Sync, Decl(forAwaitForIntersection1.ts, 0, 13))
10+
>AsyncIterable : Symbol(AsyncIterable, Decl(lib.es2018.asynciterable.d.ts, --, --))
11+
>T_Async : Symbol(T_Async, Decl(forAwaitForIntersection1.ts, 0, 20))
12+
13+
class A1 {}
14+
>A1 : Symbol(A1, Decl(forAwaitForIntersection1.ts, 0, 74))
15+
16+
class B1 {}
17+
>B1 : Symbol(B1, Decl(forAwaitForIntersection1.ts, 2, 11))
18+
19+
async function loop1(stream: Stream1<A1, B1>) {
20+
>loop1 : Symbol(loop1, Decl(forAwaitForIntersection1.ts, 3, 11))
21+
>stream : Symbol(stream, Decl(forAwaitForIntersection1.ts, 5, 21))
22+
>Stream1 : Symbol(Stream1, Decl(forAwaitForIntersection1.ts, 0, 0))
23+
>A1 : Symbol(A1, Decl(forAwaitForIntersection1.ts, 0, 74))
24+
>B1 : Symbol(B1, Decl(forAwaitForIntersection1.ts, 2, 11))
25+
26+
for await (const b of stream) {}
27+
>b : Symbol(b, Decl(forAwaitForIntersection1.ts, 6, 18))
28+
>stream : Symbol(stream, Decl(forAwaitForIntersection1.ts, 5, 21))
29+
}
30+
31+
type Stream2<T_Sync, T_Async> = Iterable<T_Sync> & AsyncIterable<T_Async>;
32+
>Stream2 : Symbol(Stream2, Decl(forAwaitForIntersection1.ts, 7, 1))
33+
>T_Sync : Symbol(T_Sync, Decl(forAwaitForIntersection1.ts, 9, 13))
34+
>T_Async : Symbol(T_Async, Decl(forAwaitForIntersection1.ts, 9, 20))
35+
>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --))
36+
>T_Sync : Symbol(T_Sync, Decl(forAwaitForIntersection1.ts, 9, 13))
37+
>AsyncIterable : Symbol(AsyncIterable, Decl(lib.es2018.asynciterable.d.ts, --, --))
38+
>T_Async : Symbol(T_Async, Decl(forAwaitForIntersection1.ts, 9, 20))
39+
40+
class A2 {}
41+
>A2 : Symbol(A2, Decl(forAwaitForIntersection1.ts, 9, 74))
42+
43+
class B2 {}
44+
>B2 : Symbol(B2, Decl(forAwaitForIntersection1.ts, 11, 11))
45+
46+
async function loop2(stream: Stream2<A2, B2>) {
47+
>loop2 : Symbol(loop2, Decl(forAwaitForIntersection1.ts, 12, 11))
48+
>stream : Symbol(stream, Decl(forAwaitForIntersection1.ts, 14, 21))
49+
>Stream2 : Symbol(Stream2, Decl(forAwaitForIntersection1.ts, 7, 1))
50+
>A2 : Symbol(A2, Decl(forAwaitForIntersection1.ts, 9, 74))
51+
>B2 : Symbol(B2, Decl(forAwaitForIntersection1.ts, 11, 11))
52+
53+
for (const a of stream) {}
54+
>a : Symbol(a, Decl(forAwaitForIntersection1.ts, 15, 12))
55+
>stream : Symbol(stream, Decl(forAwaitForIntersection1.ts, 14, 21))
56+
}
57+
58+
type Stream3<T_Sync, T_Async> = Iterable<T_Sync> & AsyncIterable<T_Async>;
59+
>Stream3 : Symbol(Stream3, Decl(forAwaitForIntersection1.ts, 16, 1))
60+
>T_Sync : Symbol(T_Sync, Decl(forAwaitForIntersection1.ts, 18, 13))
61+
>T_Async : Symbol(T_Async, Decl(forAwaitForIntersection1.ts, 18, 20))
62+
>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --))
63+
>T_Sync : Symbol(T_Sync, Decl(forAwaitForIntersection1.ts, 18, 13))
64+
>AsyncIterable : Symbol(AsyncIterable, Decl(lib.es2018.asynciterable.d.ts, --, --))
65+
>T_Async : Symbol(T_Async, Decl(forAwaitForIntersection1.ts, 18, 20))
66+
67+
class A3 {}
68+
>A3 : Symbol(A3, Decl(forAwaitForIntersection1.ts, 18, 74))
69+
70+
class B3 {}
71+
>B3 : Symbol(B3, Decl(forAwaitForIntersection1.ts, 20, 11))
72+
73+
async function loop3(stream: Stream3<A3, B3>) {
74+
>loop3 : Symbol(loop3, Decl(forAwaitForIntersection1.ts, 21, 11))
75+
>stream : Symbol(stream, Decl(forAwaitForIntersection1.ts, 23, 21))
76+
>Stream3 : Symbol(Stream3, Decl(forAwaitForIntersection1.ts, 16, 1))
77+
>A3 : Symbol(A3, Decl(forAwaitForIntersection1.ts, 18, 74))
78+
>B3 : Symbol(B3, Decl(forAwaitForIntersection1.ts, 20, 11))
79+
80+
for await (const b of stream) {}
81+
>b : Symbol(b, Decl(forAwaitForIntersection1.ts, 24, 18))
82+
>stream : Symbol(stream, Decl(forAwaitForIntersection1.ts, 23, 21))
83+
84+
for (const a of stream) {}
85+
>a : Symbol(a, Decl(forAwaitForIntersection1.ts, 26, 12))
86+
>stream : Symbol(stream, Decl(forAwaitForIntersection1.ts, 23, 21))
87+
}
88+
89+
type Stream4<T_Sync, T_Async> = Iterable<T_Sync> & AsyncIterable<T_Async>;
90+
>Stream4 : Symbol(Stream4, Decl(forAwaitForIntersection1.ts, 27, 1))
91+
>T_Sync : Symbol(T_Sync, Decl(forAwaitForIntersection1.ts, 29, 13))
92+
>T_Async : Symbol(T_Async, Decl(forAwaitForIntersection1.ts, 29, 20))
93+
>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --))
94+
>T_Sync : Symbol(T_Sync, Decl(forAwaitForIntersection1.ts, 29, 13))
95+
>AsyncIterable : Symbol(AsyncIterable, Decl(lib.es2018.asynciterable.d.ts, --, --))
96+
>T_Async : Symbol(T_Async, Decl(forAwaitForIntersection1.ts, 29, 20))
97+
98+
class A4 {}
99+
>A4 : Symbol(A4, Decl(forAwaitForIntersection1.ts, 29, 74))
100+
101+
class B4 {}
102+
>B4 : Symbol(B4, Decl(forAwaitForIntersection1.ts, 31, 11))
103+
104+
// verify that resolving sync iteration first doesn't spoil the type for async iteration
105+
async function loop4(stream: Stream4<A4, B4>) {
106+
>loop4 : Symbol(loop4, Decl(forAwaitForIntersection1.ts, 32, 11))
107+
>stream : Symbol(stream, Decl(forAwaitForIntersection1.ts, 35, 21))
108+
>Stream4 : Symbol(Stream4, Decl(forAwaitForIntersection1.ts, 27, 1))
109+
>A4 : Symbol(A4, Decl(forAwaitForIntersection1.ts, 29, 74))
110+
>B4 : Symbol(B4, Decl(forAwaitForIntersection1.ts, 31, 11))
111+
112+
for (const a of stream) {}
113+
>a : Symbol(a, Decl(forAwaitForIntersection1.ts, 36, 12))
114+
>stream : Symbol(stream, Decl(forAwaitForIntersection1.ts, 35, 21))
115+
116+
for await (const b of stream) {}
117+
>b : Symbol(b, Decl(forAwaitForIntersection1.ts, 38, 18))
118+
>stream : Symbol(stream, Decl(forAwaitForIntersection1.ts, 35, 21))
119+
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
//// [tests/cases/compiler/forAwaitForIntersection1.ts] ////
2+
3+
=== forAwaitForIntersection1.ts ===
4+
type Stream1<T_Sync, T_Async> = Iterable<T_Sync> & AsyncIterable<T_Async>;
5+
>Stream1 : Stream1<T_Sync, T_Async>
6+
> : ^^^^^^^^^^^^^^^^^^^^^^^^
7+
8+
class A1 {}
9+
>A1 : A1
10+
> : ^^
11+
12+
class B1 {}
13+
>B1 : B1
14+
> : ^^
15+
16+
async function loop1(stream: Stream1<A1, B1>) {
17+
>loop1 : (stream: Stream1<A1, B1>) => Promise<void>
18+
> : ^ ^^ ^^^^^^^^^^^^^^^^^^
19+
>stream : Stream1<A1, B1>
20+
> : ^^^^^^^^^^^^^^^
21+
22+
for await (const b of stream) {}
23+
>b : B1
24+
> : ^^
25+
>stream : Stream1<A1, B1>
26+
> : ^^^^^^^^^^^^^^^
27+
}
28+
29+
type Stream2<T_Sync, T_Async> = Iterable<T_Sync> & AsyncIterable<T_Async>;
30+
>Stream2 : Stream2<T_Sync, T_Async>
31+
> : ^^^^^^^^^^^^^^^^^^^^^^^^
32+
33+
class A2 {}
34+
>A2 : A2
35+
> : ^^
36+
37+
class B2 {}
38+
>B2 : B2
39+
> : ^^
40+
41+
async function loop2(stream: Stream2<A2, B2>) {
42+
>loop2 : (stream: Stream2<A2, B2>) => Promise<void>
43+
> : ^ ^^ ^^^^^^^^^^^^^^^^^^
44+
>stream : Stream2<A2, B2>
45+
> : ^^^^^^^^^^^^^^^
46+
47+
for (const a of stream) {}
48+
>a : A2
49+
> : ^^
50+
>stream : Stream2<A2, B2>
51+
> : ^^^^^^^^^^^^^^^
52+
}
53+
54+
type Stream3<T_Sync, T_Async> = Iterable<T_Sync> & AsyncIterable<T_Async>;
55+
>Stream3 : Stream3<T_Sync, T_Async>
56+
> : ^^^^^^^^^^^^^^^^^^^^^^^^
57+
58+
class A3 {}
59+
>A3 : A3
60+
> : ^^
61+
62+
class B3 {}
63+
>B3 : B3
64+
> : ^^
65+
66+
async function loop3(stream: Stream3<A3, B3>) {
67+
>loop3 : (stream: Stream3<A3, B3>) => Promise<void>
68+
> : ^ ^^ ^^^^^^^^^^^^^^^^^^
69+
>stream : Stream3<A3, B3>
70+
> : ^^^^^^^^^^^^^^^
71+
72+
for await (const b of stream) {}
73+
>b : B3
74+
> : ^^
75+
>stream : Stream3<A3, B3>
76+
> : ^^^^^^^^^^^^^^^
77+
78+
for (const a of stream) {}
79+
>a : A3
80+
> : ^^
81+
>stream : Stream3<A3, B3>
82+
> : ^^^^^^^^^^^^^^^
83+
}
84+
85+
type Stream4<T_Sync, T_Async> = Iterable<T_Sync> & AsyncIterable<T_Async>;
86+
>Stream4 : Stream4<T_Sync, T_Async>
87+
> : ^^^^^^^^^^^^^^^^^^^^^^^^
88+
89+
class A4 {}
90+
>A4 : A4
91+
> : ^^
92+
93+
class B4 {}
94+
>B4 : B4
95+
> : ^^
96+
97+
// verify that resolving sync iteration first doesn't spoil the type for async iteration
98+
async function loop4(stream: Stream4<A4, B4>) {
99+
>loop4 : (stream: Stream4<A4, B4>) => Promise<void>
100+
> : ^ ^^ ^^^^^^^^^^^^^^^^^^
101+
>stream : Stream4<A4, B4>
102+
> : ^^^^^^^^^^^^^^^
103+
104+
for (const a of stream) {}
105+
>a : A4
106+
> : ^^
107+
>stream : Stream4<A4, B4>
108+
> : ^^^^^^^^^^^^^^^
109+
110+
for await (const b of stream) {}
111+
>b : B4
112+
> : ^^
113+
>stream : Stream4<A4, B4>
114+
> : ^^^^^^^^^^^^^^^
115+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// @strict: true
2+
// @target: es2018
3+
// @lib: esnext
4+
// @noEmit: true
5+
6+
type Stream1<T_Sync, T_Async> = Iterable<T_Sync> & AsyncIterable<T_Async>;
7+
8+
class A1 {}
9+
class B1 {}
10+
11+
async function loop1(stream: Stream1<A1, B1>) {
12+
for await (const b of stream) {}
13+
}
14+
15+
type Stream2<T_Sync, T_Async> = Iterable<T_Sync> & AsyncIterable<T_Async>;
16+
17+
class A2 {}
18+
class B2 {}
19+
20+
async function loop2(stream: Stream2<A2, B2>) {
21+
for (const a of stream) {}
22+
}
23+
24+
type Stream3<T_Sync, T_Async> = Iterable<T_Sync> & AsyncIterable<T_Async>;
25+
26+
class A3 {}
27+
class B3 {}
28+
29+
async function loop3(stream: Stream3<A3, B3>) {
30+
for await (const b of stream) {}
31+
32+
for (const a of stream) {}
33+
}
34+
35+
type Stream4<T_Sync, T_Async> = Iterable<T_Sync> & AsyncIterable<T_Async>;
36+
37+
class A4 {}
38+
class B4 {}
39+
40+
// verify that resolving sync iteration first doesn't spoil the type for async iteration
41+
async function loop4(stream: Stream4<A4, B4>) {
42+
for (const a of stream) {}
43+
44+
for await (const b of stream) {}
45+
}

0 commit comments

Comments
 (0)