Skip to content

Commit 475b103

Browse files
committed
Only promote type parameters when they're referenced in input positions
1 parent ba95fca commit 475b103

File tree

1 file changed

+41
-33
lines changed

1 file changed

+41
-33
lines changed

src/compiler/checker.ts

Lines changed: 41 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -14259,7 +14259,7 @@ namespace ts {
1425914259
}
1426014260
}
1426114261

14262-
function forEachMatchingParameterType(source: Signature, target: Signature, callback: (s: Type, t: Type) => void) {
14262+
function applyToParameterTypes(source: Signature, target: Signature, callback: (s: Type, t: Type) => void) {
1426314263
const sourceCount = getParameterCount(source);
1426414264
const targetCount = getParameterCount(target);
1426514265
const sourceRestType = getEffectiveRestType(source);
@@ -14281,6 +14281,18 @@ namespace ts {
1428114281
}
1428214282
}
1428314283

14284+
function applyToReturnTypes(source: Signature, target: Signature, callback: (s: Type, t: Type) => void) {
14285+
const sourceTypePredicate = getTypePredicateOfSignature(source);
14286+
const targetTypePredicate = getTypePredicateOfSignature(target);
14287+
if (sourceTypePredicate && targetTypePredicate && sourceTypePredicate.kind === targetTypePredicate.kind &&
14288+
(sourceTypePredicate.kind === TypePredicateKind.This || sourceTypePredicate.parameterIndex === (<IdentifierTypePredicate>targetTypePredicate).parameterIndex)) {
14289+
callback(sourceTypePredicate.type, targetTypePredicate.type);
14290+
}
14291+
else {
14292+
callback(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target));
14293+
}
14294+
}
14295+
1428414296
function createInferenceContext(typeParameters: ReadonlyArray<TypeParameter>, signature: Signature | undefined, flags: InferenceFlags, compareTypes?: TypeComparer): InferenceContext {
1428514297
return createInferenceContextWorker(typeParameters.map(createInferenceInfo), signature, flags, compareTypes || compareTypesAssignable);
1428614298
}
@@ -14900,17 +14912,10 @@ namespace ts {
1490014912
const kind = target.declaration ? target.declaration.kind : SyntaxKind.Unknown;
1490114913
// Once we descend into a bivariant signature we remain bivariant for all nested inferences
1490214914
bivariant = bivariant || kind === SyntaxKind.MethodDeclaration || kind === SyntaxKind.MethodSignature || kind === SyntaxKind.Constructor;
14903-
forEachMatchingParameterType(source, target, inferFromContravariantTypes);
14915+
applyToParameterTypes(source, target, inferFromContravariantTypes);
1490414916
bivariant = saveBivariant;
1490514917
}
14906-
const sourceTypePredicate = getTypePredicateOfSignature(source);
14907-
const targetTypePredicate = getTypePredicateOfSignature(target);
14908-
if (sourceTypePredicate && targetTypePredicate && sourceTypePredicate.kind === targetTypePredicate.kind) {
14909-
inferFromTypes(sourceTypePredicate.type, targetTypePredicate.type);
14910-
}
14911-
else {
14912-
inferFromTypes(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target));
14913-
}
14918+
applyToReturnTypes(source, target, inferFromTypes);
1491414919
}
1491514920

