Merge pull request #3787 from Microsoft/fixingTypeParameters

Fix type parameters upon subsequent visits to a parameter that caused fixing the first time
This commit is contained in:
Jason Freeman 2015-07-17 16:05:28 -07:00
commit 2c5ba08266
15 changed files with 512 additions and 33 deletions

View file

@ -4249,15 +4249,18 @@ namespace ts {
}
function createInferenceMapper(context: InferenceContext): TypeMapper {
return t => {
let mapper: TypeMapper = t => {
for (let i = 0; i < context.typeParameters.length; i++) {
if (t === context.typeParameters[i]) {
context.inferences[i].isFixed = true;
return getInferredType(context, i);
}
}
return t;
return t;
};
mapper.context = context;
return mapper;
}
function identityMapper(type: Type): Type {
@ -5468,7 +5471,9 @@ namespace ts {
function createInferenceContext(typeParameters: TypeParameter[], inferUnionTypes: boolean): InferenceContext {
let inferences: TypeInferences[] = [];
for (let unused of typeParameters) {
inferences.push({ primary: undefined, secondary: undefined, isFixed: false });
inferences.push({
primary: undefined, secondary: undefined, isFixed: false
});
}
return {
typeParameters,
@ -6769,10 +6774,23 @@ namespace ts {
return result;
}
// Presence of a contextual type mapper indicates inferential typing, except the identityMapper object is
// used as a special marker for other purposes.
/**
* Detect if the mapper implies an inference context. Specifically, there are 4 possible values
* for a mapper. Let's go through each one of them:
*
* 1. undefined - this means we are not doing inferential typing, but we may do contextual typing,
* which could cause us to assign a parameter a type
* 2. identityMapper - means we want to avoid assigning a parameter a type, whether or not we are in
* inferential typing (context is undefined for the identityMapper)
* 3. a mapper created by createInferenceMapper - we are doing inferential typing, we want to assign
* types to parameters and fix type parameters (context is defined)
* 4. an instantiation mapper created by createTypeMapper or createTypeEraser - this should never be
* passed as the contextual mapper when checking an expression (context is undefined for these)
*
* isInferentialContext is detecting if we are in case 3
*/
function isInferentialContext(mapper: TypeMapper) {
return mapper && mapper !== identityMapper;
return mapper && mapper.context;
}
// A node is an assignment target if it is on the left hand side of an '=' token, if it is parented by a property
@ -8861,13 +8879,52 @@ namespace ts {
let len = signature.parameters.length - (signature.hasRestParameter ? 1 : 0);
for (let i = 0; i < len; i++) {
let parameter = signature.parameters[i];
let links = getSymbolLinks(parameter);
links.type = instantiateType(getTypeAtPosition(context, i), mapper);
let contextualParameterType = getTypeAtPosition(context, i);
assignTypeToParameterAndFixTypeParameters(parameter, contextualParameterType, mapper);
}
if (signature.hasRestParameter && context.hasRestParameter && signature.parameters.length >= context.parameters.length) {
let parameter = lastOrUndefined(signature.parameters);
let links = getSymbolLinks(parameter);
links.type = instantiateType(getTypeOfSymbol(lastOrUndefined(context.parameters)), mapper);
let contextualParameterType = getTypeOfSymbol(lastOrUndefined(context.parameters));
assignTypeToParameterAndFixTypeParameters(parameter, contextualParameterType, mapper);
}
}
function assignTypeToParameterAndFixTypeParameters(parameter: Symbol, contextualType: Type, mapper: TypeMapper) {
let links = getSymbolLinks(parameter);
if (!links.type) {
links.type = instantiateType(contextualType, mapper);
}
else if (isInferentialContext(mapper)) {
// Even if the parameter already has a type, it might be because it was given a type while
// processing the function as an argument to a prior signature during overload resolution.
// If this was the case, it may have caused some type parameters to be fixed. So here,
// we need to ensure that type parameters at the same positions get fixed again. This is
// done by calling instantiateType to attach the mapper to the contextualType, and then
// calling inferTypes to force a walk of contextualType so that all the correct fixing
// happens. The choice to pass in links.type may seem kind of arbitrary, but it serves
// to make sure that all the correct positions in contextualType are reached by the walk.
// Here is an example:
//
// interface Base {
// baseProp;
// }
// interface Derived extends Base {
// toBase(): Base;
// }
//
// var derived: Derived;
//
// declare function foo<T>(x: T, func: (p: T) => T): T;
// declare function foo<T>(x: T, func: (p: T) => T): T;
//
// var result = foo(derived, d => d.toBase());
//
// We are typing d while checking the second overload. But we've already given d
// a type (Derived) from the first overload. However, we still want to fix the
// T in the second overload so that we do not infer Base as a candidate for T
// (inferring Base would make type argument inference inconsistent between the two
// overloads).
inferTypes(mapper.context, links.type, instantiateType(contextualType, mapper));
}
}
@ -9087,27 +9144,36 @@ namespace ts {
let links = getNodeLinks(node);
let type = getTypeOfSymbol(node.symbol);
// Check if function expression is contextually typed and assign parameter types if so
if (!(links.flags & NodeCheckFlags.ContextChecked)) {
let contextSensitive = isContextSensitive(node);
let mightFixTypeParameters = contextSensitive && isInferentialContext(contextualMapper);
// Check if function expression is contextually typed and assign parameter types if so.
// See the comment in assignTypeToParameterAndFixTypeParameters to understand why we need to
// check mightFixTypeParameters.
if (mightFixTypeParameters || !(links.flags & NodeCheckFlags.ContextChecked)) {
let contextualSignature = getContextualSignature(node);
// If a type check is started at a function expression that is an argument of a function call, obtaining the
// contextual type may recursively get back to here during overload resolution of the call. If so, we will have
// already assigned contextual types.
if (!(links.flags & NodeCheckFlags.ContextChecked)) {
let contextChecked = !!(links.flags & NodeCheckFlags.ContextChecked);
if (mightFixTypeParameters || !contextChecked) {
links.flags |= NodeCheckFlags.ContextChecked;
if (contextualSignature) {
let signature = getSignaturesOfType(type, SignatureKind.Call)[0];
if (isContextSensitive(node)) {
if (contextSensitive) {
assignContextualParameterTypes(signature, contextualSignature, contextualMapper || identityMapper);
}
if (!node.type && !signature.resolvedReturnType) {
if (mightFixTypeParameters || !node.type && !signature.resolvedReturnType) {
let returnType = getReturnTypeFromBody(node, contextualMapper);
if (!signature.resolvedReturnType) {
signature.resolvedReturnType = returnType;
}
}
}
checkSignatureDeclaration(node);
if (!contextChecked) {
checkSignatureDeclaration(node);
}
}
}
@ -9797,7 +9863,7 @@ namespace ts {
}
function instantiateTypeWithSingleGenericCallSignature(node: Expression | MethodDeclaration, type: Type, contextualMapper?: TypeMapper) {
if (contextualMapper && contextualMapper !== identityMapper) {
if (isInferentialContext(contextualMapper)) {
let signature = getSingleCallSignature(type);
if (signature && signature.typeParameters) {
let contextualType = getContextualType(<Expression>node);

View file

@ -1912,6 +1912,9 @@ namespace ts {
/* @internal */
export interface TypeMapper {
(t: TypeParameter): Type;
context?: InferenceContext; // The inference context this mapper was created from.
// Only inference mappers have this set (in createInferenceMapper).
// The identity mapper and regular instantiation mappers do not need it.
}
/* @internal */

View file

@ -0,0 +1,12 @@
//// [fixingTypeParametersRepeatedly1.ts]
declare function f<T>(x: T, y: (p: T) => T, z: (p: T) => T): T;
f("", x => null, x => x.toLowerCase());
// First overload of g should type check just like f
declare function g<T>(x: T, y: (p: T) => T, z: (p: T) => T): T;
declare function g();
g("", x => null, x => x.toLowerCase());
//// [fixingTypeParametersRepeatedly1.js]
f("", function (x) { return null; }, function (x) { return x.toLowerCase(); });
g("", function (x) { return null; }, function (x) { return x.toLowerCase(); });

View file

@ -0,0 +1,51 @@
=== tests/cases/compiler/fixingTypeParametersRepeatedly1.ts ===
declare function f<T>(x: T, y: (p: T) => T, z: (p: T) => T): T;
>f : Symbol(f, Decl(fixingTypeParametersRepeatedly1.ts, 0, 0))
>T : Symbol(T, Decl(fixingTypeParametersRepeatedly1.ts, 0, 19))
>x : Symbol(x, Decl(fixingTypeParametersRepeatedly1.ts, 0, 22))
>T : Symbol(T, Decl(fixingTypeParametersRepeatedly1.ts, 0, 19))
>y : Symbol(y, Decl(fixingTypeParametersRepeatedly1.ts, 0, 27))
>p : Symbol(p, Decl(fixingTypeParametersRepeatedly1.ts, 0, 32))
>T : Symbol(T, Decl(fixingTypeParametersRepeatedly1.ts, 0, 19))
>T : Symbol(T, Decl(fixingTypeParametersRepeatedly1.ts, 0, 19))
>z : Symbol(z, Decl(fixingTypeParametersRepeatedly1.ts, 0, 43))
>p : Symbol(p, Decl(fixingTypeParametersRepeatedly1.ts, 0, 48))
>T : Symbol(T, Decl(fixingTypeParametersRepeatedly1.ts, 0, 19))
>T : Symbol(T, Decl(fixingTypeParametersRepeatedly1.ts, 0, 19))
>T : Symbol(T, Decl(fixingTypeParametersRepeatedly1.ts, 0, 19))
f("", x => null, x => x.toLowerCase());
>f : Symbol(f, Decl(fixingTypeParametersRepeatedly1.ts, 0, 0))
>x : Symbol(x, Decl(fixingTypeParametersRepeatedly1.ts, 1, 5))
>x : Symbol(x, Decl(fixingTypeParametersRepeatedly1.ts, 1, 16))
>x.toLowerCase : Symbol(String.toLowerCase, Decl(lib.d.ts, 399, 51))
>x : Symbol(x, Decl(fixingTypeParametersRepeatedly1.ts, 1, 16))
>toLowerCase : Symbol(String.toLowerCase, Decl(lib.d.ts, 399, 51))
// First overload of g should type check just like f
declare function g<T>(x: T, y: (p: T) => T, z: (p: T) => T): T;
>g : Symbol(g, Decl(fixingTypeParametersRepeatedly1.ts, 1, 39), Decl(fixingTypeParametersRepeatedly1.ts, 4, 63))
>T : Symbol(T, Decl(fixingTypeParametersRepeatedly1.ts, 4, 19))
>x : Symbol(x, Decl(fixingTypeParametersRepeatedly1.ts, 4, 22))
>T : Symbol(T, Decl(fixingTypeParametersRepeatedly1.ts, 4, 19))
>y : Symbol(y, Decl(fixingTypeParametersRepeatedly1.ts, 4, 27))
>p : Symbol(p, Decl(fixingTypeParametersRepeatedly1.ts, 4, 32))
>T : Symbol(T, Decl(fixingTypeParametersRepeatedly1.ts, 4, 19))
>T : Symbol(T, Decl(fixingTypeParametersRepeatedly1.ts, 4, 19))
>z : Symbol(z, Decl(fixingTypeParametersRepeatedly1.ts, 4, 43))
>p : Symbol(p, Decl(fixingTypeParametersRepeatedly1.ts, 4, 48))
>T : Symbol(T, Decl(fixingTypeParametersRepeatedly1.ts, 4, 19))
>T : Symbol(T, Decl(fixingTypeParametersRepeatedly1.ts, 4, 19))
>T : Symbol(T, Decl(fixingTypeParametersRepeatedly1.ts, 4, 19))
declare function g();
>g : Symbol(g, Decl(fixingTypeParametersRepeatedly1.ts, 1, 39), Decl(fixingTypeParametersRepeatedly1.ts, 4, 63))
g("", x => null, x => x.toLowerCase());
>g : Symbol(g, Decl(fixingTypeParametersRepeatedly1.ts, 1, 39), Decl(fixingTypeParametersRepeatedly1.ts, 4, 63))
>x : Symbol(x, Decl(fixingTypeParametersRepeatedly1.ts, 6, 5))
>x : Symbol(x, Decl(fixingTypeParametersRepeatedly1.ts, 6, 16))
>x.toLowerCase : Symbol(String.toLowerCase, Decl(lib.d.ts, 399, 51))
>x : Symbol(x, Decl(fixingTypeParametersRepeatedly1.ts, 6, 16))
>toLowerCase : Symbol(String.toLowerCase, Decl(lib.d.ts, 399, 51))

View file

@ -0,0 +1,63 @@
=== tests/cases/compiler/fixingTypeParametersRepeatedly1.ts ===
declare function f<T>(x: T, y: (p: T) => T, z: (p: T) => T): T;
>f : <T>(x: T, y: (p: T) => T, z: (p: T) => T) => T
>T : T
>x : T
>T : T
>y : (p: T) => T
>p : T
>T : T
>T : T
>z : (p: T) => T
>p : T
>T : T
>T : T
>T : T
f("", x => null, x => x.toLowerCase());
>f("", x => null, x => x.toLowerCase()) : string
>f : <T>(x: T, y: (p: T) => T, z: (p: T) => T) => T
>"" : string
>x => null : (x: string) => any
>x : string
>null : null
>x => x.toLowerCase() : (x: string) => string
>x : string
>x.toLowerCase() : string
>x.toLowerCase : () => string
>x : string
>toLowerCase : () => string
// First overload of g should type check just like f
declare function g<T>(x: T, y: (p: T) => T, z: (p: T) => T): T;
>g : { <T>(x: T, y: (p: T) => T, z: (p: T) => T): T; (): any; }
>T : T
>x : T
>T : T
>y : (p: T) => T
>p : T
>T : T
>T : T
>z : (p: T) => T
>p : T
>T : T
>T : T
>T : T
declare function g();
>g : { <T>(x: T, y: (p: T) => T, z: (p: T) => T): T; (): any; }
g("", x => null, x => x.toLowerCase());
>g("", x => null, x => x.toLowerCase()) : string
>g : { <T>(x: T, y: (p: T) => T, z: (p: T) => T): T; (): any; }
>"" : string
>x => null : (x: string) => any
>x : string
>null : null
>x => x.toLowerCase() : (x: string) => string
>x : string
>x.toLowerCase() : string
>x.toLowerCase : () => string
>x : string
>toLowerCase : () => string

View file

@ -0,0 +1,32 @@
tests/cases/compiler/fixingTypeParametersRepeatedly2.ts(11,27): error TS2345: Argument of type '(d: Derived) => Base' is not assignable to parameter of type '(p: Derived) => Derived'.
Type 'Base' is not assignable to type 'Derived'.
Property 'toBase' is missing in type 'Base'.
tests/cases/compiler/fixingTypeParametersRepeatedly2.ts(17,27): error TS2345: Argument of type '(d: Derived) => Base' is not assignable to parameter of type '(p: Derived) => Derived'.
Type 'Base' is not assignable to type 'Derived'.
==== tests/cases/compiler/fixingTypeParametersRepeatedly2.ts (2 errors) ====
interface Base {
baseProp;
}
interface Derived extends Base {
toBase(): Base;
}
var derived: Derived;
declare function foo<T>(x: T, func: (p: T) => T): T;
var result = foo(derived, d => d.toBase());
~~~~~~~~~~~~~~~
!!! error TS2345: Argument of type '(d: Derived) => Base' is not assignable to parameter of type '(p: Derived) => Derived'.
!!! error TS2345: Type 'Base' is not assignable to type 'Derived'.
!!! error TS2345: Property 'toBase' is missing in type 'Base'.
// bar should type check just like foo.
// The same error should be observed in both cases.
declare function bar<T>(x: T, func: (p: T) => T): T;
declare function bar<T>(x: T, func: (p: T) => T): T;
var result = bar(derived, d => d.toBase());
~~~~~~~~~~~~~~~
!!! error TS2345: Argument of type '(d: Derived) => Base' is not assignable to parameter of type '(p: Derived) => Derived'.
!!! error TS2345: Type 'Base' is not assignable to type 'Derived'.

View file

@ -0,0 +1,23 @@
//// [fixingTypeParametersRepeatedly2.ts]
interface Base {
baseProp;
}
interface Derived extends Base {
toBase(): Base;
}
var derived: Derived;
declare function foo<T>(x: T, func: (p: T) => T): T;
var result = foo(derived, d => d.toBase());
// bar should type check just like foo.
// The same error should be observed in both cases.
declare function bar<T>(x: T, func: (p: T) => T): T;
declare function bar<T>(x: T, func: (p: T) => T): T;
var result = bar(derived, d => d.toBase());
//// [fixingTypeParametersRepeatedly2.js]
var derived;
var result = foo(derived, function (d) { return d.toBase(); });
var result = bar(derived, function (d) { return d.toBase(); });

View file

@ -0,0 +1,23 @@
//// [fixingTypeParametersRepeatedly3.ts]
interface Base {
baseProp;
}
interface Derived extends Base {
toBase?(): Base;
}
var derived: Derived;
declare function foo<T>(x: T, func: (p: T) => T): T;
var result = foo(derived, d => d.toBase());
// bar should type check just like foo.
// result2 should have the same type as result
declare function bar<T>(x: T, func: (p: T) => T): T;
declare function bar<T>(x: T, func: (p: T) => T): T;
var result2 = bar(derived, d => d.toBase());
//// [fixingTypeParametersRepeatedly3.js]
var derived;
var result = foo(derived, function (d) { return d.toBase(); });
var result2 = bar(derived, function (d) { return d.toBase(); });

View file

@ -0,0 +1,73 @@
=== tests/cases/compiler/fixingTypeParametersRepeatedly3.ts ===
interface Base {
>Base : Symbol(Base, Decl(fixingTypeParametersRepeatedly3.ts, 0, 0))
baseProp;
>baseProp : Symbol(baseProp, Decl(fixingTypeParametersRepeatedly3.ts, 0, 16))
}
interface Derived extends Base {
>Derived : Symbol(Derived, Decl(fixingTypeParametersRepeatedly3.ts, 2, 1))
>Base : Symbol(Base, Decl(fixingTypeParametersRepeatedly3.ts, 0, 0))
toBase?(): Base;
>toBase : Symbol(toBase, Decl(fixingTypeParametersRepeatedly3.ts, 3, 32))
>Base : Symbol(Base, Decl(fixingTypeParametersRepeatedly3.ts, 0, 0))
}
var derived: Derived;
>derived : Symbol(derived, Decl(fixingTypeParametersRepeatedly3.ts, 7, 3))
>Derived : Symbol(Derived, Decl(fixingTypeParametersRepeatedly3.ts, 2, 1))
declare function foo<T>(x: T, func: (p: T) => T): T;
>foo : Symbol(foo, Decl(fixingTypeParametersRepeatedly3.ts, 7, 21))
>T : Symbol(T, Decl(fixingTypeParametersRepeatedly3.ts, 9, 21))
>x : Symbol(x, Decl(fixingTypeParametersRepeatedly3.ts, 9, 24))
>T : Symbol(T, Decl(fixingTypeParametersRepeatedly3.ts, 9, 21))
>func : Symbol(func, Decl(fixingTypeParametersRepeatedly3.ts, 9, 29))
>p : Symbol(p, Decl(fixingTypeParametersRepeatedly3.ts, 9, 37))
>T : Symbol(T, Decl(fixingTypeParametersRepeatedly3.ts, 9, 21))
>T : Symbol(T, Decl(fixingTypeParametersRepeatedly3.ts, 9, 21))
>T : Symbol(T, Decl(fixingTypeParametersRepeatedly3.ts, 9, 21))
var result = foo(derived, d => d.toBase());
>result : Symbol(result, Decl(fixingTypeParametersRepeatedly3.ts, 10, 3))
>foo : Symbol(foo, Decl(fixingTypeParametersRepeatedly3.ts, 7, 21))
>derived : Symbol(derived, Decl(fixingTypeParametersRepeatedly3.ts, 7, 3))
>d : Symbol(d, Decl(fixingTypeParametersRepeatedly3.ts, 10, 25))
>d.toBase : Symbol(Derived.toBase, Decl(fixingTypeParametersRepeatedly3.ts, 3, 32))
>d : Symbol(d, Decl(fixingTypeParametersRepeatedly3.ts, 10, 25))
>toBase : Symbol(Derived.toBase, Decl(fixingTypeParametersRepeatedly3.ts, 3, 32))
// bar should type check just like foo.
// result2 should have the same type as result
declare function bar<T>(x: T, func: (p: T) => T): T;
>bar : Symbol(bar, Decl(fixingTypeParametersRepeatedly3.ts, 10, 43), Decl(fixingTypeParametersRepeatedly3.ts, 14, 52))
>T : Symbol(T, Decl(fixingTypeParametersRepeatedly3.ts, 14, 21))
>x : Symbol(x, Decl(fixingTypeParametersRepeatedly3.ts, 14, 24))
>T : Symbol(T, Decl(fixingTypeParametersRepeatedly3.ts, 14, 21))
>func : Symbol(func, Decl(fixingTypeParametersRepeatedly3.ts, 14, 29))
>p : Symbol(p, Decl(fixingTypeParametersRepeatedly3.ts, 14, 37))
>T : Symbol(T, Decl(fixingTypeParametersRepeatedly3.ts, 14, 21))
>T : Symbol(T, Decl(fixingTypeParametersRepeatedly3.ts, 14, 21))
>T : Symbol(T, Decl(fixingTypeParametersRepeatedly3.ts, 14, 21))
declare function bar<T>(x: T, func: (p: T) => T): T;
>bar : Symbol(bar, Decl(fixingTypeParametersRepeatedly3.ts, 10, 43), Decl(fixingTypeParametersRepeatedly3.ts, 14, 52))
>T : Symbol(T, Decl(fixingTypeParametersRepeatedly3.ts, 15, 21))
>x : Symbol(x, Decl(fixingTypeParametersRepeatedly3.ts, 15, 24))
>T : Symbol(T, Decl(fixingTypeParametersRepeatedly3.ts, 15, 21))
>func : Symbol(func, Decl(fixingTypeParametersRepeatedly3.ts, 15, 29))
>p : Symbol(p, Decl(fixingTypeParametersRepeatedly3.ts, 15, 37))
>T : Symbol(T, Decl(fixingTypeParametersRepeatedly3.ts, 15, 21))
>T : Symbol(T, Decl(fixingTypeParametersRepeatedly3.ts, 15, 21))
>T : Symbol(T, Decl(fixingTypeParametersRepeatedly3.ts, 15, 21))
var result2 = bar(derived, d => d.toBase());
>result2 : Symbol(result2, Decl(fixingTypeParametersRepeatedly3.ts, 16, 3))
>bar : Symbol(bar, Decl(fixingTypeParametersRepeatedly3.ts, 10, 43), Decl(fixingTypeParametersRepeatedly3.ts, 14, 52))
>derived : Symbol(derived, Decl(fixingTypeParametersRepeatedly3.ts, 7, 3))
>d : Symbol(d, Decl(fixingTypeParametersRepeatedly3.ts, 16, 26))
>d.toBase : Symbol(Derived.toBase, Decl(fixingTypeParametersRepeatedly3.ts, 3, 32))
>d : Symbol(d, Decl(fixingTypeParametersRepeatedly3.ts, 16, 26))
>toBase : Symbol(Derived.toBase, Decl(fixingTypeParametersRepeatedly3.ts, 3, 32))

View file

@ -0,0 +1,79 @@
=== tests/cases/compiler/fixingTypeParametersRepeatedly3.ts ===
interface Base {
>Base : Base
baseProp;
>baseProp : any
}
interface Derived extends Base {
>Derived : Derived
>Base : Base
toBase?(): Base;
>toBase : () => Base
>Base : Base
}
var derived: Derived;
>derived : Derived
>Derived : Derived
declare function foo<T>(x: T, func: (p: T) => T): T;
>foo : <T>(x: T, func: (p: T) => T) => T
>T : T
>x : T
>T : T
>func : (p: T) => T
>p : T
>T : T
>T : T
>T : T
var result = foo(derived, d => d.toBase());
>result : Derived
>foo(derived, d => d.toBase()) : Derived
>foo : <T>(x: T, func: (p: T) => T) => T
>derived : Derived
>d => d.toBase() : (d: Derived) => Base
>d : Derived
>d.toBase() : Base
>d.toBase : () => Base
>d : Derived
>toBase : () => Base
// bar should type check just like foo.
// result2 should have the same type as result
declare function bar<T>(x: T, func: (p: T) => T): T;
>bar : { <T>(x: T, func: (p: T) => T): T; <T>(x: T, func: (p: T) => T): T; }
>T : T
>x : T
>T : T
>func : (p: T) => T
>p : T
>T : T
>T : T
>T : T
declare function bar<T>(x: T, func: (p: T) => T): T;
>bar : { <T>(x: T, func: (p: T) => T): T; <T>(x: T, func: (p: T) => T): T; }
>T : T
>x : T
>T : T
>func : (p: T) => T
>p : T
>T : T
>T : T
>T : T
var result2 = bar(derived, d => d.toBase());
>result2 : Derived
>bar(derived, d => d.toBase()) : Derived
>bar : { <T>(x: T, func: (p: T) => T): T; <T>(x: T, func: (p: T) => T): T; }
>derived : Derived
>d => d.toBase() : (d: Derived) => Base
>d : Derived
>d.toBase() : Base
>d.toBase : () => Base
>d : Derived
>toBase : () => Base

View file

@ -146,8 +146,8 @@ var h = fun((((x => x))), ((x => x)), 10);
// Ternaries in parens
var i = fun((Math.random() < 0.5 ? x => x : x => undefined), 10);
>i : any
>fun((Math.random() < 0.5 ? x => x : x => undefined), 10) : any
>i : number
>fun((Math.random() < 0.5 ? x => x : x => undefined), 10) : number
>fun : { <T>(g: (x: T) => T, x: T): T; <T>(g: (x: T) => T, h: (y: T) => T, x: T): T; }
>(Math.random() < 0.5 ? x => x : x => undefined) : (x: number) => any
>Math.random() < 0.5 ? x => x : x => undefined : (x: number) => any
@ -166,8 +166,8 @@ var i = fun((Math.random() < 0.5 ? x => x : x => undefined), 10);
>10 : number
var j = fun((Math.random() < 0.5 ? (x => x) : (x => undefined)), 10);
>j : any
>fun((Math.random() < 0.5 ? (x => x) : (x => undefined)), 10) : any
>j : number
>fun((Math.random() < 0.5 ? (x => x) : (x => undefined)), 10) : number
>fun : { <T>(g: (x: T) => T, x: T): T; <T>(g: (x: T) => T, h: (y: T) => T, x: T): T; }
>(Math.random() < 0.5 ? (x => x) : (x => undefined)) : (x: number) => any
>Math.random() < 0.5 ? (x => x) : (x => undefined) : (x: number) => any
@ -188,8 +188,8 @@ var j = fun((Math.random() < 0.5 ? (x => x) : (x => undefined)), 10);
>10 : number
var k = fun((Math.random() < 0.5 ? (x => x) : (x => undefined)), x => x, 10);
>k : any
>fun((Math.random() < 0.5 ? (x => x) : (x => undefined)), x => x, 10) : any
>k : number
>fun((Math.random() < 0.5 ? (x => x) : (x => undefined)), x => x, 10) : number
>fun : { <T>(g: (x: T) => T, x: T): T; <T>(g: (x: T) => T, h: (y: T) => T, x: T): T; }
>(Math.random() < 0.5 ? (x => x) : (x => undefined)) : (x: number) => any
>Math.random() < 0.5 ? (x => x) : (x => undefined) : (x: number) => any
@ -207,14 +207,14 @@ var k = fun((Math.random() < 0.5 ? (x => x) : (x => undefined)), x => x, 10);
>x => undefined : (x: number) => any
>x : number
>undefined : undefined
>x => x : (x: any) => any
>x : any
>x : any
>x => x : (x: number) => number
>x : number
>x : number
>10 : number
var l = fun(((Math.random() < 0.5 ? ((x => x)) : ((x => undefined)))), ((x => x)), 10);
>l : any
>fun(((Math.random() < 0.5 ? ((x => x)) : ((x => undefined)))), ((x => x)), 10) : any
>l : number
>fun(((Math.random() < 0.5 ? ((x => x)) : ((x => undefined)))), ((x => x)), 10) : number
>fun : { <T>(g: (x: T) => T, x: T): T; <T>(g: (x: T) => T, h: (y: T) => T, x: T): T; }
>((Math.random() < 0.5 ? ((x => x)) : ((x => undefined)))) : (x: number) => any
>(Math.random() < 0.5 ? ((x => x)) : ((x => undefined))) : (x: number) => any
@ -235,11 +235,11 @@ var l = fun(((Math.random() < 0.5 ? ((x => x)) : ((x => undefined)))), ((x => x)
>x => undefined : (x: number) => any
>x : number
>undefined : undefined
>((x => x)) : (x: any) => any
>(x => x) : (x: any) => any
>x => x : (x: any) => any
>x : any
>x : any
>((x => x)) : (x: number) => number
>(x => x) : (x: number) => number
>x => x : (x: number) => number
>x : number
>x : number
>10 : number
var lambda1: (x: number) => number = x => x;

View file

@ -0,0 +1,7 @@
declare function f<T>(x: T, y: (p: T) => T, z: (p: T) => T): T;
f("", x => null, x => x.toLowerCase());
// First overload of g should type check just like f
declare function g<T>(x: T, y: (p: T) => T, z: (p: T) => T): T;
declare function g();
g("", x => null, x => x.toLowerCase());

View file

@ -0,0 +1,17 @@
interface Base {
baseProp;
}
interface Derived extends Base {
toBase(): Base;
}
var derived: Derived;
declare function foo<T>(x: T, func: (p: T) => T): T;
var result = foo(derived, d => d.toBase());
// bar should type check just like foo.
// The same error should be observed in both cases.
declare function bar<T>(x: T, func: (p: T) => T): T;
declare function bar<T>(x: T, func: (p: T) => T): T;
var result = bar(derived, d => d.toBase());

View file

@ -0,0 +1,17 @@
interface Base {
baseProp;
}
interface Derived extends Base {
toBase?(): Base;
}
var derived: Derived;
declare function foo<T>(x: T, func: (p: T) => T): T;
var result = foo(derived, d => d.toBase());
// bar should type check just like foo.
// result2 should have the same type as result
declare function bar<T>(x: T, func: (p: T) => T): T;
declare function bar<T>(x: T, func: (p: T) => T): T;
var result2 = bar(derived, d => d.toBase());

View file

@ -0,0 +1,13 @@
/// <reference path='fourslash.ts'/>
////declare function f<T>(x: T, y: (p: T) => T, z: (p: T) => T): T;
////var /*1*/result = /*2*/f(0, /*3*/x => null, /*4*/x => x.blahblah);
goTo.marker('1');
verify.quickInfoIs('var result: number');
goTo.marker('2');
verify.quickInfoIs('function f<number>(x: number, y: (p: number) => number, z: (p: number) => number): number');
goTo.marker('3');
verify.quickInfoIs('(parameter) x: number');
goTo.marker('4');
verify.quickInfoIs('(parameter) x: number');