Skip to content

Commit a79610a

Browse files
authored
Merge pull request microsoft#19912 from Microsoft/fixEmptyArrayInference
Fix empty array inference
2 parents 06dd3f2 + c3b650f commit a79610a

File tree

8 files changed

+144
-39
lines changed

8 files changed

+144
-39
lines changed

src/compiler/checker.ts

+10-7
Original file line numberDiff line numberDiff line change
@@ -10898,22 +10898,25 @@ namespace ts {
1089810898
// it as an inference candidate. Hopefully, a better candidate will come along that does
1089910899
// not contain anyFunctionType when we come back to this argument for its second round
1090010900
// of inference. Also, we exclude inferences for silentNeverType (which is used as a wildcard
10901-
// when constructing types from type parameters that had no inference candidates) and
10902-
// implicitNeverType (which is used as the element type for empty array literals).
10903-
if (source.flags & TypeFlags.ContainsAnyFunctionType || source === silentNeverType || source === implicitNeverType) {
10901+
// when constructing types from type parameters that had no inference candidates).
10902+
if (source.flags & TypeFlags.ContainsAnyFunctionType || source === silentNeverType) {
1090410903
return;
1090510904
}
1090610905
const inference = getInferenceInfoForType(target);
1090710906
if (inference) {
1090810907
if (!inference.isFixed) {
10909-
if (!inference.candidates || priority < inference.priority) {
10908+
// We give lowest priority to inferences of implicitNeverType (which is used as the
10909+
// element type for empty array literals). Thus, inferences from empty array literals
10910+
// only matter when no other inferences are made.
10911+
const p = priority | (source === implicitNeverType ? InferencePriority.NeverType : 0);
10912+
if (!inference.candidates || p < inference.priority) {
1091010913
inference.candidates = [source];
10911-
inference.priority = priority;
10914+
inference.priority = p;
1091210915
}
10913-
else if (priority === inference.priority) {
10916+
else if (p === inference.priority) {
1091410917
inference.candidates.push(source);
1091510918
}
10916-
if (!(priority & InferencePriority.ReturnType) && target.flags & TypeFlags.TypeParameter && !isTypeParameterAtTopLevel(originalTarget, <TypeParameter>target)) {
10919+
if (!(p & InferencePriority.ReturnType) && target.flags & TypeFlags.TypeParameter && !isTypeParameterAtTopLevel(originalTarget, <TypeParameter>target)) {
1091710920
inference.topLevel = false;
1091810921
}
1091910922
}

src/compiler/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -3613,6 +3613,7 @@ namespace ts {
36133613
NakedTypeVariable = 1 << 1, // Naked type variable in union or intersection type
36143614
MappedType = 1 << 2, // Reverse inference for mapped type
36153615
ReturnType = 1 << 3, // Inference made from return type of generic function
3616+
NeverType = 1 << 4, // Inference made from the never type
36163617
}
36173618

36183619
export interface InferenceInfo {

tests/baselines/reference/api/tsserverlibrary.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -2142,6 +2142,7 @@ declare namespace ts {
21422142
NakedTypeVariable = 2,
21432143
MappedType = 4,
21442144
ReturnType = 8,
2145+
NeverType = 16,
21452146
}
21462147
interface InferenceInfo {
21472148
typeParameter: TypeParameter;

tests/baselines/reference/api/typescript.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -2142,6 +2142,7 @@ declare namespace ts {
21422142
NakedTypeVariable = 2,
21432143
MappedType = 4,
21442144
ReturnType = 8,
2145+
NeverType = 16,
21452146
}
21462147
interface InferenceInfo {
21472148
typeParameter: TypeParameter;

tests/baselines/reference/neverInference.js

+15-7
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
//// [neverInference.ts]
2-
declare function f<T>(x: T[]): T;
2+
declare function f1<T>(x: T[]): T;
33

44
let neverArray: never[] = [];
55

6-
let a1 = f([]); // {}
7-
let a2 = f(neverArray); // never
6+
let a1 = f1([]); // never
7+
let a2 = f1(neverArray); // never
88

99
// Repro from #19576
1010

@@ -21,11 +21,19 @@ declare function compareNumbers(x: number, y: number): number;
2121
declare function mkList<T>(items: T[], comparator: Comparator<T>): LinkedList<T>;
2222

2323
const list: LinkedList<number> = mkList([], compareNumbers);
24+
25+
// Repro from #19858
26+
27+
declare function f2<a>(as1: a[], as2: a[], cmp: (a1: a, a2: a) => number): void;
28+
f2(Array.from([0]), [], (a1, a2) => a1 - a2);
29+
f2(Array.from([]), [0], (a1, a2) => a1 - a2);
2430

2531

2632
//// [neverInference.js]
2733
"use strict";
28-
var neverArray = [];
29-
var a1 = f([]); // {}
30-
var a2 = f(neverArray); // never
31-
var list = mkList([], compareNumbers);
34+
let neverArray = [];
35+
let a1 = f1([]); // never
36+
let a2 = f1(neverArray); // never
37+
const list = mkList([], compareNumbers);
38+
f2(Array.from([0]), [], (a1, a2) => a1 - a2);
39+
f2(Array.from([]), [0], (a1, a2) => a1 - a2);

tests/baselines/reference/neverInference.symbols

+48-13
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
11
=== tests/cases/conformance/types/never/neverInference.ts ===
2-
declare function f<T>(x: T[]): T;
3-
>f : Symbol(f, Decl(neverInference.ts, 0, 0))
4-
>T : Symbol(T, Decl(neverInference.ts, 0, 19))
5-
>x : Symbol(x, Decl(neverInference.ts, 0, 22))
6-
>T : Symbol(T, Decl(neverInference.ts, 0, 19))
7-
>T : Symbol(T, Decl(neverInference.ts, 0, 19))
2+
declare function f1<T>(x: T[]): T;
3+
>f1 : Symbol(f1, Decl(neverInference.ts, 0, 0))
4+
>T : Symbol(T, Decl(neverInference.ts, 0, 20))
5+
>x : Symbol(x, Decl(neverInference.ts, 0, 23))
6+
>T : Symbol(T, Decl(neverInference.ts, 0, 20))
7+
>T : Symbol(T, Decl(neverInference.ts, 0, 20))
88

99
let neverArray: never[] = [];
1010
>neverArray : Symbol(neverArray, Decl(neverInference.ts, 2, 3))
1111

12-
let a1 = f([]); // {}
12+
let a1 = f1([]); // never
1313
>a1 : Symbol(a1, Decl(neverInference.ts, 4, 3))
14-
>f : Symbol(f, Decl(neverInference.ts, 0, 0))
14+
>f1 : Symbol(f1, Decl(neverInference.ts, 0, 0))
1515

16-
let a2 = f(neverArray); // never
16+
let a2 = f1(neverArray); // never
1717
>a2 : Symbol(a2, Decl(neverInference.ts, 5, 3))
18-
>f : Symbol(f, Decl(neverInference.ts, 0, 0))
18+
>f1 : Symbol(f1, Decl(neverInference.ts, 0, 0))
1919
>neverArray : Symbol(neverArray, Decl(neverInference.ts, 2, 3))
2020

2121
// Repro from #19576
2222

2323
type Comparator<T> = (x: T, y: T) => number;
24-
>Comparator : Symbol(Comparator, Decl(neverInference.ts, 5, 23))
24+
>Comparator : Symbol(Comparator, Decl(neverInference.ts, 5, 24))
2525
>T : Symbol(T, Decl(neverInference.ts, 9, 16))
2626
>x : Symbol(x, Decl(neverInference.ts, 9, 22))
2727
>T : Symbol(T, Decl(neverInference.ts, 9, 16))
@@ -34,7 +34,7 @@ interface LinkedList<T> {
3434

3535
comparator: Comparator<T>,
3636
>comparator : Symbol(LinkedList.comparator, Decl(neverInference.ts, 11, 25))
37-
>Comparator : Symbol(Comparator, Decl(neverInference.ts, 5, 23))
37+
>Comparator : Symbol(Comparator, Decl(neverInference.ts, 5, 24))
3838
>T : Symbol(T, Decl(neverInference.ts, 11, 21))
3939

4040
nodes: Node<T>
@@ -63,7 +63,7 @@ declare function mkList<T>(items: T[], comparator: Comparator<T>): LinkedList<T>
6363
>items : Symbol(items, Decl(neverInference.ts, 19, 27))
6464
>T : Symbol(T, Decl(neverInference.ts, 19, 24))
6565
>comparator : Symbol(comparator, Decl(neverInference.ts, 19, 38))
66-
>Comparator : Symbol(Comparator, Decl(neverInference.ts, 5, 23))
66+
>Comparator : Symbol(Comparator, Decl(neverInference.ts, 5, 24))
6767
>T : Symbol(T, Decl(neverInference.ts, 19, 24))
6868
>LinkedList : Symbol(LinkedList, Decl(neverInference.ts, 9, 44))
6969
>T : Symbol(T, Decl(neverInference.ts, 19, 24))
@@ -74,3 +74,38 @@ const list: LinkedList<number> = mkList([], compareNumbers);
7474
>mkList : Symbol(mkList, Decl(neverInference.ts, 18, 62))
7575
>compareNumbers : Symbol(compareNumbers, Decl(neverInference.ts, 16, 49))
7676

77+
// Repro from #19858
78+
79+
declare function f2<a>(as1: a[], as2: a[], cmp: (a1: a, a2: a) => number): void;
80+
>f2 : Symbol(f2, Decl(neverInference.ts, 21, 60))
81+
>a : Symbol(a, Decl(neverInference.ts, 25, 20))
82+
>as1 : Symbol(as1, Decl(neverInference.ts, 25, 23))
83+
>a : Symbol(a, Decl(neverInference.ts, 25, 20))
84+
>as2 : Symbol(as2, Decl(neverInference.ts, 25, 32))
85+
>a : Symbol(a, Decl(neverInference.ts, 25, 20))
86+
>cmp : Symbol(cmp, Decl(neverInference.ts, 25, 42))
87+
>a1 : Symbol(a1, Decl(neverInference.ts, 25, 49))
88+
>a : Symbol(a, Decl(neverInference.ts, 25, 20))
89+
>a2 : Symbol(a2, Decl(neverInference.ts, 25, 55))
90+
>a : Symbol(a, Decl(neverInference.ts, 25, 20))
91+
92+
f2(Array.from([0]), [], (a1, a2) => a1 - a2);
93+
>f2 : Symbol(f2, Decl(neverInference.ts, 21, 60))
94+
>Array.from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --))
95+
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --))
96+
>from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --))
97+
>a1 : Symbol(a1, Decl(neverInference.ts, 26, 25))
98+
>a2 : Symbol(a2, Decl(neverInference.ts, 26, 28))
99+
>a1 : Symbol(a1, Decl(neverInference.ts, 26, 25))
100+
>a2 : Symbol(a2, Decl(neverInference.ts, 26, 28))
101+
102+
f2(Array.from([]), [0], (a1, a2) => a1 - a2);
103+
>f2 : Symbol(f2, Decl(neverInference.ts, 21, 60))
104+
>Array.from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --))
105+
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --))
106+
>from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --))
107+
>a1 : Symbol(a1, Decl(neverInference.ts, 27, 25))
108+
>a2 : Symbol(a2, Decl(neverInference.ts, 27, 28))
109+
>a1 : Symbol(a1, Decl(neverInference.ts, 27, 25))
110+
>a2 : Symbol(a2, Decl(neverInference.ts, 27, 28))
111+

