From 6f37d31e18d3fdf68dee1ce83b5ddc08dd850a79 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Mon, 21 Mar 2016 15:15:41 -0700 Subject: [PATCH] drop inference limit --- src/compiler/checker.ts | 6 - tests/baselines/reference/inferenceLimit.js | 82 ++++++++++++ .../reference/inferenceLimit.symbols | 101 ++++++++++++++ .../baselines/reference/inferenceLimit.types | 123 ++++++++++++++++++ tests/cases/compiler/inferenceLimit.ts | 41 ++++++ 5 files changed, 347 insertions(+), 6 deletions(-) create mode 100644 tests/baselines/reference/inferenceLimit.js create mode 100644 tests/baselines/reference/inferenceLimit.symbols create mode 100644 tests/baselines/reference/inferenceLimit.types create mode 100644 tests/cases/compiler/inferenceLimit.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b7779fc9da0..90ded8fc6bc 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6673,7 +6673,6 @@ namespace ts { function inferTypes(context: InferenceContext, source: Type, target: Type) { let sourceStack: Type[]; let targetStack: Type[]; - const maxDepth = 5; let depth = 0; let inferiority = 0; const visited: Map = {}; @@ -6802,11 +6801,6 @@ namespace ts { if (isInProcess(source, target)) { return; } - // we delibirately limit the depth we examine to infer types: this speeds up the overall inference process - // and user rarely expects inferences to be made from the deeply nested constituents. - if (depth > maxDepth) { - return; - } if (isDeeplyNestedGeneric(source, sourceStack, depth) && isDeeplyNestedGeneric(target, targetStack, depth)) { return; } diff --git a/tests/baselines/reference/inferenceLimit.js b/tests/baselines/reference/inferenceLimit.js new file mode 100644 index 00000000000..a74bf59df44 --- /dev/null +++ b/tests/baselines/reference/inferenceLimit.js @@ -0,0 +1,82 @@ +//// [tests/cases/compiler/inferenceLimit.ts] //// + +//// [file1.ts] +"use strict"; +import * as MyModule from "./mymodule"; + +export class BrokenClass { + + constructor() {} + + public brokenMethod(field: string, value: string) { + return new Promise>((resolve, reject) => { + + let result: Array = []; + + let populateItems = (order) => { + return new Promise((resolve, reject) => { + this.doStuff(order.id) + .then((items) => { + order.items = items; + resolve(order); + }); + }); + }; + + return Promise.all(result.map(populateItems)) + .then((orders: Array) => { + resolve(orders); + }); + }); + } + + public async doStuff(id: number) { + return; + } +} + +//// [mymodule.ts] +export interface MyModel { + id: number; +} + +//// [mymodule.js] +"use strict"; +//// [file1.js] +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments)).next()); + }); +}; +class BrokenClass { + constructor() { + } + brokenMethod(field, value) { + return new Promise((resolve, reject) => { + let result = []; + let populateItems = (order) => { + return new Promise((resolve, reject) => { + this.doStuff(order.id) + .then((items) => { + order.items = items; + resolve(order); + }); + }); + }; + return Promise.all(result.map(populateItems)) + .then((orders) => { + resolve(orders); + }); + }); + } + doStuff(id) { + return __awaiter(this, void 0, void 0, function* () { + return; + }); + } +} +exports.BrokenClass = BrokenClass; diff --git a/tests/baselines/reference/inferenceLimit.symbols b/tests/baselines/reference/inferenceLimit.symbols new file mode 100644 index 00000000000..8a338b80307 --- /dev/null +++ b/tests/baselines/reference/inferenceLimit.symbols @@ -0,0 +1,101 @@ +=== tests/cases/compiler/file1.ts === +"use strict"; +import * as MyModule from "./mymodule"; +>MyModule : Symbol(MyModule, Decl(file1.ts, 1, 6)) + +export class BrokenClass { +>BrokenClass : Symbol(BrokenClass, Decl(file1.ts, 1, 39)) + + constructor() {} + + public brokenMethod(field: string, value: string) { +>brokenMethod : Symbol(BrokenClass.brokenMethod, Decl(file1.ts, 5, 18)) +>field : Symbol(field, Decl(file1.ts, 7, 22)) +>value : Symbol(value, Decl(file1.ts, 7, 36)) + + return new Promise>((resolve, reject) => { +>Promise : Symbol(Promise, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>MyModule : Symbol(MyModule, Decl(file1.ts, 1, 6)) +>MyModel : Symbol(MyModule.MyModel, Decl(mymodule.ts, 0, 0)) +>resolve : Symbol(resolve, Decl(file1.ts, 8, 47)) +>reject : Symbol(reject, Decl(file1.ts, 8, 55)) + + let result: Array = []; +>result : Symbol(result, Decl(file1.ts, 10, 7)) +>Array : Symbol(Array, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>MyModule : Symbol(MyModule, Decl(file1.ts, 1, 6)) +>MyModel : Symbol(MyModule.MyModel, Decl(mymodule.ts, 0, 0)) + + let populateItems = (order) => { +>populateItems : Symbol(populateItems, Decl(file1.ts, 12, 7)) +>order : Symbol(order, Decl(file1.ts, 12, 25)) + + return new Promise((resolve, reject) => { +>Promise : Symbol(Promise, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>resolve : Symbol(resolve, Decl(file1.ts, 13, 26)) +>reject : Symbol(reject, Decl(file1.ts, 13, 34)) + + this.doStuff(order.id) +>this.doStuff(order.id) .then : Symbol(Promise.then, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>this.doStuff : Symbol(BrokenClass.doStuff, Decl(file1.ts, 27, 3)) +>this : Symbol(BrokenClass, Decl(file1.ts, 1, 39)) +>doStuff : Symbol(BrokenClass.doStuff, Decl(file1.ts, 27, 3)) +>order : Symbol(order, Decl(file1.ts, 12, 25)) + + .then((items) => { +>then : Symbol(Promise.then, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>items : Symbol(items, Decl(file1.ts, 15, 17)) + + order.items = items; +>order : Symbol(order, Decl(file1.ts, 12, 25)) +>items : Symbol(items, Decl(file1.ts, 15, 17)) + + resolve(order); +>resolve : Symbol(resolve, Decl(file1.ts, 13, 26)) +>order : Symbol(order, Decl(file1.ts, 12, 25)) + + }); + }); + }; + + return Promise.all(result.map(populateItems)) +>Promise.all(result.map(populateItems)) .then : Symbol(Promise.then, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>Promise.all : Symbol(PromiseConstructor.all, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>Promise : Symbol(Promise, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>all : Symbol(PromiseConstructor.all, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>result.map : Symbol(Array.map, Decl(lib.d.ts, --, --)) +>result : Symbol(result, Decl(file1.ts, 10, 7)) +>map : Symbol(Array.map, Decl(lib.d.ts, --, --)) +>populateItems : Symbol(populateItems, Decl(file1.ts, 12, 7)) + + .then((orders: Array) => { +>then : Symbol(Promise.then, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>orders : Symbol(orders, Decl(file1.ts, 23, 13)) +>Array : Symbol(Array, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>MyModule : Symbol(MyModule, Decl(file1.ts, 1, 6)) +>MyModel : Symbol(MyModule.MyModel, Decl(mymodule.ts, 0, 0)) + + resolve(orders); +>resolve : Symbol(resolve, Decl(file1.ts, 8, 47)) +>orders : Symbol(orders, Decl(file1.ts, 23, 13)) + + }); + }); + } + + public async doStuff(id: number) { +>doStuff : Symbol(BrokenClass.doStuff, Decl(file1.ts, 27, 3)) +>id : Symbol(id, Decl(file1.ts, 29, 23)) + + return; + } +} + +=== tests/cases/compiler/mymodule.ts === +export interface MyModel { +>MyModel : Symbol(MyModel, Decl(mymodule.ts, 0, 0)) + + id: number; +>id : Symbol(MyModel.id, Decl(mymodule.ts, 0, 26)) +} diff --git a/tests/baselines/reference/inferenceLimit.types b/tests/baselines/reference/inferenceLimit.types new file mode 100644 index 00000000000..58f9b1e4ae0 --- /dev/null +++ b/tests/baselines/reference/inferenceLimit.types @@ -0,0 +1,123 @@ +=== tests/cases/compiler/file1.ts === +"use strict"; +>"use strict" : string + +import * as MyModule from "./mymodule"; +>MyModule : typeof MyModule + +export class BrokenClass { +>BrokenClass : BrokenClass + + constructor() {} + + public brokenMethod(field: string, value: string) { +>brokenMethod : (field: string, value: string) => Promise +>field : string +>value : string + + return new Promise>((resolve, reject) => { +>new Promise>((resolve, reject) => { let result: Array = []; let populateItems = (order) => { return new Promise((resolve, reject) => { this.doStuff(order.id) .then((items) => { order.items = items; resolve(order); }); }); }; return Promise.all(result.map(populateItems)) .then((orders: Array) => { resolve(orders); }); }) : Promise +>Promise : PromiseConstructor +>Array : T[] +>MyModule : any +>MyModel : MyModule.MyModel +>(resolve, reject) => { let result: Array = []; let populateItems = (order) => { return new Promise((resolve, reject) => { this.doStuff(order.id) .then((items) => { order.items = items; resolve(order); }); }); }; return Promise.all(result.map(populateItems)) .then((orders: Array) => { resolve(orders); }); } : (resolve: (value?: MyModule.MyModel[] | PromiseLike) => void, reject: (reason?: any) => void) => Promise +>resolve : (value?: MyModule.MyModel[] | PromiseLike) => void +>reject : (reason?: any) => void + + let result: Array = []; +>result : MyModule.MyModel[] +>Array : T[] +>MyModule : any +>MyModel : MyModule.MyModel +>[] : undefined[] + + let populateItems = (order) => { +>populateItems : (order: any) => Promise<{}> +>(order) => { return new Promise((resolve, reject) => { this.doStuff(order.id) .then((items) => { order.items = items; resolve(order); }); }); } : (order: any) => Promise<{}> +>order : any + + return new Promise((resolve, reject) => { +>new Promise((resolve, reject) => { this.doStuff(order.id) .then((items) => { order.items = items; resolve(order); }); }) : Promise<{}> +>Promise : PromiseConstructor +>(resolve, reject) => { this.doStuff(order.id) .then((items) => { order.items = items; resolve(order); }); } : (resolve: (value?: {} | PromiseLike<{}>) => void, reject: (reason?: any) => void) => void +>resolve : (value?: {} | PromiseLike<{}>) => void +>reject : (reason?: any) => void + + this.doStuff(order.id) +>this.doStuff(order.id) .then((items) => { order.items = items; resolve(order); }) : Promise +>this.doStuff(order.id) .then : { (onfulfilled?: (value: void) => TResult | PromiseLike, onrejected?: (reason: any) => TResult | PromiseLike): Promise; (onfulfilled?: (value: void) => TResult | PromiseLike, onrejected?: (reason: any) => void): Promise; } +>this.doStuff(order.id) : Promise +>this.doStuff : (id: number) => Promise +>this : this +>doStuff : (id: number) => Promise +>order.id : any +>order : any +>id : any + + .then((items) => { +>then : { (onfulfilled?: (value: void) => TResult | PromiseLike, onrejected?: (reason: any) => TResult | PromiseLike): Promise; (onfulfilled?: (value: void) => TResult | PromiseLike, onrejected?: (reason: any) => void): Promise; } +>(items) => { order.items = items; resolve(order); } : (items: void) => void +>items : void + + order.items = items; +>order.items = items : void +>order.items : any +>order : any +>items : any +>items : void + + resolve(order); +>resolve(order) : void +>resolve : (value?: {} | PromiseLike<{}>) => void +>order : any + + }); + }); + }; + + return Promise.all(result.map(populateItems)) +>Promise.all(result.map(populateItems)) .then((orders: Array) => { resolve(orders); }) : Promise +>Promise.all(result.map(populateItems)) .then : { (onfulfilled?: (value: {}[]) => TResult | PromiseLike, onrejected?: (reason: any) => TResult | PromiseLike): Promise; (onfulfilled?: (value: {}[]) => TResult | PromiseLike, onrejected?: (reason: any) => void): Promise; } +>Promise.all(result.map(populateItems)) : Promise<{}[]> +>Promise.all : { (values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike, T4 | PromiseLike, T5 | PromiseLike, T6 | PromiseLike, T7 | PromiseLike, T8 | PromiseLike, T9 | PromiseLike, T10 | PromiseLike]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]>; (values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike, T4 | PromiseLike, T5 | PromiseLike, T6 | PromiseLike, T7 | PromiseLike, T8 | PromiseLike, T9 | PromiseLike]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9]>; (values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike, T4 | PromiseLike, T5 | PromiseLike, T6 | PromiseLike, T7 | PromiseLike, T8 | PromiseLike]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8]>; (values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike, T4 | PromiseLike, T5 | PromiseLike, T6 | PromiseLike, T7 | PromiseLike]): Promise<[T1, T2, T3, T4, T5, T6, T7]>; (values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike, T4 | PromiseLike, T5 | PromiseLike, T6 | PromiseLike]): Promise<[T1, T2, T3, T4, T5, T6]>; (values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike, T4 | PromiseLike, T5 | PromiseLike]): Promise<[T1, T2, T3, T4, T5]>; (values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike, T4 | PromiseLike]): Promise<[T1, T2, T3, T4]>; (values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike]): Promise<[T1, T2, T3]>; (values: [T1 | PromiseLike, T2 | PromiseLike]): Promise<[T1, T2]>; (values: Iterable>): Promise; } +>Promise : PromiseConstructor +>all : { (values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike, T4 | PromiseLike, T5 | PromiseLike, T6 | PromiseLike, T7 | PromiseLike, T8 | PromiseLike, T9 | PromiseLike, T10 | PromiseLike]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]>; (values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike, T4 | PromiseLike, T5 | PromiseLike, T6 | PromiseLike, T7 | PromiseLike, T8 | PromiseLike, T9 | PromiseLike]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9]>; (values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike, T4 | PromiseLike, T5 | PromiseLike, T6 | PromiseLike, T7 | PromiseLike, T8 | PromiseLike]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8]>; (values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike, T4 | PromiseLike, T5 | PromiseLike, T6 | PromiseLike, T7 | PromiseLike]): Promise<[T1, T2, T3, T4, T5, T6, T7]>; (values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike, T4 | PromiseLike, T5 | PromiseLike, T6 | PromiseLike]): Promise<[T1, T2, T3, T4, T5, T6]>; (values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike, T4 | PromiseLike, T5 | PromiseLike]): Promise<[T1, T2, T3, T4, T5]>; (values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike, T4 | PromiseLike]): Promise<[T1, T2, T3, T4]>; (values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike]): Promise<[T1, T2, T3]>; (values: [T1 | PromiseLike, T2 | PromiseLike]): Promise<[T1, T2]>; (values: Iterable>): Promise; } +>result.map(populateItems) : Promise<{}>[] +>result.map : (callbackfn: (value: MyModule.MyModel, index: number, array: MyModule.MyModel[]) => U, thisArg?: any) => U[] +>result : MyModule.MyModel[] +>map : (callbackfn: (value: MyModule.MyModel, index: number, array: MyModule.MyModel[]) => U, thisArg?: any) => U[] +>populateItems : (order: any) => Promise<{}> + + .then((orders: Array) => { +>then : { (onfulfilled?: (value: {}[]) => TResult | PromiseLike, onrejected?: (reason: any) => TResult | PromiseLike): Promise; (onfulfilled?: (value: {}[]) => TResult | PromiseLike, onrejected?: (reason: any) => void): Promise; } +>(orders: Array) => { resolve(orders); } : (orders: MyModule.MyModel[]) => void +>orders : MyModule.MyModel[] +>Array : T[] +>MyModule : any +>MyModel : MyModule.MyModel + + resolve(orders); +>resolve(orders) : void +>resolve : (value?: MyModule.MyModel[] | PromiseLike) => void +>orders : MyModule.MyModel[] + + }); + }); + } + + public async doStuff(id: number) { +>doStuff : (id: number) => Promise +>id : number + + return; + } +} + +=== tests/cases/compiler/mymodule.ts === +export interface MyModel { +>MyModel : MyModel + + id: number; +>id : number +} diff --git a/tests/cases/compiler/inferenceLimit.ts b/tests/cases/compiler/inferenceLimit.ts new file mode 100644 index 00000000000..adaf13bad22 --- /dev/null +++ b/tests/cases/compiler/inferenceLimit.ts @@ -0,0 +1,41 @@ +// @target: es6 +// @module: commonjs +// @filename: file1.ts +"use strict"; +import * as MyModule from "./mymodule"; + +export class BrokenClass { + + constructor() {} + + public brokenMethod(field: string, value: string) { + return new Promise>((resolve, reject) => { + + let result: Array = []; + + let populateItems = (order) => { + return new Promise((resolve, reject) => { + this.doStuff(order.id) + .then((items) => { + order.items = items; + resolve(order); + }); + }); + }; + + return Promise.all(result.map(populateItems)) + .then((orders: Array) => { + resolve(orders); + }); + }); + } + + public async doStuff(id: number) { + return; + } +} + +// @filename: mymodule.ts +export interface MyModel { + id: number; +} \ No newline at end of file