Skip to content

Commit 9851d6f

Browse files
authored
Merge pull request #27490 from Microsoft/indexedAccessConstraint
Limit unsound indexed access type relations
2 parents f53a27e + 69cd6c0 commit 9851d6f

14 files changed

+862
-775
lines changed

src/compiler/checker.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11897,8 +11897,9 @@ namespace ts {
1189711897
}
1189811898
}
1189911899
else if (target.flags & TypeFlags.IndexedAccess) {
11900-
// A type S is related to a type T[K] if S is related to C, where C is the base constraint of T[K]
11901-
if (relation !== identityRelation) {
11900+
// A type S is related to a type T[K], where T and K aren't both type variables, if S is related to C,
11901+
// where C is the base constraint of T[K]
11902+
if (relation !== identityRelation && !(isGenericObjectType((<IndexedAccessType>target).objectType) && isGenericIndexType((<IndexedAccessType>target).indexType))) {
1190211903
const constraint = getBaseConstraintOfType(target);
1190311904
if (constraint && constraint !== target) {
1190411905
if (result = isRelatedTo(source, constraint, reportErrors)) {

tests/baselines/reference/infiniteConstraints.errors.txt

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,10 @@
1-
error TS2321: Excessive stack depth comparing types 'Extract<T[Exclude<keyof T, number>], Record<"val", string>>["val"]' and 'Extract<T[Exclude<keyof T, Exclude<keyof T, number>>], Record<"val", string>>["val"]'.
2-
error TS2321: Excessive stack depth comparing types 'Extract<T[Exclude<keyof T, string>], Record<"val", string>>["val"]' and 'Extract<T[Exclude<keyof T, Exclude<keyof T, string>>], Record<"val", string>>["val"]'.
3-
error TS2321: Excessive stack depth comparing types 'Extract<T[Exclude<keyof T, symbol>], Record<"val", string>>["val"]' and 'Extract<T[Exclude<keyof T, Exclude<keyof T, symbol>>], Record<"val", string>>["val"]'.
41
tests/cases/compiler/infiniteConstraints.ts(4,37): error TS2536: Type '"val"' cannot be used to index type 'B[Exclude<keyof B, K>]'.
5-
tests/cases/compiler/infiniteConstraints.ts(27,37): error TS2322: Type 'Record<"val", "test">' is not assignable to type 'never'.
6-
tests/cases/compiler/infiniteConstraints.ts(27,58): error TS2322: Type 'Record<"val", "test2">' is not assignable to type 'never'.
7-
tests/cases/compiler/infiniteConstraints.ts(29,45): error TS2322: Type 'Record<"val", "test">' is not assignable to type 'never'.
82
tests/cases/compiler/infiniteConstraints.ts(31,43): error TS2322: Type 'Record<"val", "dup">' is not assignable to type 'never'.
93
tests/cases/compiler/infiniteConstraints.ts(31,63): error TS2322: Type 'Record<"val", "dup">' is not assignable to type 'never'.
104
tests/cases/compiler/infiniteConstraints.ts(36,71): error TS2536: Type '"foo"' cannot be used to index type 'T[keyof T]'.
115

126

13-
!!! error TS2321: Excessive stack depth comparing types 'Extract<T[Exclude<keyof T, number>], Record<"val", string>>["val"]' and 'Extract<T[Exclude<keyof T, Exclude<keyof T, number>>], Record<"val", string>>["val"]'.
14-
!!! error TS2321: Excessive stack depth comparing types 'Extract<T[Exclude<keyof T, string>], Record<"val", string>>["val"]' and 'Extract<T[Exclude<keyof T, Exclude<keyof T, string>>], Record<"val", string>>["val"]'.
15-
!!! error TS2321: Excessive stack depth comparing types 'Extract<T[Exclude<keyof T, symbol>], Record<"val", string>>["val"]' and 'Extract<T[Exclude<keyof T, Exclude<keyof T, symbol>>], Record<"val", string>>["val"]'.
16-
==== tests/cases/compiler/infiniteConstraints.ts (7 errors) ====
7+
==== tests/cases/compiler/infiniteConstraints.ts (4 errors) ====
178
// Both of the following types trigger the recursion limiter in getImmediateBaseConstraint
189

1910
type T1<B extends { [K in keyof B]: Extract<B[Exclude<keyof B, K>], { val: string }>["val"] }> = B;
@@ -43,17 +34,8 @@ tests/cases/compiler/infiniteConstraints.ts(36,71): error TS2536: Type '"foo"' c
4334
>(vals: T): void;
4435

4536
const noError = ensureNoDuplicates({main: value("test"), alternate: value("test2")});
46-
~~~~
47-
!!! error TS2322: Type 'Record<"val", "test">' is not assignable to type 'never'.
48-
!!! related TS6500 tests/cases/compiler/infiniteConstraints.ts:27:37: The expected type comes from property 'main' which is declared here on type '{ main: never; alternate: never; }'
49-
~~~~~~~~~
50-
!!! error TS2322: Type 'Record<"val", "test2">' is not assignable to type 'never'.
51-
!!! related TS6500 tests/cases/compiler/infiniteConstraints.ts:27:58: The expected type comes from property 'alternate' which is declared here on type '{ main: never; alternate: never; }'
5237

5338
const shouldBeNoError = ensureNoDuplicates({main: value("test")});
54-
~~~~
55-
!!! error TS2322: Type 'Record<"val", "test">' is not assignable to type 'never'.
56-
!!! related TS6500 tests/cases/compiler/infiniteConstraints.ts:29:45: The expected type comes from property 'main' which is declared here on type '{ main: never; }'
5739

5840
const shouldBeError = ensureNoDuplicates({main: value("dup"), alternate: value("dup")});
5941
~~~~

tests/baselines/reference/infiniteConstraints.types

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ declare function value<V extends string>(val: V): Value<V>;
3939
>val : V
4040

4141
declare function ensureNoDuplicates<
42-
>ensureNoDuplicates : <T extends { [K in keyof T]: never; }>(vals: T) => void
42+
>ensureNoDuplicates : <T extends { [K in keyof T]: Extract<T[K], Record<"val", string>>["val"] extends Extract<T[Exclude<keyof T, K>], Record<"val", string>>["val"] ? never : any; }>(vals: T) => void
4343

4444
T extends {
4545
[K in keyof T]: Extract<T[K], Value>["val"] extends Extract<T[Exclude<keyof T, K>], Value>["val"]
@@ -50,9 +50,9 @@ declare function ensureNoDuplicates<
5050
>vals : T
5151

5252
const noError = ensureNoDuplicates({main: value("test"), alternate: value("test2")});
53-
>noError : any
54-
>ensureNoDuplicates({main: value("test"), alternate: value("test2")}) : any
55-
>ensureNoDuplicates : <T extends { [K in keyof T]: never; }>(vals: T) => void
53+
>noError : void
54+
>ensureNoDuplicates({main: value("test"), alternate: value("test2")}) : void
55+
>ensureNoDuplicates : <T extends { [K in keyof T]: Extract<T[K], Record<"val", string>>["val"] extends Extract<T[Exclude<keyof T, K>], Record<"val", string>>["val"] ? never : any; }>(vals: T) => void
5656
>{main: value("test"), alternate: value("test2")} : { main: Record<"val", "test">; alternate: Record<"val", "test2">; }
5757
>main : Record<"val", "test">
5858
>value("test") : Record<"val", "test">
@@ -64,9 +64,9 @@ const noError = ensureNoDuplicates({main: value("test"), alternate: value("test2
6464
>"test2" : "test2"
6565

6666
const shouldBeNoError = ensureNoDuplicates({main: value("test")});
67-
>shouldBeNoError : any
68-
>ensureNoDuplicates({main: value("test")}) : any
69-
>ensureNoDuplicates : <T extends { [K in keyof T]: never; }>(vals: T) => void
67+
>shouldBeNoError : void
68+
>ensureNoDuplicates({main: value("test")}) : void
69+
>ensureNoDuplicates : <T extends { [K in keyof T]: Extract<T[K], Record<"val", string>>["val"] extends Extract<T[Exclude<keyof T, K>], Record<"val", string>>["val"] ? never : any; }>(vals: T) => void
7070
>{main: value("test")} : { main: Record<"val", "test">; }
7171
>main : Record<"val", "test">
7272
>value("test") : Record<"val", "test">
@@ -76,7 +76,7 @@ const shouldBeNoError = ensureNoDuplicates({main: value("test")});
7676
const shouldBeError = ensureNoDuplicates({main: value("dup"), alternate: value("dup")});
7777
>shouldBeError : any
7878
>ensureNoDuplicates({main: value("dup"), alternate: value("dup")}) : any
79-
>ensureNoDuplicates : <T extends { [K in keyof T]: never; }>(vals: T) => void
79+
>ensureNoDuplicates : <T extends { [K in keyof T]: Extract<T[K], Record<"val", string>>["val"] extends Extract<T[Exclude<keyof T, K>], Record<"val", string>>["val"] ? never : any; }>(vals: T) => void
8080
>{main: value("dup"), alternate: value("dup")} : { main: Record<"val", "dup">; alternate: Record<"val", "dup">; }
8181
>main : Record<"val", "dup">
8282
>value("dup") : Record<"val", "dup">

tests/baselines/reference/keyofAndIndexedAccess.js

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -300,23 +300,16 @@ type S2 = {
300300
b: string;
301301
};
302302

303-
function f90<T extends S2, K extends keyof S2>(x1: S2[keyof S2], x2: T[keyof S2], x3: S2[K], x4: T[K]) {
303+
function f90<T extends S2, K extends keyof S2>(x1: S2[keyof S2], x2: T[keyof S2], x3: S2[K]) {
304304
x1 = x2;
305305
x1 = x3;
306-
x1 = x4;
307306
x2 = x1;
308307
x2 = x3;
309-
x2 = x4;
310308
x3 = x1;
311309
x3 = x2;
312-
x3 = x4;
313-
x4 = x1;
314-
x4 = x2;
315-
x4 = x3;
316310
x1.length;
317311
x2.length;
318312
x3.length;
319-
x4.length;
320313
}
321314

322315
function f91<T, K extends keyof T>(x: T, y: T[keyof T], z: T[K]) {
@@ -886,23 +879,16 @@ var C1 = /** @class */ (function () {
886879
};
887880
return C1;
888881
}());
889-
function f90(x1, x2, x3, x4) {
882+
function f90(x1, x2, x3) {
890883
x1 = x2;
891884
x1 = x3;
892-
x1 = x4;
893885
x2 = x1;
894886
x2 = x3;
895-
x2 = x4;
896887
x3 = x1;
897888
x3 = x2;
898-
x3 = x4;
899-
x4 = x1;
900-
x4 = x2;
901-
x4 = x3;
902889
x1.length;
903890
x2.length;
904891
x3.length;
905-
x4.length;
906892
}
907893
function f91(x, y, z) {
908894
var a;
@@ -1240,7 +1226,7 @@ declare type S2 = {
12401226
a: string;
12411227
b: string;
12421228
};
1243-
declare function f90<T extends S2, K extends keyof S2>(x1: S2[keyof S2], x2: T[keyof S2], x3: S2[K], x4: T[K]): void;
1229+
declare function f90<T extends S2, K extends keyof S2>(x1: S2[keyof S2], x2: T[keyof S2], x3: S2[K]): void;
12441230
declare function f91<T, K extends keyof T>(x: T, y: T[keyof T], z: T[K]): void;
12451231
declare function f92<T, K extends keyof T>(x: T, y: T[keyof T], z: T[K]): void;
12461232
declare class Base {

0 commit comments

Comments
 (0)