Skip to content

Commit b5f4a83

Browse files
authored
Merge pull request #19745 from Microsoft/emptyArrayInference
No inference from empty array literals
2 parents 7a4808a + 0a4f60e commit b5f4a83

File tree

5 files changed

+223
-7
lines changed

5 files changed

+223
-7
lines changed

src/compiler/checker.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ namespace ts {
283283
const voidType = createIntrinsicType(TypeFlags.Void, "void");
284284
const neverType = createIntrinsicType(TypeFlags.Never, "never");
285285
const silentNeverType = createIntrinsicType(TypeFlags.Never, "never");
286+
const implicitNeverType = createIntrinsicType(TypeFlags.Never, "never");
286287
const nonPrimitiveType = createIntrinsicType(TypeFlags.NonPrimitive, "object");
287288

288289
const emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
@@ -7691,7 +7692,7 @@ namespace ts {
76917692

76927693
function getIndexTypeOrString(type: Type): Type {
76937694
const indexType = getIndexType(type);
7694-
return indexType !== neverType ? indexType : stringType;
7695+
return indexType.flags & TypeFlags.Never ? stringType : indexType;
76957696
}
76967697

76977698
function getTypeFromTypeOperatorNode(node: TypeOperatorNode) {
@@ -8880,8 +8881,8 @@ namespace ts {
88808881
function isSimpleTypeRelatedTo(source: Type, target: Type, relation: Map<RelationComparisonResult>, errorReporter?: ErrorReporter) {
88818882
const s = source.flags;
88828883
const t = target.flags;
8883-
if (t & TypeFlags.Never) return false;
88848884
if (t & TypeFlags.Any || s & TypeFlags.Never) return true;
8885+
if (t & TypeFlags.Never) return false;
88858886
if (s & TypeFlags.StringLike && t & TypeFlags.String) return true;
88868887
if (s & TypeFlags.StringLiteral && s & TypeFlags.EnumLiteral &&
88878888
t & TypeFlags.StringLiteral && !(t & TypeFlags.EnumLiteral) &&
@@ -10348,7 +10349,7 @@ namespace ts {
1034810349

1034910350
function isEmptyArrayLiteralType(type: Type): boolean {
1035010351
const elementType = isArrayType(type) ? (<TypeReference>type).typeArguments[0] : undefined;
10351-
return elementType === undefinedWideningType || elementType === neverType;
10352+
return elementType === undefinedWideningType || elementType === implicitNeverType;
1035210353
}
1035310354

1035410355
function isTupleLikeType(type: Type): boolean {
@@ -10905,9 +10906,10 @@ namespace ts {
1090510906
// Because the anyFunctionType is internal, it should not be exposed to the user by adding
1090610907
// it as an inference candidate. Hopefully, a better candidate will come along that does
1090710908
// not contain anyFunctionType when we come back to this argument for its second round
10908-
// of inference. Also, we exclude inferences for silentNeverType which is used as a wildcard
10909-
// when constructing types from type parameters that had no inference candidates.
10910-
if (source.flags & TypeFlags.ContainsAnyFunctionType || source === silentNeverType) {
10909+
// of inference. Also, we exclude inferences for silentNeverType (which is used as a wildcard
10910+
// when constructing types from type parameters that had no inference candidates) and
10911+
// implicitNeverType (which is used as the element type for empty array literals).
10912+
if (source.flags & TypeFlags.ContainsAnyFunctionType || source === silentNeverType || source === implicitNeverType) {
1091110913
return;
1091210914
}
1091310915
const inference = getInferenceInfoForType(target);
@@ -13948,7 +13950,7 @@ namespace ts {
1394813950
}
1394913951
return createArrayType(elementTypes.length ?
1395013952
getUnionType(elementTypes, /*subtypeReduction*/ true) :
13951-
strictNullChecks ? neverType : undefinedWideningType);
13953+
strictNullChecks ? implicitNeverType : undefinedWideningType);
1395213954
}
1395313955

1395413956
function isNumericName(name: DeclarationName): boolean {
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//// [neverInference.ts]
2+
declare function f<T>(x: T[]): T;
3+
4+
let neverArray: never[] = [];
5+
6+
let a1 = f([]); // {}
7+
let a2 = f(neverArray); // never
8+
9+
// Repro from #19576
10+
11+
type Comparator<T> = (x: T, y: T) => number;
12+
13+
interface LinkedList<T> {
14+
comparator: Comparator<T>,
15+
nodes: Node<T>
16+
}
17+
18+
type Node<T> = { value: T, next: Node<T> } | null
19+
20+
declare function compareNumbers(x: number, y: number): number;
21+
declare function mkList<T>(items: T[], comparator: Comparator<T>): LinkedList<T>;
22+
23+
const list: LinkedList<number> = mkList([], compareNumbers);
24+
25+
26+
//// [neverInference.js]
27+
"use strict";
28+
var neverArray = [];
29+
var a1 = f([]); // {}
30+
var a2 = f(neverArray); // never
31+
var list = mkList([], compareNumbers);
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
=== 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))
8+
9+
let neverArray: never[] = [];
10+
>neverArray : Symbol(neverArray, Decl(neverInference.ts, 2, 3))
11+
12+
let a1 = f([]); // {}
13+
>a1 : Symbol(a1, Decl(neverInference.ts, 4, 3))
14+
>f : Symbol(f, Decl(neverInference.ts, 0, 0))
15+
16+
let a2 = f(neverArray); // never
17+
>a2 : Symbol(a2, Decl(neverInference.ts, 5, 3))
18+
>f : Symbol(f, Decl(neverInference.ts, 0, 0))
19+
>neverArray : Symbol(neverArray, Decl(neverInference.ts, 2, 3))
20+
21+
// Repro from #19576
22+
23+
type Comparator<T> = (x: T, y: T) => number;
24+
>Comparator : Symbol(Comparator, Decl(neverInference.ts, 5, 23))
25+
>T : Symbol(T, Decl(neverInference.ts, 9, 16))
26+
>x : Symbol(x, Decl(neverInference.ts, 9, 22))
27+
>T : Symbol(T, Decl(neverInference.ts, 9, 16))
28+
>y : Symbol(y, Decl(neverInference.ts, 9, 27))
29+
>T : Symbol(T, Decl(neverInference.ts, 9, 16))
30+
31+
interface LinkedList<T> {
32+
>LinkedList : Symbol(LinkedList, Decl(neverInference.ts, 9, 44))
33+
>T : Symbol(T, Decl(neverInference.ts, 11, 21))
34+
35+
comparator: Comparator<T>,
36+
>comparator : Symbol(LinkedList.comparator, Decl(neverInference.ts, 11, 25))
37+
>Comparator : Symbol(Comparator, Decl(neverInference.ts, 5, 23))
38+
>T : Symbol(T, Decl(neverInference.ts, 11, 21))
39+
40+
nodes: Node<T>
41+
>nodes : Symbol(LinkedList.nodes, Decl(neverInference.ts, 12, 30))
42+
>Node : Symbol(Node, Decl(neverInference.ts, 14, 1))
43+
>T : Symbol(T, Decl(neverInference.ts, 11, 21))
44+
}
45+
46+
type Node<T> = { value: T, next: Node<T> } | null
47+
>Node : Symbol(Node, Decl(neverInference.ts, 14, 1))
48+
>T : Symbol(T, Decl(neverInference.ts, 16, 10))
49+
>value : Symbol(value, Decl(neverInference.ts, 16, 16))
50+
>T : Symbol(T, Decl(neverInference.ts, 16, 10))
51+
>next : Symbol(next, Decl(neverInference.ts, 16, 26))
52+
>Node : Symbol(Node, Decl(neverInference.ts, 14, 1))
53+
>T : Symbol(T, Decl(neverInference.ts, 16, 10))
54+
55+
declare function compareNumbers(x: number, y: number): number;
56+
>compareNumbers : Symbol(compareNumbers, Decl(neverInference.ts, 16, 49))
57+
>x : Symbol(x, Decl(neverInference.ts, 18, 32))
58+
>y : Symbol(y, Decl(neverInference.ts, 18, 42))
59+
60+
declare function mkList<T>(items: T[], comparator: Comparator<T>): LinkedList<T>;
61+
>mkList : Symbol(mkList, Decl(neverInference.ts, 18, 62))
62+
>T : Symbol(T, Decl(neverInference.ts, 19, 24))
63+
>items : Symbol(items, Decl(neverInference.ts, 19, 27))
64+
>T : Symbol(T, Decl(neverInference.ts, 19, 24))
65+
>comparator : Symbol(comparator, Decl(neverInference.ts, 19, 38))
66+
>Comparator : Symbol(Comparator, Decl(neverInference.ts, 5, 23))
67+
>T : Symbol(T, Decl(neverInference.ts, 19, 24))
68+
>LinkedList : Symbol(LinkedList, Decl(neverInference.ts, 9, 44))
69+
>T : Symbol(T, Decl(neverInference.ts, 19, 24))
70+
71+
const list: LinkedList<number> = mkList([], compareNumbers);
72+
>list : Symbol(list, Decl(neverInference.ts, 21, 5))
73+
>LinkedList : Symbol(LinkedList, Decl(neverInference.ts, 9, 44))
74+
>mkList : Symbol(mkList, Decl(neverInference.ts, 18, 62))
75+
>compareNumbers : Symbol(compareNumbers, Decl(neverInference.ts, 16, 49))
76+
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
=== tests/cases/conformance/types/never/neverInference.ts ===
2+
declare function f<T>(x: T[]): T;
3+
>f : <T>(x: T[]) => T
4+
>T : T
5+
>x : T[]
6+
>T : T
7+
>T : T
8+
9+
let neverArray: never[] = [];
10+
>neverArray : never[]
11+
>[] : never[]
12+
13+
let a1 = f([]); // {}
14+
>a1 : {}
15+
>f([]) : {}
16+
>f : <T>(x: T[]) => T
17+
>[] : never[]
18+
19+
let a2 = f(neverArray); // never
20+
>a2 : never
21+
>f(neverArray) : never
22+
>f : <T>(x: T[]) => T
23+
>neverArray : never[]
24+
25+
// Repro from #19576
26+
27+
type Comparator<T> = (x: T, y: T) => number;
28+
>Comparator : Comparator<T>
29+
>T : T
30+
>x : T
31+
>T : T
32+
>y : T
33+
>T : T
34+
35+
interface LinkedList<T> {
36+
>LinkedList : LinkedList<T>
37+
>T : T
38+
39+
comparator: Comparator<T>,
40+
>comparator : Comparator<T>
41+
>Comparator : Comparator<T>
42+
>T : T
43+
44+
nodes: Node<T>
45+
>nodes : Node<T>
46+
>Node : Node<T>
47+
>T : T
48+
}
49+
50+
type Node<T> = { value: T, next: Node<T> } | null
51+
>Node : Node<T>
52+
>T : T
53+
>value : T
54+
>T : T
55+
>next : Node<T>
56+
>Node : Node<T>
57+
>T : T
58+
>null : null
59+
60+
declare function compareNumbers(x: number, y: number): number;
61+
>compareNumbers : (x: number, y: number) => number
62+
>x : number
63+
>y : number
64+
65+
declare function mkList<T>(items: T[], comparator: Comparator<T>): LinkedList<T>;
66+
>mkList : <T>(items: T[], comparator: Comparator<T>) => LinkedList<T>
67+
>T : T
68+
>items : T[]
69+
>T : T
70+
>comparator : Comparator<T>
71+
>Comparator : Comparator<T>
72+
>T : T
73+
>LinkedList : LinkedList<T>
74+
>T : T
75+
76+
const list: LinkedList<number> = mkList([], compareNumbers);
77+
>list : LinkedList<number>
78+
>LinkedList : LinkedList<T>
79+
>mkList([], compareNumbers) : LinkedList<number>
80+
>mkList : <T>(items: T[], comparator: Comparator<T>) => LinkedList<T>
81+
>[] : never[]
82+
>compareNumbers : (x: number, y: number) => number
83+
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// @strict: true
2+
3+
declare function f<T>(x: T[]): T;
4+
5+
let neverArray: never[] = [];
6+
7+
let a1 = f([]); // {}
8+
let a2 = f(neverArray); // never
9+
10+
// Repro from #19576
11+
12+
type Comparator<T> = (x: T, y: T) => number;
13+
14+
interface LinkedList<T> {
15+
comparator: Comparator<T>,
16+
nodes: Node<T>
17+
}
18+
19+
type Node<T> = { value: T, next: Node<T> } | null
20+
21+
declare function compareNumbers(x: number, y: number): number;
22+
declare function mkList<T>(items: T[], comparator: Comparator<T>): LinkedList<T>;
23+
24+
const list: LinkedList<number> = mkList([], compareNumbers);

0 commit comments

Comments
 (0)