Skip to content

Commit a660d7b

Browse files
committed
Add hopefully helpful comments
1 parent d25bcea commit a660d7b

File tree

2 files changed

+42
-8
lines changed

2 files changed

+42
-8
lines changed

src/compiler/checker.ts

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8794,21 +8794,51 @@ namespace ts {
87948794
for (let i = 0; i < len; i++) {
87958795
let parameter = signature.parameters[i];
87968796
let contextualParameterType = getTypeAtPosition(context, i);
8797-
assignTypeToParameterAndFixTypeParameters(getSymbolLinks(parameter), contextualParameterType, mapper);
8797+
assignTypeToParameterAndFixTypeParameters(parameter, contextualParameterType, mapper);
87988798
}
87998799
if (signature.hasRestParameter && context.hasRestParameter && signature.parameters.length >= context.parameters.length) {
88008800
let parameter = lastOrUndefined(signature.parameters);
88018801
let contextualParameterType = getTypeOfSymbol(lastOrUndefined(context.parameters));
8802-
assignTypeToParameterAndFixTypeParameters(getSymbolLinks(parameter), contextualParameterType, mapper);
8802+
assignTypeToParameterAndFixTypeParameters(parameter, contextualParameterType, mapper);
88038803
}
88048804
}
88058805

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);
88098810
}
88108811
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));
88128842
}
88138843
}
88148844

@@ -9031,7 +9061,9 @@ namespace ts {
90319061
let contextSensitive = isContextSensitive(node);
90329062
let mightFixTypeParameters = contextSensitive && isInferentialContext(contextualMapper);
90339063

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.
90359067
if (mightFixTypeParameters || !(links.flags & NodeCheckFlags.ContextChecked)) {
90369068
let contextualSignature = getContextualSignature(node);
90379069
// If a type check is started at a function expression that is an argument of a function call, obtaining the

src/compiler/types.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1893,7 +1893,9 @@ namespace ts {
18931893
/* @internal */
18941894
export interface TypeMapper {
18951895
(t: TypeParameter): Type;
1896-
context?: InferenceContext;
1896+
context?: InferenceContext; // The inference context this mapper was created from.
1897+
// Only inference mappers have this set (in createInferenceMapper).
1898+
// The identity mapper and regular instantiation mappers do not need it.
18971899
}
18981900

18991901
/* @internal */

0 commit comments

Comments
 (0)