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,15 +4249,18 @@ namespace ts {
|
||||||
}
|
}
|
||||||
|
|
||||||
function createInferenceMapper(context: InferenceContext): TypeMapper {
|
function createInferenceMapper(context: InferenceContext): TypeMapper {
|
||||||
return t => {
|
let mapper: TypeMapper = t => {
|
||||||
for (let i = 0; i < context.typeParameters.length; i++) {
|
for (let i = 0; i < context.typeParameters.length; i++) {
|
||||||
if (t === context.typeParameters[i]) {
|
if (t === context.typeParameters[i]) {
|
||||||
context.inferences[i].isFixed = true;
|
context.inferences[i].isFixed = true;
|
||||||
return getInferredType(context, i);
|
return getInferredType(context, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return t;
|
return t;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mapper.context = context;
|
||||||
|
return mapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
function identityMapper(type: Type): Type {
|
function identityMapper(type: Type): Type {
|
||||||
|
@ -5468,7 +5471,9 @@ namespace ts {
|
||||||
function createInferenceContext(typeParameters: TypeParameter[], inferUnionTypes: boolean): InferenceContext {
|
function createInferenceContext(typeParameters: TypeParameter[], inferUnionTypes: boolean): InferenceContext {
|
||||||
let inferences: TypeInferences[] = [];
|
let inferences: TypeInferences[] = [];
|
||||||
for (let unused of typeParameters) {
|
for (let unused of typeParameters) {
|
||||||
inferences.push({ primary: undefined, secondary: undefined, isFixed: false });
|
inferences.push({
|
||||||
|
primary: undefined, secondary: undefined, isFixed: false
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
typeParameters,
|
typeParameters,
|
||||||
|
@ -6769,10 +6774,23 @@ namespace ts {
|
||||||
return result;
|
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) {
|
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
|
// 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);
|
let len = signature.parameters.length - (signature.hasRestParameter ? 1 : 0);
|
||||||
for (let i = 0; i < len; i++) {
|
for (let i = 0; i < len; i++) {
|
||||||
let parameter = signature.parameters[i];
|
let parameter = signature.parameters[i];
|
||||||
let links = getSymbolLinks(parameter);
|
let contextualParameterType = getTypeAtPosition(context, i);
|
||||||
links.type = instantiateType(getTypeAtPosition(context, i), mapper);
|
assignTypeToParameterAndFixTypeParameters(parameter, contextualParameterType, mapper);
|
||||||
}
|
}
|
||||||
if (signature.hasRestParameter && context.hasRestParameter && signature.parameters.length >= context.parameters.length) {
|
if (signature.hasRestParameter && context.hasRestParameter && signature.parameters.length >= context.parameters.length) {
|
||||||
let parameter = lastOrUndefined(signature.parameters);
|
let parameter = lastOrUndefined(signature.parameters);
|
||||||
let links = getSymbolLinks(parameter);
|
let contextualParameterType = getTypeOfSymbol(lastOrUndefined(context.parameters));
|
||||||
links.type = instantiateType(getTypeOfSymbol(lastOrUndefined(context.parameters)), mapper);
|
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 links = getNodeLinks(node);
|
||||||
let type = getTypeOfSymbol(node.symbol);
|
let type = getTypeOfSymbol(node.symbol);
|
||||||
// Check if function expression is contextually typed and assign parameter types if so
|
let contextSensitive = isContextSensitive(node);
|
||||||
if (!(links.flags & NodeCheckFlags.ContextChecked)) {
|
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);
|
let contextualSignature = getContextualSignature(node);
|
||||||
// If a type check is started at a function expression that is an argument of a function call, obtaining the
|
// 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
|
// contextual type may recursively get back to here during overload resolution of the call. If so, we will have
|
||||||
// already assigned contextual types.
|
// already assigned contextual types.
|
||||||
if (!(links.flags & NodeCheckFlags.ContextChecked)) {
|
let contextChecked = !!(links.flags & NodeCheckFlags.ContextChecked);
|
||||||
|
if (mightFixTypeParameters || !contextChecked) {
|
||||||
links.flags |= NodeCheckFlags.ContextChecked;
|
links.flags |= NodeCheckFlags.ContextChecked;
|
||||||
if (contextualSignature) {
|
if (contextualSignature) {
|
||||||
let signature = getSignaturesOfType(type, SignatureKind.Call)[0];
|
let signature = getSignaturesOfType(type, SignatureKind.Call)[0];
|
||||||
if (isContextSensitive(node)) {
|
if (contextSensitive) {
|
||||||
assignContextualParameterTypes(signature, contextualSignature, contextualMapper || identityMapper);
|
assignContextualParameterTypes(signature, contextualSignature, contextualMapper || identityMapper);
|
||||||
}
|
}
|
||||||
if (!node.type && !signature.resolvedReturnType) {
|
if (mightFixTypeParameters || !node.type && !signature.resolvedReturnType) {
|
||||||
let returnType = getReturnTypeFromBody(node, contextualMapper);
|
let returnType = getReturnTypeFromBody(node, contextualMapper);
|
||||||
if (!signature.resolvedReturnType) {
|
if (!signature.resolvedReturnType) {
|
||||||
signature.resolvedReturnType = returnType;
|
signature.resolvedReturnType = returnType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checkSignatureDeclaration(node);
|
|
||||||
|
if (!contextChecked) {
|
||||||
|
checkSignatureDeclaration(node);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9797,7 +9863,7 @@ namespace ts {
|
||||||
}
|
}
|
||||||
|
|
||||||
function instantiateTypeWithSingleGenericCallSignature(node: Expression | MethodDeclaration, type: Type, contextualMapper?: TypeMapper) {
|
function instantiateTypeWithSingleGenericCallSignature(node: Expression | MethodDeclaration, type: Type, contextualMapper?: TypeMapper) {
|
||||||
if (contextualMapper && contextualMapper !== identityMapper) {
|
if (isInferentialContext(contextualMapper)) {
|
||||||
let signature = getSingleCallSignature(type);
|
let signature = getSingleCallSignature(type);
|
||||||
if (signature && signature.typeParameters) {
|
if (signature && signature.typeParameters) {
|
||||||
let contextualType = getContextualType(<Expression>node);
|
let contextualType = getContextualType(<Expression>node);
|
||||||
|
|
|
@ -1912,6 +1912,9 @@ namespace ts {
|
||||||
/* @internal */
|
/* @internal */
|
||||||
export interface TypeMapper {
|
export interface TypeMapper {
|
||||||
(t: TypeParameter): Type;
|
(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 */
|
/* @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
|
// Ternaries in parens
|
||||||
var i = fun((Math.random() < 0.5 ? x => x : x => undefined), 10);
|
var i = fun((Math.random() < 0.5 ? x => x : x => undefined), 10);
|
||||||
>i : any
|
>i : number
|
||||||
>fun((Math.random() < 0.5 ? x => x : x => undefined), 10) : any
|
>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; }
|
>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
|
||||||
>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
|
>10 : number
|
||||||
|
|
||||||
var j = fun((Math.random() < 0.5 ? (x => x) : (x => undefined)), 10);
|
var j = fun((Math.random() < 0.5 ? (x => x) : (x => undefined)), 10);
|
||||||
>j : any
|
>j : number
|
||||||
>fun((Math.random() < 0.5 ? (x => x) : (x => undefined)), 10) : any
|
>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; }
|
>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
|
||||||
>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
|
>10 : number
|
||||||
|
|
||||||
var k = fun((Math.random() < 0.5 ? (x => x) : (x => undefined)), x => x, 10);
|
var k = fun((Math.random() < 0.5 ? (x => x) : (x => undefined)), x => x, 10);
|
||||||
>k : any
|
>k : number
|
||||||
>fun((Math.random() < 0.5 ? (x => x) : (x => undefined)), x => x, 10) : any
|
>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; }
|
>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
|
||||||
>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 => undefined : (x: number) => any
|
||||||
>x : number
|
>x : number
|
||||||
>undefined : undefined
|
>undefined : undefined
|
||||||
>x => x : (x: any) => any
|
>x => x : (x: number) => number
|
||||||
>x : any
|
>x : number
|
||||||
>x : any
|
>x : number
|
||||||
>10 : number
|
>10 : number
|
||||||
|
|
||||||
var l = fun(((Math.random() < 0.5 ? ((x => x)) : ((x => undefined)))), ((x => x)), 10);
|
var l = fun(((Math.random() < 0.5 ? ((x => x)) : ((x => undefined)))), ((x => x)), 10);
|
||||||
>l : any
|
>l : number
|
||||||
>fun(((Math.random() < 0.5 ? ((x => x)) : ((x => undefined)))), ((x => x)), 10) : any
|
>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; }
|
>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
|
||||||
>(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 => undefined : (x: number) => any
|
||||||
>x : number
|
>x : number
|
||||||
>undefined : undefined
|
>undefined : undefined
|
||||||
>((x => x)) : (x: any) => any
|
>((x => x)) : (x: number) => number
|
||||||
>(x => x) : (x: any) => any
|
>(x => x) : (x: number) => number
|
||||||
>x => x : (x: any) => any
|
>x => x : (x: number) => number
|
||||||
>x : any
|
>x : number
|
||||||
>x : any
|
>x : number
|
||||||
>10 : number
|
>10 : number
|
||||||
|
|
||||||
var lambda1: (x: number) => number = x => x;
|
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