Skip to content

Commit 96faf0a

Browse files
committed
Backport tsog PR 3301 for testing
1 parent 0844c43 commit 96faf0a

4 files changed

Lines changed: 160 additions & 3 deletions

File tree

src/compiler/checker.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25499,12 +25499,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2549925499

2550025500
function getSingleCommonSupertype(types: Type[]) {
2550125501
// First, find the leftmost type for which no type to the right is a strict supertype, and if that
25502-
// type is a strict supertype of all other candidates, return it. Otherwise, return the leftmost type
25503-
// for which no type to the right is a (regular) supertype.
25502+
// type is a strict supertype of all other candidates, return it. Otherwise, use asymmetric
25503+
// assignability as a tiebreaker (i.e. only switch candidates when the assignment is one-way).
2550425504
const candidate = reduceLeft(types, (s, t) => isTypeStrictSubtypeOf(s, t) ? t : s)!;
2550525505
return every(types, t => t === candidate || isTypeStrictSubtypeOf(t, candidate)) ?
2550625506
candidate :
25507-
reduceLeft(types, (s, t) => isTypeSubtypeOf(s, t) ? t : s)!;
25507+
reduceLeft(types, (s, t) => isTypeAssignableTo(s, t) && !isTypeAssignableTo(t, s) ? t : s)!;
2550825508
}
2550925509

