From 245f7a8ef4d15b058e08f92049a6b1c50c010d23 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 4 Aug 2015 11:42:58 -0700 Subject: [PATCH 1/2] Add explicit handling of tuple-to-tuple type inference --- src/compiler/checker.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c37189488b..95bd110787 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5732,6 +5732,14 @@ namespace ts { inferFromTypes(sourceTypes[i], targetTypes[i]); } } + else if (source.flags & TypeFlags.Tuple && target.flags & TypeFlags.Tuple && (source).elementTypes.length === (target).elementTypes.length) { + // If source and target are tuples of the same size, infer from element types + let sourceTypes = (source).elementTypes; + let targetTypes = (target).elementTypes; + for (let i = 0; i < sourceTypes.length; i++) { + inferFromTypes(sourceTypes[i], targetTypes[i]); + } + } else if (target.flags & TypeFlags.UnionOrIntersection) { let targetTypes = (target).types; let typeParameterCount = 0; From 81544d4652850955969daf5ea1d1c62b8f8a7510 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 4 Aug 2015 11:43:13 -0700 Subject: [PATCH 2/2] Adding test case --- .../baselines/reference/tupleTypeInference.js | 31 +++++ .../reference/tupleTypeInference.symbols | 110 ++++++++++++++++ .../reference/tupleTypeInference.types | 122 ++++++++++++++++++ tests/cases/compiler/tupleTypeInference.ts | 21 +++ 4 files changed, 284 insertions(+) create mode 100644 tests/baselines/reference/tupleTypeInference.js create mode 100644 tests/baselines/reference/tupleTypeInference.symbols create mode 100644 tests/baselines/reference/tupleTypeInference.types create mode 100644 tests/cases/compiler/tupleTypeInference.ts diff --git a/tests/baselines/reference/tupleTypeInference.js b/tests/baselines/reference/tupleTypeInference.js new file mode 100644 index 0000000000..dfc0de8302 --- /dev/null +++ b/tests/baselines/reference/tupleTypeInference.js @@ -0,0 +1,31 @@ +//// [tupleTypeInference.ts] +declare var $q: IQService; + +interface IQService { + all(x: [IPromise, IPromise, IPromise]): IPromise<[T1, T2, T3]>; + all(x: [IPromise, IPromise]): IPromise<[T1, T2]>; + all(x: [IPromise]): IPromise<[T1]>; + when(t?: T): IPromise; +} + +interface IPromise { + then(callback: (t: T) => TResult): IPromise; +} + +// 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()]); + + +//// [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()]); diff --git a/tests/baselines/reference/tupleTypeInference.symbols b/tests/baselines/reference/tupleTypeInference.symbols new file mode 100644 index 0000000000..4dbed73e39 --- /dev/null +++ b/tests/baselines/reference/tupleTypeInference.symbols @@ -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(x: [IPromise, IPromise, IPromise]): 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(x: [IPromise, IPromise]): 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(x: [IPromise]): 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): IPromise; +>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 { +>IPromise : Symbol(IPromise, Decl(tupleTypeInference.ts, 7, 1)) +>T : Symbol(T, Decl(tupleTypeInference.ts, 9, 19)) + + then(callback: (t: T) => TResult): IPromise; +>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(), $q.when()]); +>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([$q.when(), $q.when()]); +>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(), $q.when()]); +>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)) + diff --git a/tests/baselines/reference/tupleTypeInference.types b/tests/baselines/reference/tupleTypeInference.types new file mode 100644 index 0000000000..999574a78e --- /dev/null +++ b/tests/baselines/reference/tupleTypeInference.types @@ -0,0 +1,122 @@ +=== tests/cases/compiler/tupleTypeInference.ts === +declare var $q: IQService; +>$q : IQService +>IQService : IQService + +interface IQService { +>IQService : IQService + + all(x: [IPromise, IPromise, IPromise]): IPromise<[T1, T2, T3]>; +>all : { (x: [IPromise, IPromise, IPromise]): IPromise<[T1, T2, T3]>; (x: [IPromise, IPromise]): IPromise<[T1, T2]>; (x: [IPromise]): IPromise<[T1]>; } +>T1 : T1 +>T2 : T2 +>T3 : T3 +>x : [IPromise, IPromise, IPromise] +>IPromise : IPromise +>T1 : T1 +>IPromise : IPromise +>T2 : T2 +>IPromise : IPromise +>T3 : T3 +>IPromise : IPromise +>T1 : T1 +>T2 : T2 +>T3 : T3 + + all(x: [IPromise, IPromise]): IPromise<[T1, T2]>; +>all : { (x: [IPromise, IPromise, IPromise]): IPromise<[T1, T2, T3]>; (x: [IPromise, IPromise]): IPromise<[T1, T2]>; (x: [IPromise]): IPromise<[T1]>; } +>T1 : T1 +>T2 : T2 +>x : [IPromise, IPromise] +>IPromise : IPromise +>T1 : T1 +>IPromise : IPromise +>T2 : T2 +>IPromise : IPromise +>T1 : T1 +>T2 : T2 + + all(x: [IPromise]): IPromise<[T1]>; +>all : { (x: [IPromise, IPromise, IPromise]): IPromise<[T1, T2, T3]>; (x: [IPromise, IPromise]): IPromise<[T1, T2]>; (x: [IPromise]): IPromise<[T1]>; } +>T1 : T1 +>x : [IPromise] +>IPromise : IPromise +>T1 : T1 +>IPromise : IPromise +>T1 : T1 + + when(t?: T): IPromise; +>when : (t?: T) => IPromise +>T : T +>t : T +>T : T +>IPromise : IPromise +>T : T +} + +interface IPromise { +>IPromise : IPromise +>T : T + + then(callback: (t: T) => TResult): IPromise; +>then : (callback: (t: T) => TResult) => IPromise +>TResult : TResult +>callback : (t: T) => TResult +>t : T +>T : T +>TResult : TResult +>IPromise : IPromise +>TResult : TResult +} + +// Implicit different types +var a = $q.all([$q.when(), $q.when()]); +>a : IPromise<[string, number]> +>$q.all([$q.when(), $q.when()]) : IPromise<[string, number]> +>$q.all : { (x: [IPromise, IPromise, IPromise]): IPromise<[T1, T2, T3]>; (x: [IPromise, IPromise]): IPromise<[T1, T2]>; (x: [IPromise]): IPromise<[T1]>; } +>$q : IQService +>all : { (x: [IPromise, IPromise, IPromise]): IPromise<[T1, T2, T3]>; (x: [IPromise, IPromise]): IPromise<[T1, T2]>; (x: [IPromise]): IPromise<[T1]>; } +>[$q.when(), $q.when()] : [IPromise, IPromise] +>$q.when() : IPromise +>$q.when : (t?: T) => IPromise +>$q : IQService +>when : (t?: T) => IPromise +>$q.when() : IPromise +>$q.when : (t?: T) => IPromise +>$q : IQService +>when : (t?: T) => IPromise + +// Explicit different types +var b = $q.all([$q.when(), $q.when()]); +>b : IPromise<[string, number]> +>$q.all([$q.when(), $q.when()]) : IPromise<[string, number]> +>$q.all : { (x: [IPromise, IPromise, IPromise]): IPromise<[T1, T2, T3]>; (x: [IPromise, IPromise]): IPromise<[T1, T2]>; (x: [IPromise]): IPromise<[T1]>; } +>$q : IQService +>all : { (x: [IPromise, IPromise, IPromise]): IPromise<[T1, T2, T3]>; (x: [IPromise, IPromise]): IPromise<[T1, T2]>; (x: [IPromise]): IPromise<[T1]>; } +>[$q.when(), $q.when()] : [IPromise, IPromise] +>$q.when() : IPromise +>$q.when : (t?: T) => IPromise +>$q : IQService +>when : (t?: T) => IPromise +>$q.when() : IPromise +>$q.when : (t?: T) => IPromise +>$q : IQService +>when : (t?: T) => IPromise + +// Implicit identical types +var c = $q.all([$q.when(), $q.when()]); +>c : IPromise<[string, string]> +>$q.all([$q.when(), $q.when()]) : IPromise<[string, string]> +>$q.all : { (x: [IPromise, IPromise, IPromise]): IPromise<[T1, T2, T3]>; (x: [IPromise, IPromise]): IPromise<[T1, T2]>; (x: [IPromise]): IPromise<[T1]>; } +>$q : IQService +>all : { (x: [IPromise, IPromise, IPromise]): IPromise<[T1, T2, T3]>; (x: [IPromise, IPromise]): IPromise<[T1, T2]>; (x: [IPromise]): IPromise<[T1]>; } +>[$q.when(), $q.when()] : [IPromise, IPromise] +>$q.when() : IPromise +>$q.when : (t?: T) => IPromise +>$q : IQService +>when : (t?: T) => IPromise +>$q.when() : IPromise +>$q.when : (t?: T) => IPromise +>$q : IQService +>when : (t?: T) => IPromise + diff --git a/tests/cases/compiler/tupleTypeInference.ts b/tests/cases/compiler/tupleTypeInference.ts new file mode 100644 index 0000000000..7c5a49d3ca --- /dev/null +++ b/tests/cases/compiler/tupleTypeInference.ts @@ -0,0 +1,21 @@ +declare var $q: IQService; + +interface IQService { + all(x: [IPromise, IPromise, IPromise]): IPromise<[T1, T2, T3]>; + all(x: [IPromise, IPromise]): IPromise<[T1, T2]>; + all(x: [IPromise]): IPromise<[T1]>; + when(t?: T): IPromise; +} + +interface IPromise { + then(callback: (t: T) => TResult): IPromise; +} + +// 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()]);