@@ -4225,7 +4225,7 @@ namespace ts {
42254225 }
42264226
42274227 function createInferenceMapper(context: InferenceContext): TypeMapper {
4228- return t => {
4228+ let mapper: TypeMapper = t => {
42294229 for (let i = 0; i < context.typeParameters.length; i++) {
42304230 if (t === context.typeParameters[i]) {
42314231 context.inferences[i].isFixed = true;
@@ -4234,6 +4234,20 @@ namespace ts {
42344234 }
42354235 return t;
42364236 }
4237+
4238+ mapper.context = context;
4239+ return mapper;
4240+ }
4241+
4242+ function fixTypeParametersAfterInferringFromContextualParameterTypes(context: InferenceContext): void {
4243+ for (let i = 0; i < context.typeParameters.length; i++) {
4244+ let typeParameterInfo = context.inferences[i];
4245+ if (typeParameterInfo.fixAfterInferringFromContextualParameterType) {
4246+ typeParameterInfo.fixAfterInferringFromContextualParameterType = false;
4247+ typeParameterInfo.isFixed = true;
4248+ getInferredType(context, i);
4249+ }
4250+ }
42374251 }
42384252
42394253 function identityMapper(type: Type): Type {
@@ -5397,7 +5411,10 @@ namespace ts {
53975411 function createInferenceContext(typeParameters: TypeParameter[], inferUnionTypes: boolean): InferenceContext {
53985412 let inferences: TypeInferences[] = [];
53995413 for (let unused of typeParameters) {
5400- inferences.push({ primary: undefined, secondary: undefined, isFixed: false });
5414+ inferences.push({
5415+ primary: undefined, secondary: undefined,
5416+ isFixed: false, fixAfterInferringFromContextualParameterType: false
5417+ });
54015418 }
54025419 return {
54035420 typeParameters,
@@ -5407,7 +5424,7 @@ namespace ts {
54075424 };
54085425 }
54095426
5410- function inferTypes(context: InferenceContext, source: Type, target: Type) {
5427+ function inferTypes(context: InferenceContext, source: Type, target: Type, inferringFromContextuallyTypedParameter: boolean ) {
54115428 let sourceStack: Type[];
54125429 let targetStack: Type[];
54135430 let depth = 0;
@@ -5446,6 +5463,9 @@ namespace ts {
54465463 if (!contains(candidates, source)) {
54475464 candidates.push(source);
54485465 }
5466+ if (inferringFromContextuallyTypedParameter) {
5467+ inferences.fixAfterInferringFromContextualParameterType = true;
5468+ }
54495469 }
54505470 return;
54515471 }
@@ -6698,7 +6718,7 @@ namespace ts {
66986718 // Presence of a contextual type mapper indicates inferential typing, except the identityMapper object is
66996719 // used as a special marker for other purposes.
67006720 function isInferentialContext(mapper: TypeMapper) {
6701- return mapper && mapper !== identityMapper ;
6721+ return mapper && mapper.context ;
67026722 }
67036723
67046724 // A node is an assignment target if it is on the left hand side of an '=' token, if it is parented by a property
@@ -7834,7 +7854,7 @@ namespace ts {
78347854 let context = createInferenceContext(signature.typeParameters, /*inferUnionTypes*/ true);
78357855 forEachMatchingParameterType(contextualSignature, signature, (source, target) => {
78367856 // Type parameters from outer context referenced by source type are fixed by instantiation of the source type
7837- inferTypes(context, instantiateType(source, contextualMapper), target);
7857+ inferTypes(context, instantiateType(source, contextualMapper), target, false );
78387858 });
78397859 return getSignatureInstantiation(signature, getInferredTypes(context));
78407860 }
@@ -7884,7 +7904,7 @@ namespace ts {
78847904 argType = checkExpressionWithContextualType(arg, paramType, mapper);
78857905 }
78867906
7887- inferTypes(context, argType, paramType);
7907+ inferTypes(context, argType, paramType, false );
78887908 }
78897909 }
78907910
@@ -7899,7 +7919,7 @@ namespace ts {
78997919 if (excludeArgument[i] === false) {
79007920 let arg = args[i];
79017921 let paramType = getTypeAtPosition(signature, i);
7902- inferTypes(context, checkExpressionWithContextualType(arg, paramType, inferenceMapper), paramType);
7922+ inferTypes(context, checkExpressionWithContextualType(arg, paramType, inferenceMapper), paramType, false );
79037923 }
79047924 }
79057925 }
@@ -8788,13 +8808,23 @@ namespace ts {
87888808 let len = signature.parameters.length - (signature.hasRestParameter ? 1 : 0);
87898809 for (let i = 0; i < len; i++) {
87908810 let parameter = signature.parameters[i];
8791- let links = getSymbolLinks(parameter );
8792- links.type = instantiateType(getTypeAtPosition(context, i) , mapper);
8811+ let contextualParameterType = getTypeAtPosition(context, i );
8812+ assignTypeToParameterAndFixTypeParameters(getSymbolLinks(parameter), contextualParameterType , mapper);
87938813 }
87948814 if (signature.hasRestParameter && context.hasRestParameter && signature.parameters.length >= context.parameters.length) {
87958815 let parameter = lastOrUndefined(signature.parameters);
8796- let links = getSymbolLinks(parameter);
8797- links.type = instantiateType(getTypeOfSymbol(lastOrUndefined(context.parameters)), mapper);
8816+ let contextualParameterType = getTypeOfSymbol(lastOrUndefined(context.parameters));
8817+ assignTypeToParameterAndFixTypeParameters(getSymbolLinks(parameter), contextualParameterType, mapper);
8818+ }
8819+ }
8820+
8821+ function assignTypeToParameterAndFixTypeParameters(parameterLinks: SymbolLinks, contextualType: Type, mapper: TypeMapper) {
8822+ if (!parameterLinks.type) {
8823+ parameterLinks.type = instantiateType(contextualType, mapper);
8824+ }
8825+ else if (isInferentialContext(mapper)) {
8826+ inferTypes(mapper.context, parameterLinks.type, contextualType, true);
8827+ fixTypeParametersAfterInferringFromContextualParameterTypes(mapper.context);
87988828 }
87998829 }
88008830
@@ -9014,27 +9044,34 @@ namespace ts {
90149044
90159045 let links = getNodeLinks(node);
90169046 let type = getTypeOfSymbol(node.symbol);
9047+ let contextSensitive = isContextSensitive(node);
9048+ let mightFixTypeParameters = contextSensitive && isInferentialContext(contextualMapper);
9049+
90179050 // Check if function expression is contextually typed and assign parameter types if so
9018- if (!(links.flags & NodeCheckFlags.ContextChecked)) {
9051+ if (mightFixTypeParameters || !(links.flags & NodeCheckFlags.ContextChecked)) {
90199052 let contextualSignature = getContextualSignature(node);
90209053 // If a type check is started at a function expression that is an argument of a function call, obtaining the
90219054 // contextual type may recursively get back to here during overload resolution of the call. If so, we will have
90229055 // already assigned contextual types.
9023- if (!(links.flags & NodeCheckFlags.ContextChecked)) {
9056+ let contextChecked = !!(links.flags & NodeCheckFlags.ContextChecked);
9057+ if (mightFixTypeParameters || !contextChecked) {
90249058 links.flags |= NodeCheckFlags.ContextChecked;
90259059 if (contextualSignature) {
90269060 let signature = getSignaturesOfType(type, SignatureKind.Call)[0];
9027- if (isContextSensitive(node) ) {
9061+ if (contextSensitive ) {
90289062 assignContextualParameterTypes(signature, contextualSignature, contextualMapper || identityMapper);
90299063 }
9030- if (!node.type && !signature.resolvedReturnType) {
9064+ if (mightFixTypeParameters || !node.type && !signature.resolvedReturnType) {
90319065 let returnType = getReturnTypeFromBody(node, contextualMapper);
90329066 if (!signature.resolvedReturnType) {
90339067 signature.resolvedReturnType = returnType;
90349068 }
90359069 }
90369070 }
9037- checkSignatureDeclaration(node);
9071+
9072+ if (!contextChecked) {
9073+ checkSignatureDeclaration(node);
9074+ }
90389075 }
90399076 }
90409077
@@ -9724,7 +9761,7 @@ namespace ts {
97249761 }
97259762
97269763 function instantiateTypeWithSingleGenericCallSignature(node: Expression | MethodDeclaration, type: Type, contextualMapper?: TypeMapper) {
9727- if (contextualMapper && contextualMapper !== identityMapper ) {
9764+ if (isInferentialContext( contextualMapper) ) {
97289765 let signature = getSingleCallSignature(type);
97299766 if (signature && signature.typeParameters) {
97309767 let contextualType = getContextualType(<Expression>node);
0 commit comments