Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix empty array inference #19912

Merged
merged 5 commits into from
Nov 10, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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, <TypeParameter>target)) {
if (!(p & InferencePriority.ReturnType) && target.flags & TypeFlags.TypeParameter && !isTypeParameterAtTopLevel(originalTarget, <TypeParameter>target)) {
inference.topLevel = false;
}
}
Expand Down
1 change: 1 addition & 0 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
1 change: 1 addition & 0 deletions tests/baselines/reference/api/tsserverlibrary.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2142,6 +2142,7 @@ declare namespace ts {
NakedTypeVariable = 2,
MappedType = 4,
ReturnType = 8,
NeverType = 16,
}
interface InferenceInfo {
typeParameter: TypeParameter;
Expand Down
1 change: 1 addition & 0 deletions tests/baselines/reference/api/typescript.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2142,6 +2142,7 @@ declare namespace ts {
NakedTypeVariable = 2,
MappedType = 4,
ReturnType = 8,
NeverType = 16,
}
interface InferenceInfo {
typeParameter: TypeParameter;
Expand Down
22 changes: 15 additions & 7 deletions tests/baselines/reference/neverInference.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
//// [neverInference.ts]
declare function f<T>(x: T[]): T;
declare function f1<T>(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

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

const list: LinkedList<number> = mkList([], compareNumbers);

// Repro from #19858

declare function f2<a>(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);
61 changes: 48 additions & 13 deletions tests/baselines/reference/neverInference.symbols
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
=== tests/cases/conformance/types/never/neverInference.ts ===
declare function f<T>(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<T>(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<T> = (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))
Expand All @@ -34,7 +34,7 @@ interface LinkedList<T> {

comparator: Comparator<T>,
>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<T>
Expand Down Expand Up @@ -63,7 +63,7 @@ declare function mkList<T>(items: T[], comparator: Comparator<T>): LinkedList<T>
>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))
Expand All @@ -74,3 +74,38 @@ const list: LinkedList<number> = mkList([], compareNumbers);
>mkList : Symbol(mkList, Decl(neverInference.ts, 18, 62))
>compareNumbers : Symbol(compareNumbers, Decl(neverInference.ts, 16, 49))

// Repro from #19858

declare function f2<a>(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))

67 changes: 58 additions & 9 deletions tests/baselines/reference/neverInference.types
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
=== tests/cases/conformance/types/never/neverInference.ts ===
declare function f<T>(x: T[]): T;
>f : <T>(x: T[]) => T
declare function f1<T>(x: T[]): T;
>f1 : <T>(x: T[]) => T
>T : T
>x : T[]
>T : T
Expand All @@ -10,16 +10,16 @@ let neverArray: never[] = [];
>neverArray : never[]
>[] : never[]

let a1 = f([]); // {}
>a1 : {}
>f([]) : {}
>f : <T>(x: T[]) => T
let a1 = f1([]); // never
>a1 : never
>f1([]) : never
>f1 : <T>(x: T[]) => T
>[] : never[]

let a2 = f(neverArray); // never
let a2 = f1(neverArray); // never
>a2 : never
>f(neverArray) : never
>f : <T>(x: T[]) => T
>f1(neverArray) : never
>f1 : <T>(x: T[]) => T
>neverArray : never[]

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

// Repro from #19858

declare function f2<a>(as1: a[], as2: a[], cmp: (a1: a, a2: a) => number): void;
>f2 : <a>(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 : <a>(as1: a[], as2: a[], cmp: (a1: a, a2: a) => number) => void
>Array.from([0]) : number[]
>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[]; }
>Array : ArrayConstructor
>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[]; }
>[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 : <a>(as1: a[], as2: a[], cmp: (a1: a, a2: a) => number) => void
>Array.from([]) : never[]
>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[]; }
>Array : ArrayConstructor
>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[]; }
>[] : 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

13 changes: 10 additions & 3 deletions tests/cases/conformance/types/never/neverInference.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
// @strict: true
// @target: es2015

declare function f<T>(x: T[]): T;
declare function f1<T>(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

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

const list: LinkedList<number> = mkList([], compareNumbers);

// Repro from #19858

declare function f2<a>(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);