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

Revert structuredTypeRelatedTo change and fix isUnitLikeType #51076

Merged
merged 5 commits into from Oct 19, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 2 additions & 3 deletions src/compiler/checker.ts
Expand Up @@ -19663,7 +19663,7 @@ namespace ts {
// For example, if `T extends 1 | 2` and `U extends 2 | 3` and we compare `T & U` to `T & U & (1 | 2 | 3)`
if (!result && (source.flags & TypeFlags.Intersection || source.flags & TypeFlags.TypeParameter && target.flags & TypeFlags.Union)) {
const constraint = getEffectiveConstraintOfIntersection(source.flags & TypeFlags.Intersection ? (source as IntersectionType).types: [source], !!(target.flags & TypeFlags.Union));
if (constraint && !(constraint.flags & TypeFlags.Never) && everyType(constraint, c => c !== source)) { // Skip comparison if expansion contains the source itself
if (constraint && everyType(constraint, c => c !== source)) { // Skip comparison if expansion contains the source itself
// TODO: Stack errors so we get a pyramid for the "normal" comparison above, _and_ a second for this
result = isRelatedTo(constraint, target, RecursionFlags.Source, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState);
}
Expand Down Expand Up @@ -21630,8 +21630,7 @@ namespace ts {
}

function isUnitLikeType(type: Type): boolean {
return type.flags & TypeFlags.Intersection ? some((type as IntersectionType).types, isUnitType) :
!!(type.flags & TypeFlags.Unit);
return isUnitType(getBaseConstraintOrType(type));
}

function extractUnitType(type: Type) {
Expand Down
27 changes: 27 additions & 0 deletions tests/baselines/reference/unknownControlFlow.errors.txt
Expand Up @@ -417,4 +417,31 @@ tests/cases/conformance/types/unknown/unknownControlFlow.ts(293,5): error TS2345
value;
}
}

// Repro from #51009

type TypeA = {
A: 'A',
B: 'B',
}

type TypeB = {
A: 'A',
B: 'B',
C: 'C',
}

type R<T extends keyof TypeA> =
T extends keyof TypeB ? [TypeA[T], TypeB[T]] : never;

type R2<T extends PropertyKey> =
T extends keyof TypeA ? T extends keyof TypeB ? [TypeA[T], TypeB[T]] : never : never;

// Repro from #51041

type AB = "A" | "B";

function x<T_AB extends AB>(x: T_AB & undefined, y: any) {
let r2: never = y as T_AB & undefined;
}

43 changes: 43 additions & 0 deletions tests/baselines/reference/unknownControlFlow.js
Expand Up @@ -400,6 +400,33 @@ function doSomething2(value: unknown): void {
value;
}
}

// Repro from #51009

type TypeA = {
A: 'A',
B: 'B',
}

type TypeB = {
A: 'A',
B: 'B',
C: 'C',
}

type R<T extends keyof TypeA> =
T extends keyof TypeB ? [TypeA[T], TypeB[T]] : never;

type R2<T extends PropertyKey> =
T extends keyof TypeA ? T extends keyof TypeB ? [TypeA[T], TypeB[T]] : never : never;

// Repro from #51041

type AB = "A" | "B";

function x<T_AB extends AB>(x: T_AB & undefined, y: any) {
let r2: never = y as T_AB & undefined;
}


//// [unknownControlFlow.js]
Expand Down Expand Up @@ -742,6 +769,9 @@ function doSomething2(value) {
value;
}
}
function x(x, y) {
var r2 = y;
}


