From a8160de49c9b74fe536705a1edd35618c1e855e6 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 4 Nov 2017 17:26:02 -0700 Subject: [PATCH 1/2] Empty array literal has a non-inferrable element type --- src/compiler/checker.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e2e45b2ccb0f6..5b5bc92350bbc 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -281,6 +281,7 @@ namespace ts { const voidType = createIntrinsicType(TypeFlags.Void, "void"); const neverType = createIntrinsicType(TypeFlags.Never, "never"); const silentNeverType = createIntrinsicType(TypeFlags.Never, "never"); + const implicitNeverType = createIntrinsicType(TypeFlags.Never, "never"); const nonPrimitiveType = createIntrinsicType(TypeFlags.NonPrimitive, "object"); const emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); @@ -7684,7 +7685,7 @@ namespace ts { function getIndexTypeOrString(type: Type): Type { const indexType = getIndexType(type); - return indexType !== neverType ? indexType : stringType; + return indexType.flags & TypeFlags.Never ? stringType : indexType; } function getTypeFromTypeOperatorNode(node: TypeOperatorNode) { @@ -8861,8 +8862,8 @@ namespace ts { function isSimpleTypeRelatedTo(source: Type, target: Type, relation: Map, errorReporter?: ErrorReporter) { const s = source.flags; const t = target.flags; - if (t & TypeFlags.Never) return false; if (t & TypeFlags.Any || s & TypeFlags.Never) return true; + if (t & TypeFlags.Never) return false; if (s & TypeFlags.StringLike && t & TypeFlags.String) return true; if (s & TypeFlags.StringLiteral && s & TypeFlags.EnumLiteral && t & TypeFlags.StringLiteral && !(t & TypeFlags.EnumLiteral) && @@ -10323,7 +10324,7 @@ namespace ts { function isEmptyArrayLiteralType(type: Type): boolean { const elementType = isArrayType(type) ? (type).typeArguments[0] : undefined; - return elementType === undefinedWideningType || elementType === neverType; + return elementType === undefinedWideningType || elementType === implicitNeverType; } function isTupleLikeType(type: Type): boolean { @@ -10880,9 +10881,10 @@ namespace ts { // Because the anyFunctionType is internal, it should not be exposed to the user by adding // it as an inference candidate. Hopefully, a better candidate will come along that does // not contain anyFunctionType when we come back to this argument for its second round - // of inference. Also, we exclude inferences for silentNeverType which is used as a wildcard - // when constructing types from type parameters that had no inference candidates. - if (source.flags & TypeFlags.ContainsAnyFunctionType || source === silentNeverType) { + // of inference. Also, we exclude inferences for silentNeverType (which is used as a wildcard + // when constructing types from type parameters that had no inference candidates) and + // implicitNeverType (which is used as the element type for empty array literals). + if (source.flags & TypeFlags.ContainsAnyFunctionType || source === silentNeverType || source === implicitNeverType) { return; } const inference = getInferenceInfoForType(target); @@ -13923,7 +13925,7 @@ namespace ts { } return createArrayType(elementTypes.length ? getUnionType(elementTypes, /*subtypeReduction*/ true) : - strictNullChecks ? neverType : undefinedWideningType); + strictNullChecks ? implicitNeverType : undefinedWideningType); } function isNumericName(name: DeclarationName): boolean { From 0a4f60e87b030dfe58a067c671177dad40c89944 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 4 Nov 2017 17:26:12 -0700 Subject: [PATCH 2/2] Add tests --- tests/baselines/reference/neverInference.js | 31 +++++++ .../reference/neverInference.symbols | 76 +++++++++++++++++ .../baselines/reference/neverInference.types | 83 +++++++++++++++++++ .../conformance/types/never/neverInference.ts | 24 ++++++ 4 files changed, 214 insertions(+) create mode 100644 tests/baselines/reference/neverInference.js create mode 100644 tests/baselines/reference/neverInference.symbols create mode 100644 tests/baselines/reference/neverInference.types create mode 100644 tests/cases/conformance/types/never/neverInference.ts diff --git a/tests/baselines/reference/neverInference.js b/tests/baselines/reference/neverInference.js new file mode 100644 index 0000000000000..d13e537eba496 --- /dev/null +++ b/tests/baselines/reference/neverInference.js @@ -0,0 +1,31 @@ +//// [neverInference.ts] +declare function f(x: T[]): T; + +let neverArray: never[] = []; + +let a1 = f([]); // {} +let a2 = f(neverArray); // never + +// Repro from #19576 + +type Comparator = (x: T, y: T) => number; + +interface LinkedList { + comparator: Comparator, + nodes: Node +} + +type Node = { value: T, next: Node } | null + +declare function compareNumbers(x: number, y: number): number; +declare function mkList(items: T[], comparator: Comparator): LinkedList; + +const list: LinkedList = mkList([], compareNumbers); + + +//// [neverInference.js] +"use strict"; +var neverArray = []; +var a1 = f([]); // {} +var a2 = f(neverArray); // never +var list = mkList([], compareNumbers); diff --git a/tests/baselines/reference/neverInference.symbols b/tests/baselines/reference/neverInference.symbols new file mode 100644 index 0000000000000..683e079b2f840 --- /dev/null +++ b/tests/baselines/reference/neverInference.symbols @@ -0,0 +1,76 @@ +=== tests/cases/conformance/types/never/neverInference.ts === +declare function f(x: T[]): T; +>f : Symbol(f, Decl(neverInference.ts, 0, 0)) +>T : Symbol(T, Decl(neverInference.ts, 0, 19)) +>x : Symbol(x, Decl(neverInference.ts, 0, 22)) +>T : Symbol(T, Decl(neverInference.ts, 0, 19)) +>T : Symbol(T, Decl(neverInference.ts, 0, 19)) + +let neverArray: never[] = []; +>neverArray : Symbol(neverArray, Decl(neverInference.ts, 2, 3)) + +let a1 = f([]); // {} +>a1 : Symbol(a1, Decl(neverInference.ts, 4, 3)) +>f : Symbol(f, Decl(neverInference.ts, 0, 0)) + +let a2 = f(neverArray); // never +>a2 : Symbol(a2, Decl(neverInference.ts, 5, 3)) +>f : Symbol(f, Decl(neverInference.ts, 0, 0)) +>neverArray : Symbol(neverArray, Decl(neverInference.ts, 2, 3)) + +// Repro from #19576 + +type Comparator = (x: T, y: T) => number; +>Comparator : Symbol(Comparator, Decl(neverInference.ts, 5, 23)) +>T : Symbol(T, Decl(neverInference.ts, 9, 16)) +>x : Symbol(x, Decl(neverInference.ts, 9, 22)) +>T : Symbol(T, Decl(neverInference.ts, 9, 16)) +>y : Symbol(y, Decl(neverInference.ts, 9, 27)) +>T : Symbol(T, Decl(neverInference.ts, 9, 16)) + +interface LinkedList { +>LinkedList : Symbol(LinkedList, Decl(neverInference.ts, 9, 44)) +>T : Symbol(T, Decl(neverInference.ts, 11, 21)) + + comparator: Comparator, +>comparator : Symbol(LinkedList.comparator, Decl(neverInference.ts, 11, 25)) +>Comparator : Symbol(Comparator, Decl(neverInference.ts, 5, 23)) +>T : Symbol(T, Decl(neverInference.ts, 11, 21)) + + nodes: Node +>nodes : Symbol(LinkedList.nodes, Decl(neverInference.ts, 12, 30)) +>Node : Symbol(Node, Decl(neverInference.ts, 14, 1)) +>T : Symbol(T, Decl(neverInference.ts, 11, 21)) +} + +type Node = { value: T, next: Node } | null +>Node : Symbol(Node, Decl(neverInference.ts, 14, 1)) +>T : Symbol(T, Decl(neverInference.ts, 16, 10)) +>value : Symbol(value, Decl(neverInference.ts, 16, 16)) +>T : Symbol(T, Decl(neverInference.ts, 16, 10)) +>next : Symbol(next, Decl(neverInference.ts, 16, 26)) +>Node : Symbol(Node, Decl(neverInference.ts, 14, 1)) +>T : Symbol(T, Decl(neverInference.ts, 16, 10)) + +declare function compareNumbers(x: number, y: number): number; +>compareNumbers : Symbol(compareNumbers, Decl(neverInference.ts, 16, 49)) +>x : Symbol(x, Decl(neverInference.ts, 18, 32)) +>y : Symbol(y, Decl(neverInference.ts, 18, 42)) + +declare function mkList(items: T[], comparator: Comparator): LinkedList; +>mkList : Symbol(mkList, Decl(neverInference.ts, 18, 62)) +>T : Symbol(T, Decl(neverInference.ts, 19, 24)) +>items : Symbol(items, Decl(neverInference.ts, 19, 27)) +>T : Symbol(T, Decl(neverInference.ts, 19, 24)) +>comparator : Symbol(comparator, Decl(neverInference.ts, 19, 38)) +>Comparator : Symbol(Comparator, Decl(neverInference.ts, 5, 23)) +>T : Symbol(T, Decl(neverInference.ts, 19, 24)) +>LinkedList : Symbol(LinkedList, Decl(neverInference.ts, 9, 44)) +>T : Symbol(T, Decl(neverInference.ts, 19, 24)) + +const list: LinkedList = mkList([], compareNumbers); +>list : Symbol(list, Decl(neverInference.ts, 21, 5)) +>LinkedList : Symbol(LinkedList, Decl(neverInference.ts, 9, 44)) +>mkList : Symbol(mkList, Decl(neverInference.ts, 18, 62)) +>compareNumbers : Symbol(compareNumbers, Decl(neverInference.ts, 16, 49)) + diff --git a/tests/baselines/reference/neverInference.types b/tests/baselines/reference/neverInference.types new file mode 100644 index 0000000000000..a7dd05a3f8bc8 --- /dev/null +++ b/tests/baselines/reference/neverInference.types @@ -0,0 +1,83 @@ +=== tests/cases/conformance/types/never/neverInference.ts === +declare function f(x: T[]): T; +>f : (x: T[]) => T +>T : T +>x : T[] +>T : T +>T : T + +let neverArray: never[] = []; +>neverArray : never[] +>[] : never[] + +let a1 = f([]); // {} +>a1 : {} +>f([]) : {} +>f : (x: T[]) => T +>[] : never[] + +let a2 = f(neverArray); // never +>a2 : never +>f(neverArray) : never +>f : (x: T[]) => T +>neverArray : never[] + +// Repro from #19576 + +type Comparator = (x: T, y: T) => number; +>Comparator : Comparator +>T : T +>x : T +>T : T +>y : T +>T : T + +interface LinkedList { +>LinkedList : LinkedList +>T : T + + comparator: Comparator, +>comparator : Comparator +>Comparator : Comparator +>T : T + + nodes: Node +>nodes : Node +>Node : Node +>T : T +} + +type Node = { value: T, next: Node } | null +>Node : Node +>T : T +>value : T +>T : T +>next : Node +>Node : Node +>T : T +>null : null + +declare function compareNumbers(x: number, y: number): number; +>compareNumbers : (x: number, y: number) => number +>x : number +>y : number + +declare function mkList(items: T[], comparator: Comparator): LinkedList; +>mkList : (items: T[], comparator: Comparator) => LinkedList +>T : T +>items : T[] +>T : T +>comparator : Comparator +>Comparator : Comparator +>T : T +>LinkedList : LinkedList +>T : T + +const list: LinkedList = mkList([], compareNumbers); +>list : LinkedList +>LinkedList : LinkedList +>mkList([], compareNumbers) : LinkedList +>mkList : (items: T[], comparator: Comparator) => LinkedList +>[] : never[] +>compareNumbers : (x: number, y: number) => number + diff --git a/tests/cases/conformance/types/never/neverInference.ts b/tests/cases/conformance/types/never/neverInference.ts new file mode 100644 index 0000000000000..1258a35e3d311 --- /dev/null +++ b/tests/cases/conformance/types/never/neverInference.ts @@ -0,0 +1,24 @@ +// @strict: true + +declare function f(x: T[]): T; + +let neverArray: never[] = []; + +let a1 = f([]); // {} +let a2 = f(neverArray); // never + +// Repro from #19576 + +type Comparator = (x: T, y: T) => number; + +interface LinkedList { + comparator: Comparator, + nodes: Node +} + +type Node = { value: T, next: Node } | null + +declare function compareNumbers(x: number, y: number): number; +declare function mkList(items: T[], comparator: Comparator): LinkedList; + +const list: LinkedList = mkList([], compareNumbers);