Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Limit unsound indexed access type relations #27490

Merged
merged 4 commits into from
Oct 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11876,8 +11876,9 @@ namespace ts {
}
}
else if (target.flags & TypeFlags.IndexedAccess) {
// 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]
if (relation !== identityRelation) {
// 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,
// where C is the base constraint of T[K]
if (relation !== identityRelation && !(isGenericObjectType((<IndexedAccessType>target).objectType) && isGenericIndexType((<IndexedAccessType>target).indexType))) {
const constraint = getBaseConstraintOfType(target);
if (constraint && constraint !== target) {
if (result = isRelatedTo(source, constraint, reportErrors)) {
Expand Down
20 changes: 1 addition & 19 deletions tests/baselines/reference/infiniteConstraints.errors.txt
Original file line number Diff line number Diff line change
@@ -1,19 +1,10 @@
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"]'.
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"]'.
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"]'.
tests/cases/compiler/infiniteConstraints.ts(4,37): error TS2536: Type '"val"' cannot be used to index type 'B[Exclude<keyof B, K>]'.
tests/cases/compiler/infiniteConstraints.ts(27,37): error TS2322: Type 'Record<"val", "test">' is not assignable to type 'never'.
tests/cases/compiler/infiniteConstraints.ts(27,58): error TS2322: Type 'Record<"val", "test2">' is not assignable to type 'never'.
tests/cases/compiler/infiniteConstraints.ts(29,45): error TS2322: Type 'Record<"val", "test">' is not assignable to type 'never'.
tests/cases/compiler/infiniteConstraints.ts(31,43): error TS2322: Type 'Record<"val", "dup">' is not assignable to type 'never'.
tests/cases/compiler/infiniteConstraints.ts(31,63): error TS2322: Type 'Record<"val", "dup">' is not assignable to type 'never'.
tests/cases/compiler/infiniteConstraints.ts(36,71): error TS2536: Type '"foo"' cannot be used to index type 'T[keyof T]'.


!!! 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"]'.
!!! 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"]'.
!!! 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"]'.
==== tests/cases/compiler/infiniteConstraints.ts (7 errors) ====
==== tests/cases/compiler/infiniteConstraints.ts (4 errors) ====
// Both of the following types trigger the recursion limiter in getImmediateBaseConstraint

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

const noError = ensureNoDuplicates({main: value("test"), alternate: value("test2")});
~~~~
!!! error TS2322: Type 'Record<"val", "test">' is not assignable to type 'never'.
!!! 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; }'
~~~~~~~~~
!!! error TS2322: Type 'Record<"val", "test2">' is not assignable to type 'never'.
!!! 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; }'

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

const shouldBeError = ensureNoDuplicates({main: value("dup"), alternate: value("dup")});
~~~~
Expand Down
16 changes: 8 additions & 8 deletions tests/baselines/reference/infiniteConstraints.types
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ declare function value<V extends string>(val: V): Value<V>;
>val : V

declare function ensureNoDuplicates<
>ensureNoDuplicates : <T extends { [K in keyof T]: never; }>(vals: T) => void
>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

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

const noError = ensureNoDuplicates({main: value("test"), alternate: value("test2")});
>noError : any
>ensureNoDuplicates({main: value("test"), alternate: value("test2")}) : any
>ensureNoDuplicates : <T extends { [K in keyof T]: never; }>(vals: T) => void
>noError : void
>ensureNoDuplicates({main: value("test"), alternate: value("test2")}) : void
>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
>{main: value("test"), alternate: value("test2")} : { main: Record<"val", "test">; alternate: Record<"val", "test2">; }
>main : Record<"val", "test">
>value("test") : Record<"val", "test">
Expand All @@ -64,9 +64,9 @@ const noError = ensureNoDuplicates({main: value("test"), alternate: value("test2
>"test2" : "test2"

const shouldBeNoError = ensureNoDuplicates({main: value("test")});
>shouldBeNoError : any
>ensureNoDuplicates({main: value("test")}) : any
>ensureNoDuplicates : <T extends { [K in keyof T]: never; }>(vals: T) => void
>shouldBeNoError : void
>ensureNoDuplicates({main: value("test")}) : void
>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
>{main: value("test")} : { main: Record<"val", "test">; }
>main : Record<"val", "test">
>value("test") : Record<"val", "test">
Expand All @@ -76,7 +76,7 @@ const shouldBeNoError = ensureNoDuplicates({main: value("test")});
const shouldBeError = ensureNoDuplicates({main: value("dup"), alternate: value("dup")});
>shouldBeError : any
>ensureNoDuplicates({main: value("dup"), alternate: value("dup")}) : any
>ensureNoDuplicates : <T extends { [K in keyof T]: never; }>(vals: T) => void
>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
>{main: value("dup"), alternate: value("dup")} : { main: Record<"val", "dup">; alternate: Record<"val", "dup">; }
>main : Record<"val", "dup">
>value("dup") : Record<"val", "dup">
Expand Down
20 changes: 3 additions & 17 deletions tests/baselines/reference/keyofAndIndexedAccess.js
Original file line number Diff line number Diff line change
Expand Up @@ -300,23 +300,16 @@ type S2 = {
b: string;
};

function f90<T extends S2, K extends keyof S2>(x1: S2[keyof S2], x2: T[keyof S2], x3: S2[K], x4: T[K]) {
function f90<T extends S2, K extends keyof S2>(x1: S2[keyof S2], x2: T[keyof S2], x3: S2[K]) {
x1 = x2;
x1 = x3;
x1 = x4;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth keeping all these variants (maybe in a different file or function) just to document that they're expected to fail now (and so we know if they suddenly start succeeding again).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They're basically covered by the new tests in keyofAndIndexedAccessErrors.ts, so I think it is fine to get rid of them.

x2 = x1;
x2 = x3;
x2 = x4;
x3 = x1;
x3 = x2;
x3 = x4;
x4 = x1;
x4 = x2;
x4 = x3;
x1.length;
x2.length;
x3.length;
x4.length;
}

function f91<T, K extends keyof T>(x: T, y: T[keyof T], z: T[K]) {
Expand Down Expand Up @@ -886,23 +879,16 @@ var C1 = /** @class */ (function () {
};
return C1;
}());
function f90(x1, x2, x3, x4) {
function f90(x1, x2, x3) {
x1 = x2;
x1 = x3;
x1 = x4;
x2 = x1;
x2 = x3;
x2 = x4;
x3 = x1;
x3 = x2;
x3 = x4;
x4 = x1;
x4 = x2;
x4 = x3;
x1.length;
x2.length;
x3.length;
x4.length;
}
function f91(x, y, z) {
var a;
Expand Down Expand Up @@ -1240,7 +1226,7 @@ declare type S2 = {
a: string;
b: string;
};
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;
declare function f90<T extends S2, K extends keyof S2>(x1: S2[keyof S2], x2: T[keyof S2], x3: S2[K]): void;
declare function f91<T, K extends keyof T>(x: T, y: T[keyof T], z: T[K]): void;
declare function f92<T, K extends keyof T>(x: T, y: T[keyof T], z: T[K]): void;
declare class Base {
Expand Down
Loading