Merge pull request #4153 from Microsoft/tupleTypeInference

Improved tuple type inference
This commit is contained in:
Anders Hejlsberg 2015-08-05 11:27:18 -07:00
commit c8b4a2edfd
5 changed files with 292 additions and 0 deletions

View file

@ -5732,6 +5732,14 @@ namespace ts {
inferFromTypes(sourceTypes[i], targetTypes[i]);
}
}
else if (source.flags & TypeFlags.Tuple && target.flags & TypeFlags.Tuple && (<TupleType>source).elementTypes.length === (<TupleType>target).elementTypes.length) {
// If source and target are tuples of the same size, infer from element types
let sourceTypes = (<TupleType>source).elementTypes;
let targetTypes = (<TupleType>target).elementTypes;
for (let i = 0; i < sourceTypes.length; i++) {
inferFromTypes(sourceTypes[i], targetTypes[i]);
}
}
else if (target.flags & TypeFlags.UnionOrIntersection) {
let targetTypes = (<UnionOrIntersectionType>target).types;
let typeParameterCount = 0;

View file

@ -0,0 +1,31 @@
//// [tupleTypeInference.ts]
declare var $q: IQService;
interface IQService {
all<T1, T2, T3>(x: [IPromise<T1>, IPromise<T2>, IPromise<T3>]): IPromise<[T1, T2, T3]>;
all<T1, T2>(x: [IPromise<T1>, IPromise<T2>]): IPromise<[T1, T2]>;
all<T1>(x: [IPromise<T1>]): IPromise<[T1]>;
when<T>(t?: T): IPromise<T>;
}
interface IPromise<T> {
then<TResult>(callback: (t: T) => TResult): IPromise<TResult>;
}
// Implicit different types
var a = $q.all([$q.when<string>(), $q.when<number>()]);
// Explicit different types
var b = $q.all<string, number>([$q.when<string>(), $q.when<number>()]);
// Implicit identical types
var c = $q.all([$q.when<string>(), $q.when<string>()]);
//// [tupleTypeInference.js]
// Implicit different types
var a = $q.all([$q.when(), $q.when()]);
// Explicit different types
var b = $q.all([$q.when(), $q.when()]);
// Implicit identical types
var c = $q.all([$q.when(), $q.when()]);

View file

@ -0,0 +1,110 @@
=== tests/cases/compiler/tupleTypeInference.ts ===
declare var $q: IQService;
>$q : Symbol($q, Decl(tupleTypeInference.ts, 0, 11))
>IQService : Symbol(IQService, Decl(tupleTypeInference.ts, 0, 26))
interface IQService {
>IQService : Symbol(IQService, Decl(tupleTypeInference.ts, 0, 26))
all<T1, T2, T3>(x: [IPromise<T1>, IPromise<T2>, IPromise<T3>]): IPromise<[T1, T2, T3]>;
>all : Symbol(all, Decl(tupleTypeInference.ts, 2, 21), Decl(tupleTypeInference.ts, 3, 91), Decl(tupleTypeInference.ts, 4, 69))
>T1 : Symbol(T1, Decl(tupleTypeInference.ts, 3, 8))
>T2 : Symbol(T2, Decl(tupleTypeInference.ts, 3, 11))
>T3 : Symbol(T3, Decl(tupleTypeInference.ts, 3, 15))
>x : Symbol(x, Decl(tupleTypeInference.ts, 3, 20))
>IPromise : Symbol(IPromise, Decl(tupleTypeInference.ts, 7, 1))
>T1 : Symbol(T1, Decl(tupleTypeInference.ts, 3, 8))
>IPromise : Symbol(IPromise, Decl(tupleTypeInference.ts, 7, 1))
>T2 : Symbol(T2, Decl(tupleTypeInference.ts, 3, 11))
>IPromise : Symbol(IPromise, Decl(tupleTypeInference.ts, 7, 1))
>T3 : Symbol(T3, Decl(tupleTypeInference.ts, 3, 15))
>IPromise : Symbol(IPromise, Decl(tupleTypeInference.ts, 7, 1))
>T1 : Symbol(T1, Decl(tupleTypeInference.ts, 3, 8))
>T2 : Symbol(T2, Decl(tupleTypeInference.ts, 3, 11))
>T3 : Symbol(T3, Decl(tupleTypeInference.ts, 3, 15))
all<T1, T2>(x: [IPromise<T1>, IPromise<T2>]): IPromise<[T1, T2]>;
>all : Symbol(all, Decl(tupleTypeInference.ts, 2, 21), Decl(tupleTypeInference.ts, 3, 91), Decl(tupleTypeInference.ts, 4, 69))
>T1 : Symbol(T1, Decl(tupleTypeInference.ts, 4, 8))
>T2 : Symbol(T2, Decl(tupleTypeInference.ts, 4, 11))
>x : Symbol(x, Decl(tupleTypeInference.ts, 4, 16))
>IPromise : Symbol(IPromise, Decl(tupleTypeInference.ts, 7, 1))
>T1 : Symbol(T1, Decl(tupleTypeInference.ts, 4, 8))
>IPromise : Symbol(IPromise, Decl(tupleTypeInference.ts, 7, 1))
>T2 : Symbol(T2, Decl(tupleTypeInference.ts, 4, 11))
>IPromise : Symbol(IPromise, Decl(tupleTypeInference.ts, 7, 1))
>T1 : Symbol(T1, Decl(tupleTypeInference.ts, 4, 8))
>T2 : Symbol(T2, Decl(tupleTypeInference.ts, 4, 11))
all<T1>(x: [IPromise<T1>]): IPromise<[T1]>;
>all : Symbol(all, Decl(tupleTypeInference.ts, 2, 21), Decl(tupleTypeInference.ts, 3, 91), Decl(tupleTypeInference.ts, 4, 69))
>T1 : Symbol(T1, Decl(tupleTypeInference.ts, 5, 8))
>x : Symbol(x, Decl(tupleTypeInference.ts, 5, 12))
>IPromise : Symbol(IPromise, Decl(tupleTypeInference.ts, 7, 1))
>T1 : Symbol(T1, Decl(tupleTypeInference.ts, 5, 8))
>IPromise : Symbol(IPromise, Decl(tupleTypeInference.ts, 7, 1))
>T1 : Symbol(T1, Decl(tupleTypeInference.ts, 5, 8))
when<T>(t?: T): IPromise<T>;
>when : Symbol(when, Decl(tupleTypeInference.ts, 5, 47))
>T : Symbol(T, Decl(tupleTypeInference.ts, 6, 9))
>t : Symbol(t, Decl(tupleTypeInference.ts, 6, 12))
>T : Symbol(T, Decl(tupleTypeInference.ts, 6, 9))
>IPromise : Symbol(IPromise, Decl(tupleTypeInference.ts, 7, 1))
>T : Symbol(T, Decl(tupleTypeInference.ts, 6, 9))
}
interface IPromise<T> {
>IPromise : Symbol(IPromise, Decl(tupleTypeInference.ts, 7, 1))
>T : Symbol(T, Decl(tupleTypeInference.ts, 9, 19))
then<TResult>(callback: (t: T) => TResult): IPromise<TResult>;
>then : Symbol(then, Decl(tupleTypeInference.ts, 9, 23))
>TResult : Symbol(TResult, Decl(tupleTypeInference.ts, 10, 9))
>callback : Symbol(callback, Decl(tupleTypeInference.ts, 10, 18))
>t : Symbol(t, Decl(tupleTypeInference.ts, 10, 29))
>T : Symbol(T, Decl(tupleTypeInference.ts, 9, 19))
>TResult : Symbol(TResult, Decl(tupleTypeInference.ts, 10, 9))
>IPromise : Symbol(IPromise, Decl(tupleTypeInference.ts, 7, 1))
>TResult : Symbol(TResult, Decl(tupleTypeInference.ts, 10, 9))
}
// Implicit different types
var a = $q.all([$q.when<string>(), $q.when<number>()]);
>a : Symbol(a, Decl(tupleTypeInference.ts, 14, 3))
>$q.all : Symbol(IQService.all, Decl(tupleTypeInference.ts, 2, 21), Decl(tupleTypeInference.ts, 3, 91), Decl(tupleTypeInference.ts, 4, 69))
>$q : Symbol($q, Decl(tupleTypeInference.ts, 0, 11))
>all : Symbol(IQService.all, Decl(tupleTypeInference.ts, 2, 21), Decl(tupleTypeInference.ts, 3, 91), Decl(tupleTypeInference.ts, 4, 69))
>$q.when : Symbol(IQService.when, Decl(tupleTypeInference.ts, 5, 47))
>$q : Symbol($q, Decl(tupleTypeInference.ts, 0, 11))
>when : Symbol(IQService.when, Decl(tupleTypeInference.ts, 5, 47))
>$q.when : Symbol(IQService.when, Decl(tupleTypeInference.ts, 5, 47))
>$q : Symbol($q, Decl(tupleTypeInference.ts, 0, 11))
>when : Symbol(IQService.when, Decl(tupleTypeInference.ts, 5, 47))
// Explicit different types
var b = $q.all<string, number>([$q.when<string>(), $q.when<number>()]);
>b : Symbol(b, Decl(tupleTypeInference.ts, 17, 3))
>$q.all : Symbol(IQService.all, Decl(tupleTypeInference.ts, 2, 21), Decl(tupleTypeInference.ts, 3, 91), Decl(tupleTypeInference.ts, 4, 69))
>$q : Symbol($q, Decl(tupleTypeInference.ts, 0, 11))
>all : Symbol(IQService.all, Decl(tupleTypeInference.ts, 2, 21), Decl(tupleTypeInference.ts, 3, 91), Decl(tupleTypeInference.ts, 4, 69))
>$q.when : Symbol(IQService.when, Decl(tupleTypeInference.ts, 5, 47))
>$q : Symbol($q, Decl(tupleTypeInference.ts, 0, 11))
>when : Symbol(IQService.when, Decl(tupleTypeInference.ts, 5, 47))
>$q.when : Symbol(IQService.when, Decl(tupleTypeInference.ts, 5, 47))
>$q : Symbol($q, Decl(tupleTypeInference.ts, 0, 11))
>when : Symbol(IQService.when, Decl(tupleTypeInference.ts, 5, 47))
// Implicit identical types
var c = $q.all([$q.when<string>(), $q.when<string>()]);
>c : Symbol(c, Decl(tupleTypeInference.ts, 20, 3))
>$q.all : Symbol(IQService.all, Decl(tupleTypeInference.ts, 2, 21), Decl(tupleTypeInference.ts, 3, 91), Decl(tupleTypeInference.ts, 4, 69))
>$q : Symbol($q, Decl(tupleTypeInference.ts, 0, 11))
>all : Symbol(IQService.all, Decl(tupleTypeInference.ts, 2, 21), Decl(tupleTypeInference.ts, 3, 91), Decl(tupleTypeInference.ts, 4, 69))
>$q.when : Symbol(IQService.when, Decl(tupleTypeInference.ts, 5, 47))
>$q : Symbol($q, Decl(tupleTypeInference.ts, 0, 11))
>when : Symbol(IQService.when, Decl(tupleTypeInference.ts, 5, 47))
>$q.when : Symbol(IQService.when, Decl(tupleTypeInference.ts, 5, 47))
>$q : Symbol($q, Decl(tupleTypeInference.ts, 0, 11))
>when : Symbol(IQService.when, Decl(tupleTypeInference.ts, 5, 47))

View file

@ -0,0 +1,122 @@
=== tests/cases/compiler/tupleTypeInference.ts ===
declare var $q: IQService;
>$q : IQService
>IQService : IQService
interface IQService {
>IQService : IQService
all<T1, T2, T3>(x: [IPromise<T1>, IPromise<T2>, IPromise<T3>]): IPromise<[T1, T2, T3]>;
>all : { <T1, T2, T3>(x: [IPromise<T1>, IPromise<T2>, IPromise<T3>]): IPromise<[T1, T2, T3]>; <T1, T2>(x: [IPromise<T1>, IPromise<T2>]): IPromise<[T1, T2]>; <T1>(x: [IPromise<T1>]): IPromise<[T1]>; }
>T1 : T1
>T2 : T2
>T3 : T3
>x : [IPromise<T1>, IPromise<T2>, IPromise<T3>]
>IPromise : IPromise<T>
>T1 : T1
>IPromise : IPromise<T>
>T2 : T2
>IPromise : IPromise<T>
>T3 : T3
>IPromise : IPromise<T>
>T1 : T1
>T2 : T2
>T3 : T3
all<T1, T2>(x: [IPromise<T1>, IPromise<T2>]): IPromise<[T1, T2]>;
>all : { <T1, T2, T3>(x: [IPromise<T1>, IPromise<T2>, IPromise<T3>]): IPromise<[T1, T2, T3]>; <T1, T2>(x: [IPromise<T1>, IPromise<T2>]): IPromise<[T1, T2]>; <T1>(x: [IPromise<T1>]): IPromise<[T1]>; }
>T1 : T1
>T2 : T2
>x : [IPromise<T1>, IPromise<T2>]
>IPromise : IPromise<T>
>T1 : T1
>IPromise : IPromise<T>
>T2 : T2
>IPromise : IPromise<T>
>T1 : T1
>T2 : T2
all<T1>(x: [IPromise<T1>]): IPromise<[T1]>;
>all : { <T1, T2, T3>(x: [IPromise<T1>, IPromise<T2>, IPromise<T3>]): IPromise<[T1, T2, T3]>; <T1, T2>(x: [IPromise<T1>, IPromise<T2>]): IPromise<[T1, T2]>; <T1>(x: [IPromise<T1>]): IPromise<[T1]>; }
>T1 : T1
>x : [IPromise<T1>]
>IPromise : IPromise<T>
>T1 : T1
>IPromise : IPromise<T>
>T1 : T1
when<T>(t?: T): IPromise<T>;
>when : <T>(t?: T) => IPromise<T>
>T : T
>t : T
>T : T
>IPromise : IPromise<T>
>T : T
}
interface IPromise<T> {
>IPromise : IPromise<T>
>T : T
then<TResult>(callback: (t: T) => TResult): IPromise<TResult>;
>then : <TResult>(callback: (t: T) => TResult) => IPromise<TResult>
>TResult : TResult
>callback : (t: T) => TResult
>t : T
>T : T
>TResult : TResult
>IPromise : IPromise<T>
>TResult : TResult
}
// Implicit different types
var a = $q.all([$q.when<string>(), $q.when<number>()]);
>a : IPromise<[string, number]>
>$q.all([$q.when<string>(), $q.when<number>()]) : IPromise<[string, number]>
>$q.all : { <T1, T2, T3>(x: [IPromise<T1>, IPromise<T2>, IPromise<T3>]): IPromise<[T1, T2, T3]>; <T1, T2>(x: [IPromise<T1>, IPromise<T2>]): IPromise<[T1, T2]>; <T1>(x: [IPromise<T1>]): IPromise<[T1]>; }
>$q : IQService
>all : { <T1, T2, T3>(x: [IPromise<T1>, IPromise<T2>, IPromise<T3>]): IPromise<[T1, T2, T3]>; <T1, T2>(x: [IPromise<T1>, IPromise<T2>]): IPromise<[T1, T2]>; <T1>(x: [IPromise<T1>]): IPromise<[T1]>; }
>[$q.when<string>(), $q.when<number>()] : [IPromise<string>, IPromise<number>]
>$q.when<string>() : IPromise<string>
>$q.when : <T>(t?: T) => IPromise<T>
>$q : IQService
>when : <T>(t?: T) => IPromise<T>
>$q.when<number>() : IPromise<number>
>$q.when : <T>(t?: T) => IPromise<T>
>$q : IQService
>when : <T>(t?: T) => IPromise<T>
// Explicit different types
var b = $q.all<string, number>([$q.when<string>(), $q.when<number>()]);
>b : IPromise<[string, number]>
>$q.all<string, number>([$q.when<string>(), $q.when<number>()]) : IPromise<[string, number]>
>$q.all : { <T1, T2, T3>(x: [IPromise<T1>, IPromise<T2>, IPromise<T3>]): IPromise<[T1, T2, T3]>; <T1, T2>(x: [IPromise<T1>, IPromise<T2>]): IPromise<[T1, T2]>; <T1>(x: [IPromise<T1>]): IPromise<[T1]>; }
>$q : IQService
>all : { <T1, T2, T3>(x: [IPromise<T1>, IPromise<T2>, IPromise<T3>]): IPromise<[T1, T2, T3]>; <T1, T2>(x: [IPromise<T1>, IPromise<T2>]): IPromise<[T1, T2]>; <T1>(x: [IPromise<T1>]): IPromise<[T1]>; }
>[$q.when<string>(), $q.when<number>()] : [IPromise<string>, IPromise<number>]
>$q.when<string>() : IPromise<string>
>$q.when : <T>(t?: T) => IPromise<T>
>$q : IQService
>when : <T>(t?: T) => IPromise<T>
>$q.when<number>() : IPromise<number>
>$q.when : <T>(t?: T) => IPromise<T>
>$q : IQService
>when : <T>(t?: T) => IPromise<T>
// Implicit identical types
var c = $q.all([$q.when<string>(), $q.when<string>()]);
>c : IPromise<[string, string]>
>$q.all([$q.when<string>(), $q.when<string>()]) : IPromise<[string, string]>
>$q.all : { <T1, T2, T3>(x: [IPromise<T1>, IPromise<T2>, IPromise<T3>]): IPromise<[T1, T2, T3]>; <T1, T2>(x: [IPromise<T1>, IPromise<T2>]): IPromise<[T1, T2]>; <T1>(x: [IPromise<T1>]): IPromise<[T1]>; }
>$q : IQService
>all : { <T1, T2, T3>(x: [IPromise<T1>, IPromise<T2>, IPromise<T3>]): IPromise<[T1, T2, T3]>; <T1, T2>(x: [IPromise<T1>, IPromise<T2>]): IPromise<[T1, T2]>; <T1>(x: [IPromise<T1>]): IPromise<[T1]>; }
>[$q.when<string>(), $q.when<string>()] : [IPromise<string>, IPromise<string>]
>$q.when<string>() : IPromise<string>
>$q.when : <T>(t?: T) => IPromise<T>
>$q : IQService
>when : <T>(t?: T) => IPromise<T>
>$q.when<string>() : IPromise<string>
>$q.when : <T>(t?: T) => IPromise<T>
>$q : IQService
>when : <T>(t?: T) => IPromise<T>

View file

@ -0,0 +1,21 @@
declare var $q: IQService;
interface IQService {
all<T1, T2, T3>(x: [IPromise<T1>, IPromise<T2>, IPromise<T3>]): IPromise<[T1, T2, T3]>;
all<T1, T2>(x: [IPromise<T1>, IPromise<T2>]): IPromise<[T1, T2]>;
all<T1>(x: [IPromise<T1>]): IPromise<[T1]>;
when<T>(t?: T): IPromise<T>;
}
interface IPromise<T> {
then<TResult>(callback: (t: T) => TResult): IPromise<TResult>;
}
// Implicit different types
var a = $q.all([$q.when<string>(), $q.when<number>()]);
// Explicit different types
var b = $q.all<string, number>([$q.when<string>(), $q.when<number>()]);
// Implicit identical types
var c = $q.all([$q.when<string>(), $q.when<string>()]);