mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-24 02:21:30 -05:00
Merge pull request #908 from Microsoft/contextualSignatureUnionTypes
Union types in contextual signature instantiations
This commit is contained in:
@@ -3758,11 +3758,12 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
function createInferenceContext(typeParameters: TypeParameter[]): InferenceContext {
|
||||
function createInferenceContext(typeParameters: TypeParameter[], inferUnionTypes: boolean): InferenceContext {
|
||||
var inferences: Type[][] = [];
|
||||
for (var i = 0; i < typeParameters.length; i++) inferences.push([]);
|
||||
return {
|
||||
typeParameters: typeParameters,
|
||||
inferUnionTypes: inferUnionTypes,
|
||||
inferenceCount: 0,
|
||||
inferences: inferences,
|
||||
inferredTypes: new Array(typeParameters.length),
|
||||
@@ -3909,10 +3910,9 @@ module ts {
|
||||
if (!result) {
|
||||
var inferences = context.inferences[index];
|
||||
if (inferences.length) {
|
||||
// Find type that is supertype of all others
|
||||
var supertype = getCommonSupertype(inferences);
|
||||
// Infer widened supertype, or the undefined type for no common supertype
|
||||
var inferredType = supertype ? getWidenedType(supertype) : undefinedType;
|
||||
// Infer widened union or supertype, or the undefined type for no common supertype
|
||||
var unionOrSuperType = context.inferUnionTypes ? getUnionType(inferences) : getCommonSupertype(inferences);
|
||||
var inferredType = unionOrSuperType ? getWidenedType(unionOrSuperType) : undefinedType;
|
||||
}
|
||||
else {
|
||||
// Infer the empty object type when no inferences were made
|
||||
@@ -4976,7 +4976,7 @@ module ts {
|
||||
|
||||
// Instantiate a generic signature in the context of a non-generic signature (section 3.8.5 in TypeScript spec)
|
||||
function instantiateSignatureInContextOf(signature: Signature, contextualSignature: Signature, contextualMapper: TypeMapper): Signature {
|
||||
var context = createInferenceContext(signature.typeParameters);
|
||||
var context = createInferenceContext(signature.typeParameters, /*inferUnionTypes*/ true);
|
||||
forEachMatchingParameterType(contextualSignature, signature, (source, target) => {
|
||||
// Type parameters from outer context referenced by source type are fixed by instantiation of the source type
|
||||
inferTypes(context, instantiateType(source, contextualMapper), target);
|
||||
@@ -4986,7 +4986,7 @@ module ts {
|
||||
|
||||
function inferTypeArguments(signature: Signature, args: Expression[], excludeArgument?: boolean[]): Type[] {
|
||||
var typeParameters = signature.typeParameters;
|
||||
var context = createInferenceContext(typeParameters);
|
||||
var context = createInferenceContext(typeParameters, /*inferUnionTypes*/ false);
|
||||
var mapper = createInferenceMapper(context);
|
||||
// First infer from arguments that are not context sensitive
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
|
||||
@@ -1010,6 +1010,7 @@ module ts {
|
||||
|
||||
export interface InferenceContext {
|
||||
typeParameters: TypeParameter[]; // Type parameters for which inferences are made
|
||||
inferUnionTypes: boolean; // Infer union types for disjoint candidates (otherwise undefinedType)
|
||||
inferenceCount: number; // Incremented for every inference made (whether new or not)
|
||||
inferences: Type[][]; // Inferences made for each type parameter
|
||||
inferredTypes: Type[]; // Inferred type for each type parameter
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
//// [contextualSignatureInstantiation.ts]
|
||||
// TypeScript Spec, section 4.12.2:
|
||||
// If e is an expression of a function type that contains exactly one generic call signature and no other members,
|
||||
// and T is a function type with exactly one non - generic call signature and no other members, then any inferences
|
||||
// made for type parameters referenced by the parameters of T's call signature are fixed, and e's type is changed
|
||||
// to a function type with e's call signature instantiated in the context of T's call signature (section 3.8.5).
|
||||
|
||||
declare function foo<T>(cb: (x: number, y: string) => T): T;
|
||||
declare function bar<T, U, V>(x: T, y: U, cb: (x: T, y: U) => V): V;
|
||||
declare function baz<T, U>(x: T, y: T, cb: (x: T, y: T) => U): U;
|
||||
|
||||
declare function g<T>(x: T, y: T): T;
|
||||
declare function h<T, U>(x: T, y: U): T[] | U[];
|
||||
|
||||
var a: number;
|
||||
var a = bar(1, 1, g); // Should be number
|
||||
var a = baz(1, 1, g); // Should be number
|
||||
|
||||
var b: number | string;
|
||||
var b = foo(g); // Should be number | string
|
||||
var b = bar(1, "one", g); // Should be number | string
|
||||
var b = bar("one", 1, g); // Should be number | string
|
||||
var b = baz(b, b, g); // Should be number | string
|
||||
|
||||
var d: number[] | string[];
|
||||
var d = foo(h); // Should be number[] | string[]
|
||||
var d = bar(1, "one", h); // Should be number[] | string[]
|
||||
var d = bar("one", 1, h); // Should be number[] | string[]
|
||||
var d = baz(d, d, g); // Should be number[] | string[]
|
||||
|
||||
|
||||
//// [contextualSignatureInstantiation.js]
|
||||
// TypeScript Spec, section 4.12.2:
|
||||
// If e is an expression of a function type that contains exactly one generic call signature and no other members,
|
||||
// and T is a function type with exactly one non - generic call signature and no other members, then any inferences
|
||||
// made for type parameters referenced by the parameters of T's call signature are fixed, and e's type is changed
|
||||
// to a function type with e's call signature instantiated in the context of T's call signature (section 3.8.5).
|
||||
var a;
|
||||
var a = bar(1, 1, g); // Should be number
|
||||
var a = baz(1, 1, g); // Should be number
|
||||
var b;
|
||||
var b = foo(g); // Should be number | string
|
||||
var b = bar(1, "one", g); // Should be number | string
|
||||
var b = bar("one", 1, g); // Should be number | string
|
||||
var b = baz(b, b, g); // Should be number | string
|
||||
var d;
|
||||
var d = foo(h); // Should be number[] | string[]
|
||||
var d = bar(1, "one", h); // Should be number[] | string[]
|
||||
var d = bar("one", 1, h); // Should be number[] | string[]
|
||||
var d = baz(d, d, g); // Should be number[] | string[]
|
||||
142
tests/baselines/reference/contextualSignatureInstantiation.types
Normal file
142
tests/baselines/reference/contextualSignatureInstantiation.types
Normal file
@@ -0,0 +1,142 @@
|
||||
=== tests/cases/conformance/types/typeRelationships/typeInference/contextualSignatureInstantiation.ts ===
|
||||
// TypeScript Spec, section 4.12.2:
|
||||
// If e is an expression of a function type that contains exactly one generic call signature and no other members,
|
||||
// and T is a function type with exactly one non - generic call signature and no other members, then any inferences
|
||||
// made for type parameters referenced by the parameters of T's call signature are fixed, and e's type is changed
|
||||
// to a function type with e's call signature instantiated in the context of T's call signature (section 3.8.5).
|
||||
|
||||
declare function foo<T>(cb: (x: number, y: string) => T): T;
|
||||
>foo : <T>(cb: (x: number, y: string) => T) => T
|
||||
>T : T
|
||||
>cb : (x: number, y: string) => T
|
||||
>x : number
|
||||
>y : string
|
||||
>T : T
|
||||
>T : T
|
||||
|
||||
declare function bar<T, U, V>(x: T, y: U, cb: (x: T, y: U) => V): V;
|
||||
>bar : <T, U, V>(x: T, y: U, cb: (x: T, y: U) => V) => V
|
||||
>T : T
|
||||
>U : U
|
||||
>V : V
|
||||
>x : T
|
||||
>T : T
|
||||
>y : U
|
||||
>U : U
|
||||
>cb : (x: T, y: U) => V
|
||||
>x : T
|
||||
>T : T
|
||||
>y : U
|
||||
>U : U
|
||||
>V : V
|
||||
>V : V
|
||||
|
||||
declare function baz<T, U>(x: T, y: T, cb: (x: T, y: T) => U): U;
|
||||
>baz : <T, U>(x: T, y: T, cb: (x: T, y: T) => U) => U
|
||||
>T : T
|
||||
>U : U
|
||||
>x : T
|
||||
>T : T
|
||||
>y : T
|
||||
>T : T
|
||||
>cb : (x: T, y: T) => U
|
||||
>x : T
|
||||
>T : T
|
||||
>y : T
|
||||
>T : T
|
||||
>U : U
|
||||
>U : U
|
||||
|
||||
declare function g<T>(x: T, y: T): T;
|
||||
>g : <T>(x: T, y: T) => T
|
||||
>T : T
|
||||
>x : T
|
||||
>T : T
|
||||
>y : T
|
||||
>T : T
|
||||
>T : T
|
||||
|
||||
declare function h<T, U>(x: T, y: U): T[] | U[];
|
||||
>h : <T, U>(x: T, y: U) => T[] | U[]
|
||||
>T : T
|
||||
>U : U
|
||||
>x : T
|
||||
>T : T
|
||||
>y : U
|
||||
>U : U
|
||||
>T : T
|
||||
>U : U
|
||||
|
||||
var a: number;
|
||||
>a : number
|
||||
|
||||
var a = bar(1, 1, g); // Should be number
|
||||
>a : number
|
||||
>bar(1, 1, g) : number
|
||||
>bar : <T, U, V>(x: T, y: U, cb: (x: T, y: U) => V) => V
|
||||
>g : <T>(x: T, y: T) => T
|
||||
|
||||
var a = baz(1, 1, g); // Should be number
|
||||
>a : number
|
||||
>baz(1, 1, g) : number
|
||||
>baz : <T, U>(x: T, y: T, cb: (x: T, y: T) => U) => U
|
||||
>g : <T>(x: T, y: T) => T
|
||||
|
||||
var b: number | string;
|
||||
>b : string | number
|
||||
|
||||
var b = foo(g); // Should be number | string
|
||||
>b : string | number
|
||||
>foo(g) : string | number
|
||||
>foo : <T>(cb: (x: number, y: string) => T) => T
|
||||
>g : <T>(x: T, y: T) => T
|
||||
|
||||
var b = bar(1, "one", g); // Should be number | string
|
||||
>b : string | number
|
||||
>bar(1, "one", g) : string | number
|
||||
>bar : <T, U, V>(x: T, y: U, cb: (x: T, y: U) => V) => V
|
||||
>g : <T>(x: T, y: T) => T
|
||||
|
||||
var b = bar("one", 1, g); // Should be number | string
|
||||
>b : string | number
|
||||
>bar("one", 1, g) : string | number
|
||||
>bar : <T, U, V>(x: T, y: U, cb: (x: T, y: U) => V) => V
|
||||
>g : <T>(x: T, y: T) => T
|
||||
|
||||
var b = baz(b, b, g); // Should be number | string
|
||||
>b : string | number
|
||||
>baz(b, b, g) : string | number
|
||||
>baz : <T, U>(x: T, y: T, cb: (x: T, y: T) => U) => U
|
||||
>b : string | number
|
||||
>b : string | number
|
||||
>g : <T>(x: T, y: T) => T
|
||||
|
||||
var d: number[] | string[];
|
||||
>d : string[] | number[]
|
||||
|
||||
var d = foo(h); // Should be number[] | string[]
|
||||
>d : string[] | number[]
|
||||
>foo(h) : string[] | number[]
|
||||
>foo : <T>(cb: (x: number, y: string) => T) => T
|
||||
>h : <T, U>(x: T, y: U) => T[] | U[]
|
||||
|
||||
var d = bar(1, "one", h); // Should be number[] | string[]
|
||||
>d : string[] | number[]
|
||||
>bar(1, "one", h) : string[] | number[]
|
||||
>bar : <T, U, V>(x: T, y: U, cb: (x: T, y: U) => V) => V
|
||||
>h : <T, U>(x: T, y: U) => T[] | U[]
|
||||
|
||||
var d = bar("one", 1, h); // Should be number[] | string[]
|
||||
>d : string[] | number[]
|
||||
>bar("one", 1, h) : string[] | number[]
|
||||
>bar : <T, U, V>(x: T, y: U, cb: (x: T, y: U) => V) => V
|
||||
>h : <T, U>(x: T, y: U) => T[] | U[]
|
||||
|
||||
var d = baz(d, d, g); // Should be number[] | string[]
|
||||
>d : string[] | number[]
|
||||
>baz(d, d, g) : string[] | number[]
|
||||
>baz : <T, U>(x: T, y: T, cb: (x: T, y: T) => U) => U
|
||||
>d : string[] | number[]
|
||||
>d : string[] | number[]
|
||||
>g : <T>(x: T, y: T) => T
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
// TypeScript Spec, section 4.12.2:
|
||||
// If e is an expression of a function type that contains exactly one generic call signature and no other members,
|
||||
// and T is a function type with exactly one non - generic call signature and no other members, then any inferences
|
||||
// made for type parameters referenced by the parameters of T's call signature are fixed, and e's type is changed
|
||||
// to a function type with e's call signature instantiated in the context of T's call signature (section 3.8.5).
|
||||
|
||||
declare function foo<T>(cb: (x: number, y: string) => T): T;
|
||||
declare function bar<T, U, V>(x: T, y: U, cb: (x: T, y: U) => V): V;
|
||||
declare function baz<T, U>(x: T, y: T, cb: (x: T, y: T) => U): U;
|
||||
|
||||
declare function g<T>(x: T, y: T): T;
|
||||
declare function h<T, U>(x: T, y: U): T[] | U[];
|
||||
|
||||
var a: number;
|
||||
var a = bar(1, 1, g); // Should be number
|
||||
var a = baz(1, 1, g); // Should be number
|
||||
|
||||
var b: number | string;
|
||||
var b = foo(g); // Should be number | string
|
||||
var b = bar(1, "one", g); // Should be number | string
|
||||
var b = bar("one", 1, g); // Should be number | string
|
||||
var b = baz(b, b, g); // Should be number | string
|
||||
|
||||
var d: number[] | string[];
|
||||
var d = foo(h); // Should be number[] | string[]
|
||||
var d = bar(1, "one", h); // Should be number[] | string[]
|
||||
var d = bar("one", 1, h); // Should be number[] | string[]
|
||||
var d = baz(d, d, g); // Should be number[] | string[]
|
||||
Reference in New Issue
Block a user