@@ -8408,10 +8408,9 @@ namespace ts {
8408
8408
return Ternary.False;
8409
8409
}
8410
8410
8411
- // Spec 1.0 Section 3.8.3 & 3.8.4:
8412
- // M and N (the signatures) are instantiated using type Any as the type argument for all type parameters declared by M and N
8413
- source = getErasedSignature(source);
8414
- target = getErasedSignature(target);
8411
+ if (source.typeParameters) {
8412
+ source = instantiateSignatureInContextOf(source, target);
8413
+ }
8415
8414
8416
8415
let result = Ternary.True;
8417
8416
@@ -9446,23 +9445,32 @@ namespace ts {
9446
9445
const saveErrorInfo = errorInfo;
9447
9446
9448
9447
if (getObjectFlags(source) & ObjectFlags.Instantiated && getObjectFlags(target) & ObjectFlags.Instantiated && source.symbol === target.symbol) {
9449
- // We instantiations of the same anonymous type (which typically will be the type of a method).
9450
- // Simply do a pairwise comparison of the signatures in the two signature lists instead of the
9451
- // much more expensive N * M comparison matrix we explore below.
9448
+ // We have instantiations of the same anonymous type (which typically will be the type of a
9449
+ // method). Simply do a pairwise comparison of the signatures in the two signature lists instead
9450
+ // of the much more expensive N * M comparison matrix we explore below. We erase type parameters
9451
+ // as they are known to always be the same.
9452
9452
for (let i = 0; i < targetSignatures.length; i++) {
9453
- const related = signatureRelatedTo(sourceSignatures[i], targetSignatures[i], reportErrors);
9453
+ const related = signatureRelatedTo(sourceSignatures[i], targetSignatures[i], /*erase*/ true, reportErrors);
9454
9454
if (!related) {
9455
9455
return Ternary.False;
9456
9456
}
9457
9457
result &= related;
9458
9458
}
9459
9459
}
9460
+ else if (sourceSignatures.length === 1 && targetSignatures.length === 1) {
9461
+ // For pure functions (functions with a single signature) we only erase type parameters for
9462
+ // the comparable relation. Otherwise, if the source signature is generic, we instantiate it
9463
+ // in the context of the target signature before checking the relationship. Ideally we'd do
9464
+ // this regardless of the number of signatures, but the potential costs are prohibitive due
9465
+ // to the quadratic nature of the logic below.
9466
+ result = signatureRelatedTo(sourceSignatures[0], targetSignatures[0], /*erase*/ relation === comparableRelation, reportErrors);
9467
+ }
9460
9468
else {
9461
9469
outer: for (const t of targetSignatures) {
9462
9470
// Only elaborate errors from the first failure
9463
9471
let shouldElaborateErrors = reportErrors;
9464
9472
for (const s of sourceSignatures) {
9465
- const related = signatureRelatedTo(s, t, shouldElaborateErrors);
9473
+ const related = signatureRelatedTo(s, t, /*erase*/ true, shouldElaborateErrors);
9466
9474
if (related) {
9467
9475
result &= related;
9468
9476
errorInfo = saveErrorInfo;
@@ -9485,8 +9493,9 @@ namespace ts {
9485
9493
/**
9486
9494
* See signatureAssignableTo, compareSignaturesIdentical
9487
9495
*/
9488
- function signatureRelatedTo(source: Signature, target: Signature, reportErrors: boolean): Ternary {
9489
- return compareSignaturesRelated(source, target, /*checkAsCallback*/ false, /*ignoreReturnTypes*/ false, reportErrors, reportError, isRelatedTo);
9496
+ function signatureRelatedTo(source: Signature, target: Signature, erase: boolean, reportErrors: boolean): Ternary {
9497
+ return compareSignaturesRelated(erase ? getErasedSignature(source) : source, erase ? getErasedSignature(target) : target,
9498
+ /*checkAsCallback*/ false, /*ignoreReturnTypes*/ false, reportErrors, reportError, isRelatedTo);
9490
9499
}
9491
9500
9492
9501
function signaturesIdenticalTo(source: Type, target: Type, kind: SignatureKind): Ternary {
@@ -14915,12 +14924,15 @@ namespace ts {
14915
14924
}
14916
14925
14917
14926
// Instantiate a generic signature in the context of a non-generic signature (section 3.8.5 in TypeScript spec)
14918
- function instantiateSignatureInContextOf(signature: Signature, contextualSignature: Signature, contextualMapper: TypeMapper): Signature {
14927
+ function instantiateSignatureInContextOf(signature: Signature, contextualSignature: Signature, contextualMapper? : TypeMapper): Signature {
14919
14928
const context = createInferenceContext(signature, InferenceFlags.InferUnionTypes);
14920
14929
forEachMatchingParameterType(contextualSignature, signature, (source, target) => {
14921
14930
// Type parameters from outer context referenced by source type are fixed by instantiation of the source type
14922
- inferTypes(context.inferences, instantiateType(source, contextualMapper), target);
14931
+ inferTypes(context.inferences, instantiateType(source, contextualMapper || identityMapper ), target);
14923
14932
});
14933
+ if (!contextualMapper) {
14934
+ inferTypes(context.inferences, getReturnTypeOfSignature(contextualSignature), getReturnTypeOfSignature(signature), InferencePriority.ReturnType);
14935
+ }
14924
14936
return getSignatureInstantiation(signature, getInferredTypes(context));
14925
14937
}
14926
14938
0 commit comments