@@ -8550,11 +8550,16 @@ namespace ts {
8550
8550
isInJSFile(signature.declaration));
8551
8551
}
8552
8552
8553
+ function getErasedConstraint(type: Type, typeParameters: readonly TypeParameter[]): Type | undefined {
8554
+ const constraint = getConstraintOfType(type);
8555
+ return constraint && contains(typeParameters, constraint) ? getErasedConstraint(constraint, typeParameters) : constraint;
8556
+ }
8557
+
8553
8558
function getBaseSignature(signature: Signature) {
8554
8559
const typeParameters = signature.typeParameters;
8555
8560
if (typeParameters) {
8556
8561
const typeEraser = createTypeEraser(typeParameters);
8557
- const baseConstraints = map(typeParameters, tp => instantiateType(getBaseConstraintOfType (tp), typeEraser) || unknownType);
8562
+ const baseConstraints = map(typeParameters, tp => instantiateType(getErasedConstraint (tp, typeParameters ), typeEraser) || unknownType);
8558
8563
return instantiateSignature(signature, createTypeMapper(typeParameters, baseConstraints), /*eraseTypeParameters*/ true);
8559
8564
}
8560
8565
return signature;
@@ -13392,35 +13397,33 @@ namespace ts {
13392
13397
let result = Ternary.True;
13393
13398
const saveErrorInfo = errorInfo;
13394
13399
13395
- if ( getObjectFlags(source) & ObjectFlags.Instantiated && getObjectFlags(target) & ObjectFlags.Instantiated && source.symbol === target.symbol) {
13396
- // We have instantiations of the same anonymous type (which typically will be the type of a
13397
- // method). Simply do a pairwise comparison of the signatures in the two signature lists instead
13398
- // of the much more expensive N * M comparison matrix we explore below. We instantiate type
13399
- // parameters to their constraints because, whereas the type parameters are known to be the same,
13400
- // the constraints might differ if they reference outer type parameters.
13400
+ const sameSignatureInstantiations = getObjectFlags(source) & ObjectFlags.Instantiated && getObjectFlags(target) & ObjectFlags.Instantiated && source.symbol === target.symbol;
13401
+ if (sameSignatureInstantiations || sourceSignatures.length === 1 && targetSignatures.length === 1) {
13402
+ // We have instantiations of the same anonymous type (which typically will be the type of a method)
13403
+ // or we have non-overloaded signatures. Simply do a pairwise comparison of the signatures in the
13404
+ // two signature lists instead of the much more expensive N * M comparison matrix we explore below.
13405
+ const eraseGenerics = relation === comparableRelation || !!compilerOptions.noStrictGenericChecks;
13401
13406
for (let i = 0; i < targetSignatures.length; i++) {
13402
- const related = signatureRelatedTo(getBaseSignature(sourceSignatures[i]), getBaseSignature(targetSignatures[i]), /*erase*/ false, reportErrors);
13407
+ const s = sourceSignatures[i];
13408
+ const t = targetSignatures[i];
13409
+ // We erase type parameters for the comparable relation or when strict checks are disabled.
13410
+ // Otherwise, when we have instantiations of the same anonymous type, we instantiate target
13411
+ // type parameters to their constraints because the type parameters are known to be the same.
13412
+ const effectiveSource = eraseGenerics ? getErasedSignature(s) : s;
13413
+ const effectiveTarget = eraseGenerics ? getErasedSignature(t) : sameSignatureInstantiations ? getBaseSignature(t) : t;
13414
+ const related = signatureRelatedTo(effectiveSource, effectiveTarget, reportErrors);
13403
13415
if (!related) {
13404
13416
return Ternary.False;
13405
13417
}
13406
13418
result &= related;
13407
13419
}
13408
13420
}
13409
- else if (sourceSignatures.length === 1 && targetSignatures.length === 1) {
13410
- // For simple functions (functions with a single signature) we only erase type parameters for
13411
- // the comparable relation. Otherwise, if the source signature is generic, we instantiate it
13412
- // in the context of the target signature before checking the relationship. Ideally we'd do
13413
- // this regardless of the number of signatures, but the potential costs are prohibitive due
13414
- // to the quadratic nature of the logic below.
13415
- const eraseGenerics = relation === comparableRelation || !!compilerOptions.noStrictGenericChecks;
13416
- result = signatureRelatedTo(sourceSignatures[0], targetSignatures[0], eraseGenerics, reportErrors);
13417
- }
13418
13421
else {
13419
13422
outer: for (const t of targetSignatures) {
13420
13423
// Only elaborate errors from the first failure
13421
13424
let shouldElaborateErrors = reportErrors;
13422
13425
for (const s of sourceSignatures) {
13423
- const related = signatureRelatedTo(s, t, /*erase*/ true , shouldElaborateErrors);
13426
+ const related = signatureRelatedTo(getErasedSignature(s), getErasedSignature(t) , shouldElaborateErrors);
13424
13427
if (related) {
13425
13428
result &= related;
13426
13429
errorInfo = saveErrorInfo;
@@ -13443,9 +13446,8 @@ namespace ts {
13443
13446
/**
13444
13447
* See signatureAssignableTo, compareSignaturesIdentical
13445
13448
*/
13446
- function signatureRelatedTo(source: Signature, target: Signature, erase: boolean, reportErrors: boolean): Ternary {
13447
- return compareSignaturesRelated(erase ? getErasedSignature(source) : source, erase ? getErasedSignature(target) : target,
13448
- CallbackCheck.None, /*ignoreReturnTypes*/ false, reportErrors, reportError, isRelatedTo);
13449
+ function signatureRelatedTo(source: Signature, target: Signature, reportErrors: boolean): Ternary {
13450
+ return compareSignaturesRelated(source, target, CallbackCheck.None, /*ignoreReturnTypes*/ false, reportErrors, reportError, isRelatedTo);
13449
13451
}
13450
13452
13451
13453
function signaturesIdenticalTo(source: Type, target: Type, kind: SignatureKind): Ternary {
0 commit comments