Skip to content

Commit 612c92d

Browse files
Track source and target relationship stack depth seperately, only increase on change in value (#41821)
* Track source and target relationship stack depth seperately, only increase on change in value * Add baselines for test from #43485 * Bail on unwrapping conditional constraints on the source side when the source conditional is already known to be spooling out of control * More usage of isDeeplyNestedType to block _specifically_ conditional recursion on only one side * Negative cases of getNarrowedType that match the exact type should be filtered out, even when generic * Add test and fix for #44404 * Swap to manually specifying left and right recursion * Rename Left -> Source, Right -> Target Co-authored-by: Andrew Branch <andrew@wheream.io>
1 parent 96f259d commit 612c92d

25 files changed

+1368
-133
lines changed

src/compiler/checker.ts

+148-121
Large diffs are not rendered by default.

tests/baselines/reference/circularlyConstrainedMappedTypeContainingConditionalNoInfiniteInstantiationDepth.errors.txt

+196
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
tests/cases/compiler/conditionalTypeVarianceBigArrayConstraintsPerformance.ts(9,5): error TS2322: Type 'Stuff<U>' is not assignable to type 'Stuff<T>'.
2+
Type 'U' is not assignable to type 'T'.
3+
'T' could be instantiated with an arbitrary type which could be unrelated to 'U'.
4+
5+
6+
==== tests/cases/compiler/conditionalTypeVarianceBigArrayConstraintsPerformance.ts (1 errors) ====
7+
/// <reference path="/.lib/react16.d.ts" />
8+
9+
type Stuff<T> =
10+
T extends keyof JSX.IntrinsicElements
11+
? JSX.IntrinsicElements[T]
12+
: any;
13+
14+
function F<T, U>(p1: Stuff<T>, p2: Stuff<U>) {
15+
p1 = p2; // Error
16+
~~
17+
!!! error TS2322: Type 'Stuff<U>' is not assignable to type 'Stuff<T>'.
18+
!!! error TS2322: Type 'U' is not assignable to type 'T'.
19+
!!! error TS2322: 'T' could be instantiated with an arbitrary type which could be unrelated to 'U'.
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//// [conditionalTypeVarianceBigArrayConstraintsPerformance.ts]
2+
/// <reference path="/.lib/react16.d.ts" />
3+
4+
type Stuff<T> =
5+
T extends keyof JSX.IntrinsicElements
6+
? JSX.IntrinsicElements[T]
7+
: any;
8+
9+
function F<T, U>(p1: Stuff<T>, p2: Stuff<U>) {
10+
p1 = p2; // Error
11+
}
12+
13+
//// [conditionalTypeVarianceBigArrayConstraintsPerformance.js]
14+
/// <reference path="react16.d.ts" />
15+
function F(p1, p2) {
16+
p1 = p2; // Error
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
=== tests/cases/compiler/conditionalTypeVarianceBigArrayConstraintsPerformance.ts ===
2+
/// <reference path="react16.d.ts" />
3+
4+
type Stuff<T> =
5+
>Stuff : Symbol(Stuff, Decl(conditionalTypeVarianceBigArrayConstraintsPerformance.ts, 0, 0))
6+
>T : Symbol(T, Decl(conditionalTypeVarianceBigArrayConstraintsPerformance.ts, 2, 11))
7+
8+
T extends keyof JSX.IntrinsicElements
9+
>T : Symbol(T, Decl(conditionalTypeVarianceBigArrayConstraintsPerformance.ts, 2, 11))
10+
>JSX : Symbol(JSX, Decl(react16.d.ts, 2493, 12))
11+
>IntrinsicElements : Symbol(JSX.IntrinsicElements, Decl(react16.d.ts, 2514, 86))
12+
13+
? JSX.IntrinsicElements[T]
14+
>JSX : Symbol(JSX, Decl(react16.d.ts, 2493, 12))
15+
>IntrinsicElements : Symbol(JSX.IntrinsicElements, Decl(react16.d.ts, 2514, 86))
16+
>T : Symbol(T, Decl(conditionalTypeVarianceBigArrayConstraintsPerformance.ts, 2, 11))
17+
18+
: any;
19+
20+
function F<T, U>(p1: Stuff<T>, p2: Stuff<U>) {
21+
>F : Symbol(F, Decl(conditionalTypeVarianceBigArrayConstraintsPerformance.ts, 5, 14))
22+
>T : Symbol(T, Decl(conditionalTypeVarianceBigArrayConstraintsPerformance.ts, 7, 11))
23+
>U : Symbol(U, Decl(conditionalTypeVarianceBigArrayConstraintsPerformance.ts, 7, 13))
24+
>p1 : Symbol(p1, Decl(conditionalTypeVarianceBigArrayConstraintsPerformance.ts, 7, 17))
25+
>Stuff : Symbol(Stuff, Decl(conditionalTypeVarianceBigArrayConstraintsPerformance.ts, 0, 0))
26+
>T : Symbol(T, Decl(conditionalTypeVarianceBigArrayConstraintsPerformance.ts, 7, 11))
27+
>p2 : Symbol(p2, Decl(conditionalTypeVarianceBigArrayConstraintsPerformance.ts, 7, 30))
28+
>Stuff : Symbol(Stuff, Decl(conditionalTypeVarianceBigArrayConstraintsPerformance.ts, 0, 0))
29+
>U : Symbol(U, Decl(conditionalTypeVarianceBigArrayConstraintsPerformance.ts, 7, 13))
30+
31+
p1 = p2; // Error
32+
>p1 : Symbol(p1, Decl(conditionalTypeVarianceBigArrayConstraintsPerformance.ts, 7, 17))
33+
>p2 : Symbol(p2, Decl(conditionalTypeVarianceBigArrayConstraintsPerformance.ts, 7, 30))
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
=== tests/cases/compiler/conditionalTypeVarianceBigArrayConstraintsPerformance.ts ===
2+
/// <reference path="react16.d.ts" />
3+
4+
type Stuff<T> =
5+
>Stuff : Stuff<T>
6+
7+
T extends keyof JSX.IntrinsicElements
8+
>JSX : any
9+
10+
? JSX.IntrinsicElements[T]
11+
>JSX : any
12+
13+
: any;
14+
15+
function F<T, U>(p1: Stuff<T>, p2: Stuff<U>) {
16+
>F : <T, U>(p1: Stuff<T>, p2: Stuff<U>) => void
17+
>p1 : Stuff<T>
18+
>p2 : Stuff<U>
19+
20+
p1 = p2; // Error
21+
>p1 = p2 : Stuff<U>
22+
>p1 : Stuff<T>
23+
>p2 : Stuff<U>
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
tests/cases/compiler/deepComparisons.ts(2,9): error TS2322: Type 'T' is not assignable to type 'Extract<T, string>'.
2+
tests/cases/compiler/deepComparisons.ts(3,9): error TS2322: Type 'T[K1]' is not assignable to type 'Extract<T[K1], string>'.
3+
Type 'T[keyof T]' is not assignable to type 'Extract<T[K1], string>'.
4+
Type 'T[string] | T[number] | T[symbol]' is not assignable to type 'Extract<T[K1], string>'.
5+
Type 'T[string]' is not assignable to type 'Extract<T[K1], string>'.
6+
tests/cases/compiler/deepComparisons.ts(4,9): error TS2322: Type 'T[K1][K2]' is not assignable to type 'Extract<T[K1][K2], string>'.
7+
Type 'T[K1][keyof T[K1]]' is not assignable to type 'Extract<T[K1][K2], string>'.
8+
Type 'T[K1][string] | T[K1][number] | T[K1][symbol]' is not assignable to type 'Extract<T[K1][K2], string>'.
9+
Type 'T[K1][string]' is not assignable to type 'Extract<T[K1][K2], string>'.
10+
Type 'T[keyof T][string]' is not assignable to type 'Extract<T[K1][K2], string>'.
11+
Type 'T[string][string] | T[number][string] | T[symbol][string]' is not assignable to type 'Extract<T[K1][K2], string>'.
12+
Type 'T[string][string]' is not assignable to type 'Extract<T[K1][K2], string>'.
13+
14+
15+
==== tests/cases/compiler/deepComparisons.ts (3 errors) ====
16+
function f1<T, K1 extends keyof T, K2 extends keyof T[K1]>() {
17+
let v1: Extract<T, string> = 0 as any as T; // Error
18+
~~
19+
!!! error TS2322: Type 'T' is not assignable to type 'Extract<T, string>'.
20+
let v2: Extract<T[K1], string> = 0 as any as T[K1]; // Error
21+
~~
22+
!!! error TS2322: Type 'T[K1]' is not assignable to type 'Extract<T[K1], string>'.
23+
!!! error TS2322: Type 'T[keyof T]' is not assignable to type 'Extract<T[K1], string>'.
24+
!!! error TS2322: Type 'T[string] | T[number] | T[symbol]' is not assignable to type 'Extract<T[K1], string>'.
25+
!!! error TS2322: Type 'T[string]' is not assignable to type 'Extract<T[K1], string>'.
26+
let v3: Extract<T[K1][K2], string> = 0 as any as T[K1][K2]; // No error
27+
~~
28+
!!! error TS2322: Type 'T[K1][K2]' is not assignable to type 'Extract<T[K1][K2], string>'.
29+
!!! error TS2322: Type 'T[K1][keyof T[K1]]' is not assignable to type 'Extract<T[K1][K2], string>'.
30+
!!! error TS2322: Type 'T[K1][string] | T[K1][number] | T[K1][symbol]' is not assignable to type 'Extract<T[K1][K2], string>'.
31+
!!! error TS2322: Type 'T[K1][string]' is not assignable to type 'Extract<T[K1][K2], string>'.
32+
!!! error TS2322: Type 'T[keyof T][string]' is not assignable to type 'Extract<T[K1][K2], string>'.
33+
!!! error TS2322: Type 'T[string][string] | T[number][string] | T[symbol][string]' is not assignable to type 'Extract<T[K1][K2], string>'.
34+
!!! error TS2322: Type 'T[string][string]' is not assignable to type 'Extract<T[K1][K2], string>'.
35+
}
36+
37+
type Foo<T> = { x: Foo<T> };
38+
type Bar<T> = { x: Bar<T[]> };
39+
40+
function f2<U>() {
41+
let x: Foo<U> = 0 as any as Bar<U>; // Error, excessive stack depth
42+
}
43+
44+
type Foo1<T> = { x: Foo2<T> };
45+
type Foo2<T> = { x: Foo1<T> };
46+
47+
function f3<U>() {
48+
let x: Foo1<U> = 0 as any as Bar<U>; // No error!
49+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//// [deepComparisons.ts]
2+
function f1<T, K1 extends keyof T, K2 extends keyof T[K1]>() {
3+
let v1: Extract<T, string> = 0 as any as T; // Error
4+
let v2: Extract<T[K1], string> = 0 as any as T[K1]; // Error
5+
let v3: Extract<T[K1][K2], string> = 0 as any as T[K1][K2]; // No error
6+
}
7+
8+
type Foo<T> = { x: Foo<T> };
9+
type Bar<T> = { x: Bar<T[]> };
10+
11+
function f2<U>() {
12+
let x: Foo<U> = 0 as any as Bar<U>; // Error, excessive stack depth
13+
}
14+
15+
type Foo1<T> = { x: Foo2<T> };
16+
type Foo2<T> = { x: Foo1<T> };
17+
18+
function f3<U>() {
19+
let x: Foo1<U> = 0 as any as Bar<U>; // No error!
20+
}
21+
22+
//// [deepComparisons.js]
23+
function f1() {
24+
var v1 = 0; // Error
25+
var v2 = 0; // Error
26+
var v3 = 0; // No error
27+
}
28+
function f2() {
29+
var x = 0; // Error, excessive stack depth
30+
}
31+
function f3() {
32+
var x = 0; // No error!
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
=== tests/cases/compiler/deepComparisons.ts ===
2+
function f1<T, K1 extends keyof T, K2 extends keyof T[K1]>() {
3+
>f1 : Symbol(f1, Decl(deepComparisons.ts, 0, 0))
4+
>T : Symbol(T, Decl(deepComparisons.ts, 0, 12))
5+
>K1 : Symbol(K1, Decl(deepComparisons.ts, 0, 14))
6+
>T : Symbol(T, Decl(deepComparisons.ts, 0, 12))
7+
>K2 : Symbol(K2, Decl(deepComparisons.ts, 0, 34))
8+
>T : Symbol(T, Decl(deepComparisons.ts, 0, 12))
9+
>K1 : Symbol(K1, Decl(deepComparisons.ts, 0, 14))
10+
11+
let v1: Extract<T, string> = 0 as any as T; // Error
12+
>v1 : Symbol(v1, Decl(deepComparisons.ts, 1, 7))
13+
>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --))
14+
>T : Symbol(T, Decl(deepComparisons.ts, 0, 12))
15+
>T : Symbol(T, Decl(deepComparisons.ts, 0, 12))
16+
17+
let v2: Extract<T[K1], string> = 0 as any as T[K1]; // Error
18+
>v2 : Symbol(v2, Decl(deepComparisons.ts, 2, 7))
19+
>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --))
20+
>T : Symbol(T, Decl(deepComparisons.ts, 0, 12))
21+
>K1 : Symbol(K1, Decl(deepComparisons.ts, 0, 14))
22+
>T : Symbol(T, Decl(deepComparisons.ts, 0, 12))
23+
>K1 : Symbol(K1, Decl(deepComparisons.ts, 0, 14))
24+
25+
let v3: Extract<T[K1][K2], string> = 0 as any as T[K1][K2]; // No error
26+
>v3 : Symbol(v3, Decl(deepComparisons.ts, 3, 7))
27+
>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --))
28+
>T : Symbol(T, Decl(deepComparisons.ts, 0, 12))
29+
>K1 : Symbol(K1, Decl(deepComparisons.ts, 0, 14))
30+
>K2 : Symbol(K2, Decl(deepComparisons.ts, 0, 34))
31+
>T : Symbol(T, Decl(deepComparisons.ts, 0, 12))
32+
>K1 : Symbol(K1, Decl(deepComparisons.ts, 0, 14))
33+
>K2 : Symbol(K2, Decl(deepComparisons.ts, 0, 34))
34+
}
35+
36+
type Foo<T> = { x: Foo<T> };
37+
>Foo : Symbol(Foo, Decl(deepComparisons.ts, 4, 1))
38+
>T : Symbol(T, Decl(deepComparisons.ts, 6, 9))
39+
>x : Symbol(x, Decl(deepComparisons.ts, 6, 15))
40+
>Foo : Symbol(Foo, Decl(deepComparisons.ts, 4, 1))
41+
>T : Symbol(T, Decl(deepComparisons.ts, 6, 9))
42+
43+
type Bar<T> = { x: Bar<T[]> };
44+
>Bar : Symbol(Bar, Decl(deepComparisons.ts, 6, 28))
45+
>T : Symbol(T, Decl(deepComparisons.ts, 7, 9))
46+
>x : Symbol(x, Decl(deepComparisons.ts, 7, 15))
47+
>Bar : Symbol(Bar, Decl(deepComparisons.ts, 6, 28))
48+
>T : Symbol(T, Decl(deepComparisons.ts, 7, 9))
49+
50+
function f2<U>() {
51+
>f2 : Symbol(f2, Decl(deepComparisons.ts, 7, 30))
52+
>U : Symbol(U, Decl(deepComparisons.ts, 9, 12))
53+
54+
let x: Foo<U> = 0 as any as Bar<U>; // Error, excessive stack depth
55+
>x : Symbol(x, Decl(deepComparisons.ts, 10, 7))
56+
>Foo : Symbol(Foo, Decl(deepComparisons.ts, 4, 1))
57+
>U : Symbol(U, Decl(deepComparisons.ts, 9, 12))
58+
>Bar : Symbol(Bar, Decl(deepComparisons.ts, 6, 28))
59+
>U : Symbol(U, Decl(deepComparisons.ts, 9, 12))
60+
}
61+
62+
type Foo1<T> = { x: Foo2<T> };
63+
>Foo1 : Symbol(Foo1, Decl(deepComparisons.ts, 11, 1))
64+
>T : Symbol(T, Decl(deepComparisons.ts, 13, 10))
65+
>x : Symbol(x, Decl(deepComparisons.ts, 13, 16))
66+
>Foo2 : Symbol(Foo2, Decl(deepComparisons.ts, 13, 30))
67+
>T : Symbol(T, Decl(deepComparisons.ts, 13, 10))
68+
69+
type Foo2<T> = { x: Foo1<T> };
70+
>Foo2 : Symbol(Foo2, Decl(deepComparisons.ts, 13, 30))
71+
>T : Symbol(T, Decl(deepComparisons.ts, 14, 10))
72+
>x : Symbol(x, Decl(deepComparisons.ts, 14, 16))
73+
>Foo1 : Symbol(Foo1, Decl(deepComparisons.ts, 11, 1))
74+
>T : Symbol(T, Decl(deepComparisons.ts, 14, 10))
75+
76+
function f3<U>() {
77+
>f3 : Symbol(f3, Decl(deepComparisons.ts, 14, 30))
78+
>U : Symbol(U, Decl(deepComparisons.ts, 16, 12))
79+
80+
let x: Foo1<U> = 0 as any as Bar<U>; // No error!
81+
>x : Symbol(x, Decl(deepComparisons.ts, 17, 7))
82+
>Foo1 : Symbol(Foo1, Decl(deepComparisons.ts, 11, 1))
83+
>U : Symbol(U, Decl(deepComparisons.ts, 16, 12))
84+
>Bar : Symbol(Bar, Decl(deepComparisons.ts, 6, 28))
85+
>U : Symbol(U, Decl(deepComparisons.ts, 16, 12))
86+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
=== tests/cases/compiler/deepComparisons.ts ===
2+
function f1<T, K1 extends keyof T, K2 extends keyof T[K1]>() {
3+
>f1 : <T, K1 extends keyof T, K2 extends keyof T[K1]>() => void
4+
5+
let v1: Extract<T, string> = 0 as any as T; // Error
6+
>v1 : Extract<T, string>
7+
>0 as any as T : T
8+
>0 as any : any
9+
>0 : 0
10+
11+
let v2: Extract<T[K1], string> = 0 as any as T[K1]; // Error
12+
>v2 : Extract<T[K1], string>
13+
>0 as any as T[K1] : T[K1]
14+
>0 as any : any
15+
>0 : 0
16+
17+
let v3: Extract<T[K1][K2], string> = 0 as any as T[K1][K2]; // No error
18+
>v3 : Extract<T[K1][K2], string>
19+
>0 as any as T[K1][K2] : T[K1][K2]
20+
>0 as any : any
21+
>0 : 0
22+
}
23+
24+
type Foo<T> = { x: Foo<T> };
25+
>Foo : Foo<T>
26+
>x : Foo<T>
27+
28+
type Bar<T> = { x: Bar<T[]> };
29+
>Bar : Bar<T>
30+
>x : Bar<T[]>
31+
32+
function f2<U>() {
33+
>f2 : <U>() => void
34+
35+
let x: Foo<U> = 0 as any as Bar<U>; // Error, excessive stack depth
36+
>x : Foo<U>
37+
>0 as any as Bar<U> : Bar<U>
38+
>0 as any : any
39+
>0 : 0
40+
}
41+
42+
type Foo1<T> = { x: Foo2<T> };
43+
>Foo1 : Foo1<T>
44+
>x : Foo2<T>
45+
46+
type Foo2<T> = { x: Foo1<T> };
47+
>Foo2 : Foo2<T>
48+
>x : Foo1<T>
49+
50+
function f3<U>() {
51+
>f3 : <U>() => void
52+
53+
let x: Foo1<U> = 0 as any as Bar<U>; // No error!
54+
>x : Foo1<U>
55+
>0 as any as Bar<U> : Bar<U>
56+
>0 as any : any
57+
>0 : 0
58+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//// [genericCapturingFunctionNarrowing.ts]
2+
function needsToNarrowTheType<First extends { foo: string }, Second extends { bar: string }, SubFirst extends First, SubFirstMore extends First & {other: string}>(thing: First | SubFirst | SubFirstMore | Second) {
3+
if (hasAFoo(thing)) {
4+
console.log(thing.foo);
5+
}
6+
else {
7+
// I would expect this to work because the type should be narrowed in this branch to `Second`
8+
console.log(thing.bar); // Error: Property 'bar' does not exist on type 'First | Second'.
9+
}
10+
11+
function hasAFoo(value: First | Second): value is First {
12+
return "foo" in value;
13+
}
14+
}
15+
16+
//// [genericCapturingFunctionNarrowing.js]
17+
function needsToNarrowTheType(thing) {
18+
if (hasAFoo(thing)) {
19+
console.log(thing.foo);
20+
}
21+
else {
22+
// I would expect this to work because the type should be narrowed in this branch to `Second`
23+
console.log(thing.bar); // Error: Property 'bar' does not exist on type 'First | Second'.
24+
}
25+
function hasAFoo(value) {
26+
return "foo" in value;
27+
}
28+
}

0 commit comments

Comments
 (0)