@@ -10134,13 +10134,12 @@ namespace ts {
10134
10134
}
10135
10135
}
10136
10136
10137
- function createInferenceContext(callNode: CallLikeExpression, signature: Signature, inferUnionTypes: boolean, noInferenceType: Type ): InferenceContext {
10137
+ function createInferenceContext(callNode: CallLikeExpression, signature: Signature, flags: InferenceFlags ): InferenceContext {
10138
10138
return {
10139
10139
callNode,
10140
10140
signature,
10141
10141
inferences: map(signature.typeParameters, createInferenceInfo),
10142
- inferUnionTypes,
10143
- noInferenceType
10142
+ flags,
10144
10143
};
10145
10144
}
10146
10145
@@ -10160,8 +10159,7 @@ namespace ts {
10160
10159
callNode: context.callNode,
10161
10160
signature: context.signature,
10162
10161
inferences: map(context.inferences, cloneInferenceInfo),
10163
- inferUnionTypes: context.inferUnionTypes,
10164
- noInferenceType: silentNeverType
10162
+ flags: context.flags | InferenceFlags.NoDefault,
10165
10163
}
10166
10164
}
10167
10165
@@ -10243,10 +10241,6 @@ namespace ts {
10243
10241
}
10244
10242
}
10245
10243
10246
- function inferTypesWithContext(context: InferenceContext, originalSource: Type, originalTarget: Type) {
10247
- inferTypes(context.inferences, originalSource, originalTarget);
10248
- }
10249
-
10250
10244
function inferTypes(inferences: InferenceInfo[], originalSource: Type, originalTarget: Type, priority: InferencePriority = 0) {
10251
10245
let symbolStack: Symbol[];
10252
10246
let visited: Map<boolean>;
@@ -10315,13 +10309,10 @@ namespace ts {
10315
10309
}
10316
10310
for (const inference of inferences) {
10317
10311
if (target === inference.typeParameter) {
10318
- if (!inference.isFixed) {
10319
- // Any inferences that are made to a type parameter in a union type are inferior
10320
- // to inferences made to a flat (non-union) type. This is because if we infer to
10321
- // T | string[], we really don't know if we should be inferring to T or not (because
10322
- // the correct constituent on the target side could be string[]). Therefore, we put
10323
- // such inferior inferences into a secondary bucket, and only use them if the primary
10324
- // bucket is empty.
10312
+ // Even if an inference is marked as fixed, we can add candidates from inferences made
10313
+ // from the return type of generic functions (which only happens when no other candidates
10314
+ // are present).
10315
+ if (!inference.isFixed || priority & InferencePriority.ReturnType) {
10325
10316
if (!inference.candidates || priority < inference.priority) {
10326
10317
inference.candidates = [source];
10327
10318
inference.priority = priority;
@@ -10543,15 +10534,21 @@ namespace ts {
10543
10534
let inferenceSucceeded: boolean;
10544
10535
if (!inferredType) {
10545
10536
if (!inference.candidates && context.callNode && isExpression(context.callNode)) {
10537
+ // We have no inference candidates. Now attempt to get the contextual type for the call
10538
+ // expression associated with the context, and if a contextual type is available, infer
10539
+ // from that type to the return type of the call expression. For example, given a
10540
+ // 'function wrap<T, U>(cb: (x: T) => U): (x: T) => U' and a call expression
10541
+ // 'let f: (x: string) => number = wrap(s => s.length)', we infer from the declared type
10542
+ // of 'f' to the return type of 'wrap'.
10546
10543
const contextualType = getContextualType(context.callNode);
10547
10544
if (contextualType) {
10545
+ // We clone the contextual mapper to avoid disturbing a resolution in progress for an
10546
+ // outer call expression. Effectively we just want a snapshot of whatever has been
10547
+ // inferred for any outer call expression so far.
10548
10548
const mapper = cloneTypeMapper(getContextualMapper(context.callNode));
10549
10549
const instantiatedType = instantiateType(contextualType, mapper);
10550
10550
const returnType = getReturnTypeOfSignature(context.signature);
10551
- const saveFixed = inference.isFixed;
10552
- inference.isFixed = false;
10553
10551
inferTypes([inference], instantiatedType, returnType, InferencePriority.ReturnType);
10554
- inference.isFixed = saveFixed;
10555
10552
}
10556
10553
}
10557
10554
if (inference.candidates) {
@@ -10564,30 +10561,37 @@ namespace ts {
10564
10561
!hasPrimitiveConstraint(inference.typeParameter) &&
10565
10562
(inference.isFixed || !isTypeParameterAtTopLevel(getReturnTypeOfSignature(signature), inference.typeParameter));
10566
10563
const baseCandidates = widenLiteralTypes ? sameMap(inference.candidates, getWidenedLiteralType) : inference.candidates;
10567
- // Infer widened union or supertype, or the unknown type for no common supertype
10568
- const unionOrSuperType = context.inferUnionTypes ? getUnionType(baseCandidates, /*subtypeReduction*/ true) : getCommonSupertype(baseCandidates);
10564
+ // Infer widened union or supertype, or the unknown type for no common supertype. We infer union types
10565
+ // for inferences coming from return types in order to avoid common supertype failures.
10566
+ const unionOrSuperType = context.flags & InferenceFlags.InferUnionTypes || inference.priority & InferencePriority.ReturnType ?
10567
+ getUnionType(baseCandidates, /*subtypeReduction*/ true) : getCommonSupertype(baseCandidates);
10569
10568
inferredType = unionOrSuperType ? getWidenedType(unionOrSuperType) : unknownType;
10570
10569
inferenceSucceeded = !!unionOrSuperType;
10571
10570
}
10572
10571
else {
10573
- // Infer either the default or the empty object type when no inferences were
10574
- // made. It is important to remember that in this case, inference still
10575
- // succeeds, meaning there is no error for not having inference candidates. An
10576
- // inference error only occurs when there are *conflicting* candidates, i.e.
10577
- // candidates with no common supertype.
10578
- const defaultType = context.noInferenceType === silentNeverType ? undefined : getDefaultFromTypeParameter(inference.typeParameter);
10579
- if (defaultType) {
10580
- // Instantiate the default type. Any forward reference to a type
10581
- // parameter should be instantiated to the empty object type.
10582
- inferredType = instantiateType(defaultType,
10583
- combineTypeMappers(
10584
- createBackreferenceMapper(context.signature.typeParameters, index),
10585
- getInferenceMapper(context)));
10572
+ if (context.flags & InferenceFlags.NoDefault) {
10573
+ // We use silentNeverType as the wildcard that signals no inferences.
10574
+ inferredType = silentNeverType;
10586
10575
}
10587
10576
else {
10588
- inferredType = context.noInferenceType;
10577
+ // Infer either the default or the empty object type when no inferences were
10578
+ // made. It is important to remember that in this case, inference still
10579
+ // succeeds, meaning there is no error for not having inference candidates. An
10580
+ // inference error only occurs when there are *conflicting* candidates, i.e.
10581
+ // candidates with no common supertype.
10582
+ const defaultType = getDefaultFromTypeParameter(inference.typeParameter);
10583
+ if (defaultType) {
10584
+ // Instantiate the default type. Any forward reference to a type
10585
+ // parameter should be instantiated to the empty object type.
10586
+ inferredType = instantiateType(defaultType,
10587
+ combineTypeMappers(
10588
+ createBackreferenceMapper(context.signature.typeParameters, index),
10589
+ getInferenceMapper(context)));
10590
+ }
10591
+ else {
10592
+ inferredType = context.flags & InferenceFlags.AnyDefault ? anyType : emptyObjectType;
10593
+ }
10589
10594
}
10590
-
10591
10595
inferenceSucceeded = true;
10592
10596
}
10593
10597
inference.inferredType = inferredType;
@@ -14872,10 +14876,10 @@ namespace ts {
14872
14876
14873
14877
// Instantiate a generic signature in the context of a non-generic signature (section 3.8.5 in TypeScript spec)
14874
14878
function instantiateSignatureInContextOf(signature: Signature, contextualSignature: Signature, contextualMapper: TypeMapper): Signature {
14875
- const context = createInferenceContext(/*callNode*/ undefined, signature, /*inferUnionTypes*/ true, /*noInferenceType*/ emptyObjectType );
14879
+ const context = createInferenceContext(/*callNode*/ undefined, signature, InferenceFlags.InferUnionTypes );
14876
14880
forEachMatchingParameterType(contextualSignature, signature, (source, target) => {
14877
14881
// Type parameters from outer context referenced by source type are fixed by instantiation of the source type
14878
- inferTypesWithContext (context, instantiateType(source, contextualMapper), target);
14882
+ inferTypes (context.inferences , instantiateType(source, contextualMapper), target);
14879
14883
});
14880
14884
return getSignatureInstantiation(signature, getInferredTypes(context));
14881
14885
}
@@ -14910,7 +14914,7 @@ namespace ts {
14910
14914
if (thisType) {
14911
14915
const thisArgumentNode = getThisArgumentOfCall(node);
14912
14916
const thisArgumentType = thisArgumentNode ? checkExpression(thisArgumentNode) : voidType;
14913
- inferTypesWithContext (context, thisArgumentType, thisType);
14917
+ inferTypes (context.inferences , thisArgumentType, thisType);
14914
14918
}
14915
14919
14916
14920
// We perform two passes over the arguments. In the first pass we infer from all arguments, but use
@@ -14932,7 +14936,7 @@ namespace ts {
14932
14936
argType = checkExpressionWithContextualType(arg, paramType, mapper);
14933
14937
}
14934
14938
14935
- inferTypesWithContext (context, argType, paramType);
14939
+ inferTypes (context.inferences , argType, paramType);
14936
14940
}
14937
14941
}
14938
14942
@@ -14947,7 +14951,7 @@ namespace ts {
14947
14951
if (excludeArgument[i] === false) {
14948
14952
const arg = args[i];
14949
14953
const paramType = getTypeAtPosition(signature, i);
14950
- inferTypesWithContext (context, checkExpressionWithContextualType(arg, paramType, inferenceMapper), paramType);
14954
+ inferTypes (context.inferences , checkExpressionWithContextualType(arg, paramType, inferenceMapper), paramType);
14951
14955
}
14952
14956
}
14953
14957
}
@@ -15606,7 +15610,7 @@ namespace ts {
15606
15610
let candidate: Signature;
15607
15611
let typeArgumentsAreValid: boolean;
15608
15612
const inferenceContext = originalCandidate.typeParameters
15609
- ? createInferenceContext(node, originalCandidate, /*inferUnionTypes */ false, /*noInferenceType*/ isInJavaScriptFile(node) ? anyType : emptyObjectType )
15613
+ ? createInferenceContext(node, originalCandidate, /*flags */ isInJavaScriptFile(node) ? InferenceFlags.AnyDefault : 0 )
15610
15614
: undefined;
15611
15615
15612
15616
while (true) {
@@ -16192,7 +16196,7 @@ namespace ts {
16192
16196
for (let i = 0; i < len; i++) {
16193
16197
const declaration = <ParameterDeclaration>signature.parameters[i].valueDeclaration;
16194
16198
if (declaration.type) {
16195
- inferTypesWithContext (mapper.context, getTypeFromTypeNode(declaration.type), getTypeAtPosition(context, i));
16199
+ inferTypes (mapper.context.inferences , getTypeFromTypeNode(declaration.type), getTypeAtPosition(context, i));
16196
16200
}
16197
16201
}
16198
16202
}
@@ -16278,7 +16282,7 @@ namespace ts {
16278
16282
// T in the second overload so that we do not infer Base as a candidate for T
16279
16283
// (inferring Base would make type argument inference inconsistent between the two
16280
16284
// overloads).
16281
- inferTypesWithContext (mapper.context, links.type, instantiateType(contextualType, mapper));
16285
+ inferTypes (mapper.context.inferences , links.type, instantiateType(contextualType, mapper));
16282
16286
}
16283
16287
}
16284
16288
0 commit comments