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:
commit
2c5ba08266
15 changed files with 512 additions and 33 deletions
|
@ -4249,7 +4249,7 @@ 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;
|
||||
|
@ -4258,6 +4258,9 @@ namespace ts {
|
|||
}
|
||||
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 contextualParameterType = getTypeOfSymbol(lastOrUndefined(context.parameters));
|
||||
assignTypeToParameterAndFixTypeParameters(parameter, contextualParameterType, mapper);
|
||||
}
|
||||
}
|
||||
|
||||
function assignTypeToParameterAndFixTypeParameters(parameter: Symbol, contextualType: Type, mapper: TypeMapper) {
|
||||
let links = getSymbolLinks(parameter);
|
||||
links.type = instantiateType(getTypeOfSymbol(lastOrUndefined(context.parameters)), mapper);
|
||||
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,29 +9144,38 @@ 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!contextChecked) {
|
||||
checkSignatureDeclaration(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (produceDiagnostics && node.kind !== SyntaxKind.MethodDeclaration && node.kind !== SyntaxKind.MethodSignature) {
|
||||
checkCollisionWithCapturedSuperVariable(node, (<FunctionExpression>node).name);
|
||||
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
12
tests/baselines/reference/fixingTypeParametersRepeatedly1.js
Normal file
12
tests/baselines/reference/fixingTypeParametersRepeatedly1.js
Normal 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(); });
|
|
@ -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))
|
||||
|
|
@ -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
|
||||
|
|
@ -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'.
|
23
tests/baselines/reference/fixingTypeParametersRepeatedly2.js
Normal file
23
tests/baselines/reference/fixingTypeParametersRepeatedly2.js
Normal 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(); });
|
23
tests/baselines/reference/fixingTypeParametersRepeatedly3.js
Normal file
23
tests/baselines/reference/fixingTypeParametersRepeatedly3.js
Normal 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(); });
|
|
@ -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))
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
7
tests/cases/compiler/fixingTypeParametersRepeatedly1.ts
Normal file
7
tests/cases/compiler/fixingTypeParametersRepeatedly1.ts
Normal 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());
|
17
tests/cases/compiler/fixingTypeParametersRepeatedly2.ts
Normal file
17
tests/cases/compiler/fixingTypeParametersRepeatedly2.ts
Normal 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());
|
17
tests/cases/compiler/fixingTypeParametersRepeatedly3.ts
Normal file
17
tests/cases/compiler/fixingTypeParametersRepeatedly3.ts
Normal 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());
|
13
tests/cases/fourslash/fixingTypeParametersQuickInfo.ts
Normal file
13
tests/cases/fourslash/fixingTypeParametersQuickInfo.ts
Normal 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');
|
Loading…
Reference in a new issue