tests/baselines/reference/neverInference.types

+58-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
=== tests/cases/conformance/types/never/neverInference.ts ===
2-
declare function f<T>(x: T[]): T;
3-
>f : <T>(x: T[]) => T
2+
declare function f1<T>(x: T[]): T;
3+
>f1 : <T>(x: T[]) => T
44
>T : T
55
>x : T[]
66
>T : T
@@ -10,16 +10,16 @@ let neverArray: never[] = [];
1010
>neverArray : never[]
1111
>[] : never[]
1212

13-
let a1 = f([]); // {}
14-
>a1 : {}
15-
>f([]) : {}
16-
>f : <T>(x: T[]) => T
13+
let a1 = f1([]); // never
14+
>a1 : never
15+
>f1([]) : never
16+
>f1 : <T>(x: T[]) => T
1717
>[] : never[]
1818

19-
let a2 = f(neverArray); // never
19+
let a2 = f1(neverArray); // never
2020
>a2 : never
21-
>f(neverArray) : never
22-
>f : <T>(x: T[]) => T
21+
>f1(neverArray) : never
22+
>f1 : <T>(x: T[]) => T
2323
>neverArray : never[]
2424

2525
// Repro from #19576
@@ -81,3 +81,52 @@ const list: LinkedList<number> = mkList([], compareNumbers);
8181
>[] : never[]
8282
>compareNumbers : (x: number, y: number) => number
8383