//// [unknownControlFlow.d.ts]
Expand Down Expand Up @@ -801,3 +831,16 @@ declare function fx10(x: string | number, y: number): void;
declare function SendBlob(encoding: unknown): void;
declare function doSomething1<T extends unknown>(value: T): T;
declare function doSomething2(value: unknown): void;
type TypeA = {
A: 'A';
B: 'B';
};
type TypeB = {
A: 'A';
B: 'B';
C: 'C';
};
type R<T extends keyof TypeA> = T extends keyof TypeB ? [TypeA[T], TypeB[T]] : never;
type R2<T extends PropertyKey> = T extends keyof TypeA ? T extends keyof TypeB ? [TypeA[T], TypeB[T]] : never : never;
type AB = "A" | "B";
declare function x<T_AB extends AB>(x: T_AB & undefined, y: any): void;
72 changes: 72 additions & 0 deletions tests/baselines/reference/unknownControlFlow.symbols
Expand Up @@ -923,3 +923,75 @@ function doSomething2(value: unknown): void {
}
}

// Repro from #51009

type TypeA = {
>TypeA : Symbol(TypeA, Decl(unknownControlFlow.ts, 400, 1))

A: 'A',
>A : Symbol(A, Decl(unknownControlFlow.ts, 404, 14))

B: 'B',
>B : Symbol(B, Decl(unknownControlFlow.ts, 405, 11))
}

type TypeB = {
>TypeB : Symbol(TypeB, Decl(unknownControlFlow.ts, 407, 1))

A: 'A',
>A : Symbol(A, Decl(unknownControlFlow.ts, 409, 14))

B: 'B',
>B : Symbol(B, Decl(unknownControlFlow.ts, 410, 11))

C: 'C',
>C : Symbol(C, Decl(unknownControlFlow.ts, 411, 11))
}

type R<T extends keyof TypeA> =
>R : Symbol(R, Decl(unknownControlFlow.ts, 413, 1))
>T : Symbol(T, Decl(unknownControlFlow.ts, 415, 7))
>TypeA : Symbol(TypeA, Decl(unknownControlFlow.ts, 400, 1))

T extends keyof TypeB ? [TypeA[T], TypeB[T]] : never;
>T : Symbol(T, Decl(unknownControlFlow.ts, 415, 7))
>TypeB : Symbol(TypeB, Decl(unknownControlFlow.ts, 407, 1))
>TypeA : Symbol(TypeA, Decl(unknownControlFlow.ts, 400, 1))
>T : Symbol(T, Decl(unknownControlFlow.ts, 415, 7))
>TypeB : Symbol(TypeB, Decl(unknownControlFlow.ts, 407, 1))
>T : Symbol(T, Decl(unknownControlFlow.ts, 415, 7))

type R2<T extends PropertyKey> =
>R2 : Symbol(R2, Decl(unknownControlFlow.ts, 416, 57))
>T : Symbol(T, Decl(unknownControlFlow.ts, 418, 8))
>PropertyKey : Symbol(PropertyKey, Decl(lib.es5.d.ts, --, --))

T extends keyof TypeA ? T extends keyof TypeB ? [TypeA[T], TypeB[T]] : never : never;
>T : Symbol(T, Decl(unknownControlFlow.ts, 418, 8))
>TypeA : Symbol(TypeA, Decl(unknownControlFlow.ts, 400, 1))
>T : Symbol(T, Decl(unknownControlFlow.ts, 418, 8))
>TypeB : Symbol(TypeB, Decl(unknownControlFlow.ts, 407, 1))
>TypeA : Symbol(TypeA, Decl(unknownControlFlow.ts, 400, 1))
>T : Symbol(T, Decl(unknownControlFlow.ts, 418, 8))
>TypeB : Symbol(TypeB, Decl(unknownControlFlow.ts, 407, 1))
>T : Symbol(T, Decl(unknownControlFlow.ts, 418, 8))

// Repro from #51041

type AB = "A" | "B";
>AB : Symbol(AB, Decl(unknownControlFlow.ts, 419, 89))

