From 2010c4cda1097697390d981d63d31600d1fe9808 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 10 Nov 2017 08:30:59 -0800 Subject: [PATCH 1/5] Give lowest priority to inferences made from empty array literals --- src/compiler/checker.ts | 17 ++++++++++------- src/compiler/types.ts | 1 + 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a9aaa77fa74..fedc0c77c8f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10898,22 +10898,25 @@ namespace ts { // 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) and - // implicitNeverType (which is used as the element type for empty array literals). - if (source.flags & TypeFlags.ContainsAnyFunctionType || source === silentNeverType || source === implicitNeverType) { + // when constructing types from type parameters that had no inference candidates). + if (source.flags & TypeFlags.ContainsAnyFunctionType || source === silentNeverType) { return; } const inference = getInferenceInfoForType(target); if (inference) { if (!inference.isFixed) { - if (!inference.candidates || priority < inference.priority) { + // We give lowest priority to inferences of implicitNeverType (which is used as the + // element type for empty array literals). Thus, inferences from empty array literals + // only matter when no other inferences are made. + const p = priority | (source === implicitNeverType ? InferencePriority.NeverType : 0); + if (!inference.candidates || p < inference.priority) { inference.candidates = [source]; - inference.priority = priority; + inference.priority = p; } - else if (priority === inference.priority) { + else if (p === inference.priority) { inference.candidates.push(source); } - if (!(priority & InferencePriority.ReturnType) && target.flags & TypeFlags.TypeParameter && !isTypeParameterAtTopLevel(originalTarget, target)) { + if (!(p & InferencePriority.ReturnType) && target.flags & TypeFlags.TypeParameter && !isTypeParameterAtTopLevel(originalTarget, target)) { inference.topLevel = false; } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index bb62bead00b..3141e3f22d9 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3613,6 +3613,7 @@ namespace ts { NakedTypeVariable = 1 << 1, // Naked type variable in union or intersection type MappedType = 1 << 2, // Reverse inference for mapped type ReturnType = 1 << 3, // Inference made from return type of generic function + NeverType = 1 << 4, // Inference made from the never type } export interface InferenceInfo { From 197c635994a5d02c50d6066f05f4382da446a8fa Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 10 Nov 2017 08:36:50 -0800 Subject: [PATCH 2/5] Update tests --- .../cases/conformance/types/never/neverInference.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tests/cases/conformance/types/never/neverInference.ts b/tests/cases/conformance/types/never/neverInference.ts index 1258a35e3d3..c28d30d92c2 100644 --- a/tests/cases/conformance/types/never/neverInference.ts +++ b/tests/cases/conformance/types/never/neverInference.ts @@ -1,11 +1,11 @@ // @strict: true -declare function f(x: T[]): T; +declare function f1(x: T[]): T; let neverArray: never[] = []; -let a1 = f([]); // {} -let a2 = f(neverArray); // never +let a1 = f1([]); // never +let a2 = f1(neverArray); // never // Repro from #19576 @@ -22,3 +22,9 @@ declare function compareNumbers(x: number, y: number): number; declare function mkList(items: T[], comparator: Comparator): LinkedList; const list: LinkedList = mkList([], compareNumbers); + +// Repro from #19858 + +declare function f2(as1: a[], as2: a[], cmp: (a1: a, a2: a) => number): void; +f2(Array.from([0]), [], (a1, a2) => a1 - a2); +f2(Array.from([]), [0], (a1, a2) => a1 - a2); From afec1e1fa154e1a51ec60ef15433f93ace5b74b9 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 10 Nov 2017 08:39:29 -0800 Subject: [PATCH 3/5] Update test --- tests/cases/conformance/types/never/neverInference.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cases/conformance/types/never/neverInference.ts b/tests/cases/conformance/types/never/neverInference.ts index c28d30d92c2..549d27ae109 100644 --- a/tests/cases/conformance/types/never/neverInference.ts +++ b/tests/cases/conformance/types/never/neverInference.ts @@ -1,4 +1,5 @@ // @strict: true +// @target: es2015 declare function f1(x: T[]): T; From 2c43ef1e9b262477ced59124f2541a5102d0894d Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 10 Nov 2017 08:39:49 -0800 Subject: [PATCH 4/5] Accept new baselines --- tests/baselines/reference/neverInference.js | 22 ++++-- .../reference/neverInference.symbols | 61 +++++++++++++---- .../baselines/reference/neverInference.types | 67 ++++++++++++++++--- 3 files changed, 121 insertions(+), 29 deletions(-) diff --git a/tests/baselines/reference/neverInference.js b/tests/baselines/reference/neverInference.js index d13e537eba4..3b570599772 100644 --- a/tests/baselines/reference/neverInference.js +++ b/tests/baselines/reference/neverInference.js @@ -1,10 +1,10 @@ //// [neverInference.ts] -declare function f(x: T[]): T; +declare function f1(x: T[]): T; let neverArray: never[] = []; -let a1 = f([]); // {} -let a2 = f(neverArray); // never +let a1 = f1([]); // never +let a2 = f1(neverArray); // never // Repro from #19576 @@ -21,11 +21,19 @@ declare function compareNumbers(x: number, y: number): number; declare function mkList(items: T[], comparator: Comparator): LinkedList; const list: LinkedList = mkList([], compareNumbers); + +// Repro from #19858 + +declare function f2(as1: a[], as2: a[], cmp: (a1: a, a2: a) => number): void; +f2(Array.from([0]), [], (a1, a2) => a1 - a2); +f2(Array.from([]), [0], (a1, a2) => a1 - a2); //// [neverInference.js] "use strict"; -var neverArray = []; -var a1 = f([]); // {} -var a2 = f(neverArray); // never -var list = mkList([], compareNumbers); +let neverArray = []; +let a1 = f1([]); // never +let a2 = f1(neverArray); // never +const list = mkList([], compareNumbers); +f2(Array.from([0]), [], (a1, a2) => a1 - a2); +f2(Array.from([]), [0], (a1, a2) => a1 - a2); diff --git a/tests/baselines/reference/neverInference.symbols b/tests/baselines/reference/neverInference.symbols index 683e079b2f8..0441770dd3f 100644 --- a/tests/baselines/reference/neverInference.symbols +++ b/tests/baselines/reference/neverInference.symbols @@ -1,27 +1,27 @@ === 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)) +declare function f1(x: T[]): T; +>f1 : Symbol(f1, Decl(neverInference.ts, 0, 0)) +>T : Symbol(T, Decl(neverInference.ts, 0, 20)) +>x : Symbol(x, Decl(neverInference.ts, 0, 23)) +>T : Symbol(T, Decl(neverInference.ts, 0, 20)) +>T : Symbol(T, Decl(neverInference.ts, 0, 20)) let neverArray: never[] = []; >neverArray : Symbol(neverArray, Decl(neverInference.ts, 2, 3)) -let a1 = f([]); // {} +let a1 = f1([]); // never >a1 : Symbol(a1, Decl(neverInference.ts, 4, 3)) ->f : Symbol(f, Decl(neverInference.ts, 0, 0)) +>f1 : Symbol(f1, Decl(neverInference.ts, 0, 0)) -let a2 = f(neverArray); // never +let a2 = f1(neverArray); // never >a2 : Symbol(a2, Decl(neverInference.ts, 5, 3)) ->f : Symbol(f, Decl(neverInference.ts, 0, 0)) +>f1 : Symbol(f1, 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)) +>Comparator : Symbol(Comparator, Decl(neverInference.ts, 5, 24)) >T : Symbol(T, Decl(neverInference.ts, 9, 16)) >x : Symbol(x, Decl(neverInference.ts, 9, 22)) >T : Symbol(T, Decl(neverInference.ts, 9, 16)) @@ -34,7 +34,7 @@ interface LinkedList { comparator: Comparator, >comparator : Symbol(LinkedList.comparator, Decl(neverInference.ts, 11, 25)) ->Comparator : Symbol(Comparator, Decl(neverInference.ts, 5, 23)) +>Comparator : Symbol(Comparator, Decl(neverInference.ts, 5, 24)) >T : Symbol(T, Decl(neverInference.ts, 11, 21)) nodes: Node @@ -63,7 +63,7 @@ declare function mkList(items: T[], comparator: Comparator): LinkedList >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)) +>Comparator : Symbol(Comparator, Decl(neverInference.ts, 5, 24)) >T : Symbol(T, Decl(neverInference.ts, 19, 24)) >LinkedList : Symbol(LinkedList, Decl(neverInference.ts, 9, 44)) >T : Symbol(T, Decl(neverInference.ts, 19, 24)) @@ -74,3 +74,38 @@ const list: LinkedList = mkList([], compareNumbers); >mkList : Symbol(mkList, Decl(neverInference.ts, 18, 62)) >compareNumbers : Symbol(compareNumbers, Decl(neverInference.ts, 16, 49)) +// Repro from #19858 + +declare function f2(as1: a[], as2: a[], cmp: (a1: a, a2: a) => number): void; +>f2 : Symbol(f2, Decl(neverInference.ts, 21, 60)) +>a : Symbol(a, Decl(neverInference.ts, 25, 20)) +>as1 : Symbol(as1, Decl(neverInference.ts, 25, 23)) +>a : Symbol(a, Decl(neverInference.ts, 25, 20)) +>as2 : Symbol(as2, Decl(neverInference.ts, 25, 32)) +>a : Symbol(a, Decl(neverInference.ts, 25, 20)) +>cmp : Symbol(cmp, Decl(neverInference.ts, 25, 42)) +>a1 : Symbol(a1, Decl(neverInference.ts, 25, 49)) +>a : Symbol(a, Decl(neverInference.ts, 25, 20)) +>a2 : Symbol(a2, Decl(neverInference.ts, 25, 55)) +>a : Symbol(a, Decl(neverInference.ts, 25, 20)) + +f2(Array.from([0]), [], (a1, a2) => a1 - a2); +>f2 : Symbol(f2, Decl(neverInference.ts, 21, 60)) +>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, --, --)) +>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, --, --)) +>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, --, --)) +>a1 : Symbol(a1, Decl(neverInference.ts, 26, 25)) +>a2 : Symbol(a2, Decl(neverInference.ts, 26, 28)) +>a1 : Symbol(a1, Decl(neverInference.ts, 26, 25)) +>a2 : Symbol(a2, Decl(neverInference.ts, 26, 28)) + +f2(Array.from([]), [0], (a1, a2) => a1 - a2); +>f2 : Symbol(f2, Decl(neverInference.ts, 21, 60)) +>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, --, --)) +>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, --, --)) +>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, --, --)) +>a1 : Symbol(a1, Decl(neverInference.ts, 27, 25)) +>a2 : Symbol(a2, Decl(neverInference.ts, 27, 28)) +>a1 : Symbol(a1, Decl(neverInference.ts, 27, 25)) +>a2 : Symbol(a2, Decl(neverInference.ts, 27, 28)) + diff --git a/tests/baselines/reference/neverInference.types b/tests/baselines/reference/neverInference.types index a7dd05a3f8b..2f4b9e0cc1e 100644 --- a/tests/baselines/reference/neverInference.types +++ b/tests/baselines/reference/neverInference.types @@ -1,6 +1,6 @@ === tests/cases/conformance/types/never/neverInference.ts === -declare function f(x: T[]): T; ->f : (x: T[]) => T +declare function f1(x: T[]): T; +>f1 : (x: T[]) => T >T : T >x : T[] >T : T @@ -10,16 +10,16 @@ let neverArray: never[] = []; >neverArray : never[] >[] : never[] -let a1 = f([]); // {} ->a1 : {} ->f([]) : {} ->f : (x: T[]) => T +let a1 = f1([]); // never +>a1 : never +>f1([]) : never +>f1 : (x: T[]) => T >[] : never[] -let a2 = f(neverArray); // never +let a2 = f1(neverArray); // never >a2 : never ->f(neverArray) : never ->f : (x: T[]) => T +>f1(neverArray) : never +>f1 : (x: T[]) => T >neverArray : never[] // Repro from #19576 @@ -81,3 +81,52 @@ const list: LinkedList = mkList([], compareNumbers); >[] : never[] >compareNumbers : (x: number, y: number) => number +// Repro from #19858 + +declare function f2(as1: a[], as2: a[], cmp: (a1: a, a2: a) => number): void; +>f2 : (as1: a[], as2: a[], cmp: (a1: a, a2: a) => number) => void +>a : a +>as1 : a[] +>a : a +>as2 : a[] +>a : a +>cmp : (a1: a, a2: a) => number +>a1 : a +>a : a +>a2 : a +>a : a + +f2(Array.from([0]), [], (a1, a2) => a1 - a2); +>f2(Array.from([0]), [], (a1, a2) => a1 - a2) : void +>f2 : (as1: a[], as2: a[], cmp: (a1: a, a2: a) => number) => void +>Array.from([0]) : number[] +>Array.from : { (iterable: Iterable): T[]; (iterable: Iterable, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>Array : ArrayConstructor +>from : { (iterable: Iterable): T[]; (iterable: Iterable, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>[0] : number[] +>0 : 0 +>[] : never[] +>(a1, a2) => a1 - a2 : (a1: number, a2: number) => number +>a1 : number +>a2 : number +>a1 - a2 : number +>a1 : number +>a2 : number + +f2(Array.from([]), [0], (a1, a2) => a1 - a2); +>f2(Array.from([]), [0], (a1, a2) => a1 - a2) : void +>f2 : (as1: a[], as2: a[], cmp: (a1: a, a2: a) => number) => void +>Array.from([]) : never[] +>Array.from : { (iterable: Iterable): T[]; (iterable: Iterable, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>Array : ArrayConstructor +>from : { (iterable: Iterable): T[]; (iterable: Iterable, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>[] : never[] +>[0] : number[] +>0 : 0 +>(a1, a2) => a1 - a2 : (a1: number, a2: number) => number +>a1 : number +>a2 : number +>a1 - a2 : number +>a1 : number +>a2 : number + From c3b650fb38eaba314301edc0a6ce64a7b122acd2 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 10 Nov 2017 08:44:38 -0800 Subject: [PATCH 5/5] Accept API baseline changes --- tests/baselines/reference/api/tsserverlibrary.d.ts | 1 + tests/baselines/reference/api/typescript.d.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 78e8a377ec0..ffca9ca6c5a 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -2142,6 +2142,7 @@ declare namespace ts { NakedTypeVariable = 2, MappedType = 4, ReturnType = 8, + NeverType = 16, } interface InferenceInfo { typeParameter: TypeParameter; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 3344193d0ce..dcc077d2cd7 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -2142,6 +2142,7 @@ declare namespace ts { NakedTypeVariable = 2, MappedType = 4, ReturnType = 8, + NeverType = 16, } interface InferenceInfo { typeParameter: TypeParameter;