@@ -8550,11 +8550,16 @@ namespace ts {
85508550 isInJSFile(signature.declaration));
85518551 }
85528552
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+
85538558 function getBaseSignature(signature: Signature) {
85548559 const typeParameters = signature.typeParameters;
85558560 if (typeParameters) {
85568561 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);
85588563 return instantiateSignature(signature, createTypeMapper(typeParameters, baseConstraints), /*eraseTypeParameters*/ true);
85598564 }
85608565 return signature;
@@ -13392,35 +13397,33 @@ namespace ts {
1339213397 let result = Ternary.True;
1339313398 const saveErrorInfo = errorInfo;
1339413399
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;
1340113406 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);
1340313415 if (!related) {
1340413416 return Ternary.False;
1340513417 }
1340613418 result &= related;
1340713419 }
1340813420 }
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- }
1341813421 else {
1341913422 outer: for (const t of targetSignatures) {
1342013423 // Only elaborate errors from the first failure
1342113424 let shouldElaborateErrors = reportErrors;
1342213425 for (const s of sourceSignatures) {
13423- const related = signatureRelatedTo(s, t, /*erase*/ true , shouldElaborateErrors);
13426+ const related = signatureRelatedTo(getErasedSignature(s), getErasedSignature(t) , shouldElaborateErrors);
1342413427 if (related) {
1342513428 result &= related;
1342613429 errorInfo = saveErrorInfo;
@@ -13443,9 +13446,8 @@ namespace ts {
1344313446 /**
1344413447 * See signatureAssignableTo, compareSignaturesIdentical
1344513448 */
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);
1344913451 }
1345013452
1345113453 function signaturesIdenticalTo(source: Type, target: Type, kind: SignatureKind): Ternary {
0 commit comments