@@ -4225,7 +4225,7 @@ namespace ts {
4225
4225
}
4226
4226
4227
4227
function createInferenceMapper(context: InferenceContext): TypeMapper {
4228
- return t => {
4228
+ let mapper: TypeMapper = t => {
4229
4229
for (let i = 0; i < context.typeParameters.length; i++) {
4230
4230
if (t === context.typeParameters[i]) {
4231
4231
context.inferences[i].isFixed = true;
@@ -4234,6 +4234,20 @@ namespace ts {
4234
4234
}
4235
4235
return t;
4236
4236
}
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
+ }
4237
4251
}
4238
4252
4239
4253
function identityMapper(type: Type): Type {
@@ -5397,7 +5411,10 @@ namespace ts {
5397
5411
function createInferenceContext(typeParameters: TypeParameter[], inferUnionTypes: boolean): InferenceContext {
5398
5412
let inferences: TypeInferences[] = [];
5399
5413
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
+ });
5401
5418
}
5402
5419
return {
5403
5420
typeParameters,
@@ -5407,7 +5424,7 @@ namespace ts {
5407
5424
};
5408
5425
}
5409
5426
5410
- function inferTypes(context: InferenceContext, source: Type, target: Type) {
5427
+ function inferTypes(context: InferenceContext, source: Type, target: Type, inferringFromContextuallyTypedParameter: boolean ) {
5411
5428
let sourceStack: Type[];
5412
5429
let targetStack: Type[];
5413
5430
let depth = 0;
@@ -5446,6 +5463,9 @@ namespace ts {
5446
5463
if (!contains(candidates, source)) {
5447
5464
candidates.push(source);
5448
5465
}
5466
+ if (inferringFromContextuallyTypedParameter) {
5467
+ inferences.fixAfterInferringFromContextualParameterType = true;
5468
+ }
5449
5469
}
5450
5470
return;
5451
5471
}
@@ -6698,7 +6718,7 @@ namespace ts {
6698
6718
// Presence of a contextual type mapper indicates inferential typing, except the identityMapper object is
6699
6719
// used as a special marker for other purposes.
6700
6720
function isInferentialContext(mapper: TypeMapper) {
6701
- return mapper && mapper !== identityMapper ;
6721
+ return mapper && mapper.context ;
6702
6722
}
6703
6723
6704
6724
// 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 {
7834
7854
let context = createInferenceContext(signature.typeParameters, /*inferUnionTypes*/ true);
7835
7855
forEachMatchingParameterType(contextualSignature, signature, (source, target) => {
7836
7856
// 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 );
7838
7858
});
7839
7859
return getSignatureInstantiation(signature, getInferredTypes(context));
7840
7860
}
@@ -7884,7 +7904,7 @@ namespace ts {
7884
7904
argType = checkExpressionWithContextualType(arg, paramType, mapper);
7885
7905
}
7886
7906
7887
- inferTypes(context, argType, paramType);
7907
+ inferTypes(context, argType, paramType, false );
7888
7908
}
7889
7909
}
7890
7910
@@ -7899,7 +7919,7 @@ namespace ts {
7899
7919
if (excludeArgument[i] === false) {
7900
7920
let arg = args[i];
7901
7921
let paramType = getTypeAtPosition(signature, i);
7902
- inferTypes(context, checkExpressionWithContextualType(arg, paramType, inferenceMapper), paramType);
7922
+ inferTypes(context, checkExpressionWithContextualType(arg, paramType, inferenceMapper), paramType, false );
7903
7923
}
7904
7924
}
7905
7925
}
@@ -8788,13 +8808,23 @@ namespace ts {
8788
8808
let len = signature.parameters.length - (signature.hasRestParameter ? 1 : 0);
8789
8809
for (let i = 0; i < len; i++) {
8790
8810
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);
8793
8813
}
8794
8814
if (signature.hasRestParameter && context.hasRestParameter && signature.parameters.length >= context.parameters.length) {
8795
8815
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);
8798
8828
}
8799
8829
}
8800
8830
@@ -9014,27 +9044,34 @@ namespace ts {
9014
9044
9015
9045
let links = getNodeLinks(node);
9016
9046
let type = getTypeOfSymbol(node.symbol);
9047
+ let contextSensitive = isContextSensitive(node);
9048
+ let mightFixTypeParameters = contextSensitive && isInferentialContext(contextualMapper);
9049
+
9017
9050
// 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)) {
9019
9052
let contextualSignature = getContextualSignature(node);
9020
9053
// If a type check is started at a function expression that is an argument of a function call, obtaining the
9021
9054
// contextual type may recursively get back to here during overload resolution of the call. If so, we will have
9022
9055
// already assigned contextual types.
9023
- if (!(links.flags & NodeCheckFlags.ContextChecked)) {
9056
+ let contextChecked = !!(links.flags & NodeCheckFlags.ContextChecked);
9057
+ if (mightFixTypeParameters || !contextChecked) {
9024
9058
links.flags |= NodeCheckFlags.ContextChecked;
9025
9059
if (contextualSignature) {
9026
9060
let signature = getSignaturesOfType(type, SignatureKind.Call)[0];
9027
- if (isContextSensitive(node) ) {
9061
+ if (contextSensitive ) {
9028
9062
assignContextualParameterTypes(signature, contextualSignature, contextualMapper || identityMapper);
9029
9063
}
9030
- if (!node.type && !signature.resolvedReturnType) {
9064
+ if (mightFixTypeParameters || !node.type && !signature.resolvedReturnType) {
9031
9065
let returnType = getReturnTypeFromBody(node, contextualMapper);
9032
9066
if (!signature.resolvedReturnType) {
9033
9067
signature.resolvedReturnType = returnType;
9034
9068
}
9035
9069
}
9036
9070
}
9037
- checkSignatureDeclaration(node);
9071
+
9072
+ if (!contextChecked) {
9073
+ checkSignatureDeclaration(node);
9074
+ }
9038
9075
}
9039
9076
}
9040
9077
@@ -9724,7 +9761,7 @@ namespace ts {
9724
9761
}
9725
9762
9726
9763
function instantiateTypeWithSingleGenericCallSignature(node: Expression | MethodDeclaration, type: Type, contextualMapper?: TypeMapper) {
9727
- if (contextualMapper && contextualMapper !== identityMapper ) {
9764
+ if (isInferentialContext( contextualMapper) ) {
9728
9765
let signature = getSingleCallSignature(type);
9729
9766
if (signature && signature.typeParameters) {
9730
9767
let contextualType = getContextualType(<Expression>node);
0 commit comments