1491614921
function inferFromIndexTypes(source: Type, target: Type) {
@@ -20137,18 +20142,14 @@ namespace ts {
2013720142
const restType = getEffectiveRestType(contextualSignature);
2013820143
const mapper = inferenceContext && (restType && restType.flags & TypeFlags.TypeParameter ? inferenceContext.nonFixingMapper : inferenceContext.mapper);
2013920144
const sourceSignature = mapper ? instantiateSignature(contextualSignature, mapper) : contextualSignature;
20140-
forEachMatchingParameterType(sourceSignature, signature, (source, target) => {
20145+
applyToParameterTypes(sourceSignature, signature, (source, target) => {
2014120146
// Type parameters from outer context referenced by source type are fixed by instantiation of the source type
2014220147
inferTypes(context.inferences, source, target);
2014320148
});
2014420149
if (!inferenceContext) {
20145-
inferTypes(context.inferences, getReturnTypeOfSignature(contextualSignature), getReturnTypeOfSignature(signature), InferencePriority.ReturnType);
20146-
const signaturePredicate = getTypePredicateOfSignature(signature);
20147-
const contextualPredicate = getTypePredicateOfSignature(sourceSignature);
20148-
if (signaturePredicate && contextualPredicate && signaturePredicate.kind === contextualPredicate.kind &&
20149-
(signaturePredicate.kind === TypePredicateKind.This || signaturePredicate.parameterIndex === (contextualPredicate as IdentifierTypePredicate).parameterIndex)) {
20150-
inferTypes(context.inferences, contextualPredicate.type, signaturePredicate.type, InferencePriority.ReturnType);
20151-
}
20150+
applyToReturnTypes(contextualSignature, signature, (source, target) => {
20151+
inferTypes(context.inferences, source, target, InferencePriority.ReturnType);
20152+
});
2015220153
}
2015320154
return getSignatureInstantiation(signature, getInferredTypes(context), isInJSFile(contextualSignature.declaration));
2015420155
}
@@ -23465,23 +23466,30 @@ namespace ts {
2346523466
// potentially add inferred type parameters to the outer function return type.
2346623467
const returnSignature = context.signature && getSingleCallSignature(getReturnTypeOfSignature(context.signature));
2346723468
if (returnSignature && !returnSignature.typeParameters && !every(context.inferences, hasInferenceCandidates)) {
23468-
// Instantiate the expression type with its own type parameters as type arguments. This
23469-
// ensures that the type parameters are not erased to type any during type inference such
23470-
// that they can be inferred as actual types.
23469+
// Instantiate the signature with its own type parameters as type arguments, possibly
23470+
// renaming the type parameters to ensure they have unique names.
2347123471
const uniqueTypeParameters = getUniqueTypeParameters(context, signature.typeParameters);
23472-
const strippedType = getOrCreateTypeFromSignature(getSignatureInstantiationWithoutFillingInTypeArguments(signature, uniqueTypeParameters));
23473-
// Infer from the stripped expression type to the contextual type starting with an empty
23474-
// set of inference candidates.
23472+
const instantiatedSignature = getSignatureInstantiationWithoutFillingInTypeArguments(signature, uniqueTypeParameters);
23473+
// Infer from the parameters of the instantiated signature to the parameters of the
23474+
// contextual signature starting with an empty set of inference candidates.
2347523475
const inferences = map(context.inferences, info => createInferenceInfo(info.typeParameter));
23476-
inferTypes(inferences, strippedType, contextualType);
23477-
// If we produced some inference candidates and if the type parameters for which we produced
23478-
// candidates do not already have existing inferences, we adopt the new inference candidates and
23479-
// add the type parameters of the expression type to the set of inferred type parameters for
23480-
// the outer function return type.
23481-
if (some(inferences, hasInferenceCandidates) && !hasOverlappingInferences(context.inferences, inferences)) {
23482-
mergeInferences(context.inferences, inferences);
23483-
context.inferredTypeParameters = concatenate(context.inferredTypeParameters, uniqueTypeParameters);
23484-
return strippedType;
23476+
applyToParameterTypes(instantiatedSignature, contextualSignature, (source, target) => {
23477+
inferTypes(inferences, source, target);
23478+
});
23479+
if (some(inferences, hasInferenceCandidates)) {
23480+
// We have inference candidates, indicating that one or more type parameters are referenced
23481+
// in the parameter types of the contextual signature. Now also infer from the return type.
23482+
applyToReturnTypes(instantiatedSignature, contextualSignature, (source, target) => {
23483+
inferTypes(inferences, source, target);
23484+
});
23485+
// If the type parameters for which we produced candidates do not have any inferences yet,
23486+
// we adopt the new inference candidates and add the type parameters of the expression type
23487+
// to the set of inferred type parameters for the outer function return type.
23488+
if (!hasOverlappingInferences(context.inferences, inferences)) {
23489+
mergeInferences(context.inferences, inferences);
23490+
context.inferredTypeParameters = concatenate(context.inferredTypeParameters, uniqueTypeParameters);
23491+
return getOrCreateTypeFromSignature(instantiatedSignature);
23492+
}
2348523493
}
2348623494
}
2348723495
return getOrCreateTypeFromSignature(instantiateSignatureInContextOf(signature, contextualSignature, context));

0 commit comments

Comments
 (0)