2551025510
// Return the leftmost type for which no type to the right is a subtype.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//// [tests/cases/compiler/discriminatedUnionFlatMap.ts] ////
2+
3+
=== discriminatedUnionFlatMap.ts ===
4+
// https://github.com/microsoft/typescript-go/issues/1057
5+
6+
export type InputOp = { op: "add" } | { op: "remove"; value?: Array<unknown> };
7+
>InputOp : Symbol(InputOp, Decl(discriminatedUnionFlatMap.ts, 0, 0))
8+
>op : Symbol(op, Decl(discriminatedUnionFlatMap.ts, 2, 23))
9+
>op : Symbol(op, Decl(discriminatedUnionFlatMap.ts, 2, 39))
10+
>value : Symbol(value, Decl(discriminatedUnionFlatMap.ts, 2, 53))
11+
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 2 more)
12+
13+
export type OutputOp = { op: "add" | "remove" };
14+
>OutputOp : Symbol(OutputOp, Decl(discriminatedUnionFlatMap.ts, 2, 79))
15+
>op : Symbol(op, Decl(discriminatedUnionFlatMap.ts, 3, 24))
16+
17+
export function f(operations: InputOp[]): OutputOp[] {
18+
>f : Symbol(f, Decl(discriminatedUnionFlatMap.ts, 3, 48))
19+
>operations : Symbol(operations, Decl(discriminatedUnionFlatMap.ts, 5, 18))
20+
>InputOp : Symbol(InputOp, Decl(discriminatedUnionFlatMap.ts, 0, 0))
21+
>OutputOp : Symbol(OutputOp, Decl(discriminatedUnionFlatMap.ts, 2, 79))
22+
23+
return operations.flatMap((operation) => {
24+
>operations.flatMap : Symbol(Array.flatMap, Decl(lib.es2019.array.d.ts, --, --))
25+
>operations : Symbol(operations, Decl(discriminatedUnionFlatMap.ts, 5, 18))
26+
>flatMap : Symbol(Array.flatMap, Decl(lib.es2019.array.d.ts, --, --))
27+
>operation : Symbol(operation, Decl(discriminatedUnionFlatMap.ts, 6, 31))
28+
29+
if (operation.op === "remove" && operation.value) {
30+
>operation.op : Symbol(op, Decl(discriminatedUnionFlatMap.ts, 2, 23), Decl(discriminatedUnionFlatMap.ts, 2, 39))
31+
>operation : Symbol(operation, Decl(discriminatedUnionFlatMap.ts, 6, 31))
32+
>op : Symbol(op, Decl(discriminatedUnionFlatMap.ts, 2, 23), Decl(discriminatedUnionFlatMap.ts, 2, 39))
33+
>operation.value : Symbol(value, Decl(discriminatedUnionFlatMap.ts, 2, 53))
34+
>operation : Symbol(operation, Decl(discriminatedUnionFlatMap.ts, 6, 31))
35+
>value : Symbol(value, Decl(discriminatedUnionFlatMap.ts, 2, 53))
36+
37+
return [].map(() => ({ op: "remove" }));
38+
>[].map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --))
39+
>map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --))
40+
>op : Symbol(op, Decl(discriminatedUnionFlatMap.ts, 8, 34))
41+
42+
} else {
43+
return [operation];
44+
>operation : Symbol(operation, Decl(discriminatedUnionFlatMap.ts, 6, 31))
45+
}
46+
});
47+
}
48+
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
//// [tests/cases/compiler/discriminatedUnionFlatMap.ts] ////
2+
3+
=== discriminatedUnionFlatMap.ts ===
4+
// https://github.com/microsoft/typescript-go/issues/1057
5+
6+
export type InputOp = { op: "add" } | { op: "remove"; value?: Array<unknown> };
7+
>InputOp : InputOp
8+
> : ^^^^^^^
9+
>op : "add"
10+
> : ^^^^^
11+
>op : "remove"
12+
> : ^^^^^^^^
13+
>value : unknown[] | undefined
14+
> : ^^^^^^^^^^^^^^^^^^^^^
15+
16+
export type OutputOp = { op: "add" | "remove" };
17+
>OutputOp : OutputOp
18+
> : ^^^^^^^^
19+
>op : "add" | "remove"
20+
> : ^^^^^^^^^^^^^^^^
21+
22+
export function f(operations: InputOp[]): OutputOp[] {
23+
>f : (operations: InputOp[]) => OutputOp[]
24+
> : ^ ^^ ^^^^^
25+
>operations : InputOp[]
26+
> : ^^^^^^^^^
27+
28+
return operations.flatMap((operation) => {
29+
>operations.flatMap((operation) => { if (operation.op === "remove" && operation.value) { return [].map(() => ({ op: "remove" })); } else { return [operation]; } }) : InputOp[]
30+
> : ^^^^^^^^^
31+
>operations.flatMap : <U, This = undefined>(callback: (this: This, value: InputOp, index: number, array: InputOp[]) => U | readonly U[], thisArg?: This | undefined) => U[]
32+
> : ^ ^^ ^^^^^^^^^^^^^^ ^^^ ^^^^^^^^ ^^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^
33+
>operations : InputOp[]
34+
> : ^^^^^^^^^
35+
>flatMap : <U, This = undefined>(callback: (this: This, value: InputOp, index: number, array: InputOp[]) => U | readonly U[], thisArg?: This | undefined) => U[]
36+
> : ^ ^^ ^^^^^^^^^^^^^^ ^^^ ^^^^^^^^ ^^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^
37+
>(operation) => { if (operation.op === "remove" && operation.value) { return [].map(() => ({ op: "remove" })); } else { return [operation]; } } : (this: undefined, operation: InputOp) => InputOp[] | { op: "remove"; }[]
38+
> : ^ ^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
39+
>operation : InputOp
40+
> : ^^^^^^^
41+
42+
if (operation.op === "remove" && operation.value) {
43+
>operation.op === "remove" && operation.value : false | unknown[] | undefined
44+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
45+
>operation.op === "remove" : boolean
46+
> : ^^^^^^^
47+
>operation.op : "add" | "remove"
48+
> : ^^^^^^^^^^^^^^^^
49+
>operation : InputOp
50+
> : ^^^^^^^
51+
>op : "add" | "remove"
52+
> : ^^^^^^^^^^^^^^^^
53+
>"remove" : "remove"
54+
> : ^^^^^^^^
55+
>operation.value : unknown[] | undefined
56+
> : ^^^^^^^^^^^^^^^^^^^^^
57+
>operation : { op: "remove"; value?: Array<unknown>; }
58+
> : ^^^^^^ ^^^^^^^^^^ ^^^
59+
>value : unknown[] | undefined
60+
> : ^^^^^^^^^^^^^^^^^^^^^
61+
62+
return [].map(() => ({ op: "remove" }));
63+
>[].map(() => ({ op: "remove" })) : { op: "remove"; }[]
64+
> : ^^^^^^^^^^^^^^^^^^^
65+
>[].map : <U>(callbackfn: (value: never, index: number, array: never[]) => U, thisArg?: any) => U[]
66+
> : ^ ^^ ^^^ ^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^
67+
>[] : never[]
68+
> : ^^^^^^^
69+
>map : <U>(callbackfn: (value: never, index: number, array: never[]) => U, thisArg?: any) => U[]
70+
> : ^ ^^ ^^^ ^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^
71+
>() => ({ op: "remove" }) : () => { op: "remove"; }
72+
> : ^^^^^^^^^^^^^^^^^^^^^^^
73+
>({ op: "remove" }) : { op: "remove"; }
74+
> : ^^^^^^^^^^^^^^^^^
75+
>{ op: "remove" } : { op: "remove"; }
76+
> : ^^^^^^^^^^^^^^^^^
77+
>op : "remove"
78+
> : ^^^^^^^^
79+
>"remove" : "remove"
80+
> : ^^^^^^^^
81+
82+
} else {
83+
return [operation];
84+
>[operation] : InputOp[]
85+
> : ^^^^^^^^^
86+
>operation : InputOp
87+
> : ^^^^^^^
88+
}
89+
});
90+
}
91+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// @strict: true
2+
// @noEmit: true
3+
// @lib: es2019
4+
5+
// https://github.com/microsoft/typescript-go/issues/1057
6+
7+
export type InputOp = { op: "add" } | { op: "remove"; value?: Array<unknown> };
8+
export type OutputOp = { op: "add" | "remove" };
9+
10+
export function f(operations: InputOp[]): OutputOp[] {
11+
return operations.flatMap((operation) => {
12+
if (operation.op === "remove" && operation.value) {
13+
return [].map(() => ({ op: "remove" }));
14+
} else {
15+
return [operation];
16+
}
17+
});
18+
}

0 commit comments

Comments
 (0)