function x<T_AB extends AB>(x: T_AB & undefined, y: any) {
>x : Symbol(x, Decl(unknownControlFlow.ts, 423, 20))
>T_AB : Symbol(T_AB, Decl(unknownControlFlow.ts, 425, 11))
>AB : Symbol(AB, Decl(unknownControlFlow.ts, 419, 89))
>x : Symbol(x, Decl(unknownControlFlow.ts, 425, 28))
>T_AB : Symbol(T_AB, Decl(unknownControlFlow.ts, 425, 11))
>y : Symbol(y, Decl(unknownControlFlow.ts, 425, 48))

let r2: never = y as T_AB & undefined;
>r2 : Symbol(r2, Decl(unknownControlFlow.ts, 426, 7))
>y : Symbol(y, Decl(unknownControlFlow.ts, 425, 48))
>T_AB : Symbol(T_AB, Decl(unknownControlFlow.ts, 425, 11))
}

55 changes: 53 additions & 2 deletions tests/baselines/reference/unknownControlFlow.types
Expand Up @@ -853,7 +853,7 @@ function fx2<T extends {}>(value: T & ({} | null)) {
>42 : 42

value; // T & {}
>value : T & {}
>value : T & ({} | null)
}
else {
value; // T & ({} | null)
Expand All @@ -872,7 +872,7 @@ function fx3<T extends {} | undefined>(value: T & ({} | null)) {
>42 : 42

value; // T & {}
>value : T & {}
>value : T & ({} | null)
}
else {
value; // T & ({} | null)
Expand Down Expand Up @@ -1025,3 +1025,54 @@ function doSomething2(value: unknown): void {
}
}

// Repro from #51009

type TypeA = {
>TypeA : { A: 'A'; B: 'B'; }

A: 'A',
>A : "A"

B: 'B',
>B : "B"
}

type TypeB = {
>TypeB : { A: 'A'; B: 'B'; C: 'C'; }

A: 'A',
>A : "A"

B: 'B',
>B : "B"

C: 'C',
>C : "C"
}

type R<T extends keyof TypeA> =
>R : R<T>

T extends keyof TypeB ? [TypeA[T], TypeB[T]] : never;

type R2<T extends PropertyKey> =
>R2 : R2<T>

T extends keyof TypeA ? T extends keyof TypeB ? [TypeA[T], TypeB[T]] : never : never;

// Repro from #51041

type AB = "A" | "B";
>AB : "A" | "B"

function x<T_AB extends AB>(x: T_AB & undefined, y: any) {
>x : <T_AB extends AB>(x: T_AB & undefined, y: any) => void
>x : T_AB & undefined
>y : any

let r2: never = y as T_AB & undefined;
>r2 : never
>y as T_AB & undefined : T_AB & undefined
>y : any
}

27 changes: 27 additions & 0 deletions tests/cases/conformance/types/unknown/unknownControlFlow.ts
Expand Up @@ -402,3 +402,30 @@ function doSomething2(value: unknown): void {
value;
}
}

// Repro from #51009

type TypeA = {
A: 'A',
B: 'B',
}

type TypeB = {
A: 'A',
B: 'B',
C: 'C',
}

type R<T extends keyof TypeA> =
T extends keyof TypeB ? [TypeA[T], TypeB[T]] : never;

type R2<T extends PropertyKey> =
T extends keyof TypeA ? T extends keyof TypeB ? [TypeA[T], TypeB[T]] : never : never;

// Repro from #51041

type AB = "A" | "B";

function x<T_AB extends AB>(x: T_AB & undefined, y: any) {
Copy link
Member

Choose a reason for hiding this comment

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

I think the change itself probably makes sense - but why is this test in unknownControlFlow.ts? It doesn't seem related to control flow and it doesn't use unknown anywhere.

Copy link
Member Author

Choose a reason for hiding this comment

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

It was a regression caused by #50735, so I added it in the same location as the tests for that PR.

Copy link
Member Author

Choose a reason for hiding this comment

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

@DanielRosenwasser Otherwise good with this? I'd like to get it merged.

Copy link
Member

Choose a reason for hiding this comment

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

Seems like if you could move it, that would be ideal - other than that, the change looks reasonable to me.

let r2: never = y as T_AB & undefined;
}