@@ -8794,21 +8794,51 @@ namespace ts {
8794
8794
for (let i = 0; i < len; i++) {
8795
8795
let parameter = signature.parameters[i];
8796
8796
let contextualParameterType = getTypeAtPosition(context, i);
8797
- assignTypeToParameterAndFixTypeParameters(getSymbolLinks( parameter) , contextualParameterType, mapper);
8797
+ assignTypeToParameterAndFixTypeParameters(parameter, contextualParameterType, mapper);
8798
8798
}
8799
8799
if (signature.hasRestParameter && context.hasRestParameter && signature.parameters.length >= context.parameters.length) {
8800
8800
let parameter = lastOrUndefined(signature.parameters);
8801
8801
let contextualParameterType = getTypeOfSymbol(lastOrUndefined(context.parameters));
8802
- assignTypeToParameterAndFixTypeParameters(getSymbolLinks( parameter) , contextualParameterType, mapper);
8802
+ assignTypeToParameterAndFixTypeParameters(parameter, contextualParameterType, mapper);
8803
8803
}
8804
8804
}
8805
8805
8806
- function assignTypeToParameterAndFixTypeParameters(parameterLinks: SymbolLinks, contextualType: Type, mapper: TypeMapper) {
8807
- if (!parameterLinks.type) {
8808
- parameterLinks.type = instantiateType(contextualType, mapper);
8806
+ function assignTypeToParameterAndFixTypeParameters(parameter: Symbol, contextualType: Type, mapper: TypeMapper) {
8807
+ let links = getSymbolLinks(parameter);
8808
+ if (!links.type) {
8809
+ links.type = instantiateType(contextualType, mapper);
8809
8810
}
8810
8811
else if (isInferentialContext(mapper)) {
8811
- inferTypes(mapper.context, parameterLinks.type, instantiateType(contextualType, mapper));
8812
+ // Even if the parameter already has a type, it might be because it was given a type while
8813
+ // processing the function as an argument to a prior signature during overload resolution.
8814
+ // If this was the case, it may have caused some type parameters to be fixed. So here,
8815
+ // we need to ensure that type parameters at the same positions get fixed again. This is
8816
+ // done by calling instantiateType to attach the mapper to the contextualType, and then
8817
+ // calling inferTypes to force a walk of contextualType so that all the correct fixing
8818
+ // happens. The choice to pass in links.type may seem kind of arbitrary, but it serves
8819
+ // to make sure that all the correct positions in contextualType are reached by the walk.
8820
+ // Here is an example:
8821
+ //
8822
+ // interface Base {
8823
+ // baseProp;
8824
+ // }
8825
+ // interface Derived extends Base {
8826
+ // toBase(): Base;
8827
+ // }
8828
+ //
8829
+ // var derived: Derived;
8830
+ //
8831
+ // declare function foo<T>(x: T, func: (p: T) => T): T;
8832
+ // declare function foo<T>(x: T, func: (p: T) => T): T;
8833
+ //
8834
+ // var result = foo(derived, d => d.toBase());
8835
+ //
8836
+ // We are typing d while checking the second overload. But we've already given d
8837
+ // a type (Derived) from the first overload. However, we still want to fix the
8838
+ // T in the second overload so that we do not infer Base as a candidate for T
8839
+ // (inferring Base would make type argument inference inconsistent between the two
8840
+ // overloads).
8841
+ inferTypes(mapper.context, links.type, instantiateType(contextualType, mapper));
8812
8842
}
8813
8843
}
8814
8844
@@ -9031,7 +9061,9 @@ namespace ts {
9031
9061
let contextSensitive = isContextSensitive(node);
9032
9062
let mightFixTypeParameters = contextSensitive && isInferentialContext(contextualMapper);
9033
9063
9034
- // Check if function expression is contextually typed and assign parameter types if so
9064
+ // Check if function expression is contextually typed and assign parameter types if so.
9065
+ // See the comment in assignTypeToParameterAndFixTypeParameters to understand why we need to
9066
+ // check mightFixTypeParameters.
9035
9067
if (mightFixTypeParameters || !(links.flags & NodeCheckFlags.ContextChecked)) {
9036
9068
let contextualSignature = getContextualSignature(node);
9037
9069
// If a type check is started at a function expression that is an argument of a function call, obtaining the
0 commit comments