84+
// Repro from #19858
85+
86+
declare function f2<a>(as1: a[], as2: a[], cmp: (a1: a, a2: a) => number): void;
87+
>f2 : <a>(as1: a[], as2: a[], cmp: (a1: a, a2: a) => number) => void
88+
>a : a
89+
>as1 : a[]
90+
>a : a
91+
>as2 : a[]
92+
>a : a
93+
>cmp : (a1: a, a2: a) => number
94+
>a1 : a
95+
>a : a
96+
>a2 : a
97+
>a : a
98+
99+
f2(Array.from([0]), [], (a1, a2) => a1 - a2);
100+
>f2(Array.from([0]), [], (a1, a2) => a1 - a2) : void
101+
>f2 : <a>(as1: a[], as2: a[], cmp: (a1: a, a2: a) => number) => void
102+
>Array.from([0]) : number[]
103+
>Array.from : { <T>(iterable: Iterable<T>): T[]; <T, U>(iterable: Iterable<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
104+
>Array : ArrayConstructor
105+
>from : { <T>(iterable: Iterable<T>): T[]; <T, U>(iterable: Iterable<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
106+
>[0] : number[]
107+
>0 : 0
108+
>[] : never[]
109+
>(a1, a2) => a1 - a2 : (a1: number, a2: number) => number
110+
>a1 : number
111+
>a2 : number
112+
>a1 - a2 : number
113+
>a1 : number
114+
>a2 : number
115+
116+
f2(Array.from([]), [0], (a1, a2) => a1 - a2);
117+
>f2(Array.from([]), [0], (a1, a2) => a1 - a2) : void
118+
>f2 : <a>(as1: a[], as2: a[], cmp: (a1: a, a2: a) => number) => void
119+
>Array.from([]) : never[]
120+
>Array.from : { <T>(iterable: Iterable<T>): T[]; <T, U>(iterable: Iterable<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
121+
>Array : ArrayConstructor
122+
>from : { <T>(iterable: Iterable<T>): T[]; <T, U>(iterable: Iterable<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
123+
>[] : never[]
124+
>[0] : number[]
125+
>0 : 0
126+
>(a1, a2) => a1 - a2 : (a1: number, a2: number) => number
127+
>a1 : number
128+
>a2 : number
129+
>a1 - a2 : number
130+
>a1 : number
131+
>a2 : number
132+

tests/cases/conformance/types/never/neverInference.ts

+10-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
// @strict: true
2+
// @target: es2015
23

3-
declare function f<T>(x: T[]): T;
4+
declare function f1<T>(x: T[]): T;
45

56
let neverArray: never[] = [];
67

7-
let a1 = f([]); // {}
8-
let a2 = f(neverArray); // never
8+
let a1 = f1([]); // never
9+
let a2 = f1(neverArray); // never
910

1011
// Repro from #19576
1112

@@ -22,3 +23,9 @@ declare function compareNumbers(x: number, y: number): number;
2223
declare function mkList<T>(items: T[], comparator: Comparator<T>): LinkedList<T>;
2324

2425
const list: LinkedList<number> = mkList([], compareNumbers);
26+
27+
// Repro from #19858
28+
29+
declare function f2<a>(as1: a[], as2: a[], cmp: (a1: a, a2: a) => number): void;
30+
f2(Array.from([0]), [], (a1, a2) => a1 - a2);
31+
f2(Array.from([]), [0], (a1, a2) => a1 - a2);

0 commit comments

Comments
 (0)