@@ -3501,7 +3501,7 @@ namespace ts {
35013501
35023502        function findMatchingSignature(signatureList: Signature[], signature: Signature, partialMatch: boolean, ignoreReturnTypes: boolean): Signature {
35033503            for (const s of signatureList) {
3504-                 if (compareSignatures (s, signature, partialMatch, ignoreReturnTypes, compareTypes )) {
3504+                 if (compareSignaturesIdentical (s, signature, partialMatch, ignoreReturnTypes, compareTypesIdentical )) {
35053505                    return s;
35063506                }
35073507            }
@@ -4115,16 +4115,6 @@ namespace ts {
41154115            return signature.erasedSignatureCache;
41164116        }
41174117
4118-         function getAnyReturningErasedSignature(signature: Signature): Signature {
4119-             if (!signature.anyReturningErasedSignatureCache) {
4120-                 const erasedSignature = getErasedSignature(signature);
4121-                 const anyReturningErasedSignature = cloneSignature(erasedSignature);
4122-                 anyReturningErasedSignature.resolvedReturnType = anyType;
4123-                 signature.anyReturningErasedSignatureCache = anyReturningErasedSignature;
4124-             }
4125-             return signature.anyReturningErasedSignatureCache;
4126-         }
4127- 
41284118        function getOrCreateTypeFromSignature(signature: Signature): ObjectType {
41294119            // There are two ways to declare a construct signature, one is by declaring a class constructor
41304120            // using the constructor keyword, and the other is declaring a bare construct signature in an
@@ -4965,7 +4955,7 @@ namespace ts {
49654955            return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined);
49664956        }
49674957
4968-         function compareTypes (source: Type, target: Type): Ternary {
4958+         function compareTypesIdentical (source: Type, target: Type): Ternary {
49694959            return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined) ? Ternary.True : Ternary.False;
49704960        }
49714961
@@ -4985,10 +4975,53 @@ namespace ts {
49854975            return checkTypeRelatedTo(source, target, assignableRelation, errorNode, headMessage, containingMessageChain);
49864976        }
49874977
4988-         function isSignatureAssignableTo(source: Signature, target: Signature): boolean {
4989-             const sourceType = getOrCreateTypeFromSignature(source);
4990-             const targetType = getOrCreateTypeFromSignature(target);
4991-             return checkTypeRelatedTo(sourceType, targetType, assignableRelation, /*errorNode*/ undefined);
4978+         /**
4979+          * See signatureRelatedTo, compareSignaturesIdentical
4980+          */
4981+         function isSignatureAssignableTo(source: Signature, target: Signature, ignoreReturnTypes: boolean): boolean {
4982+             // TODO (drosen): De-duplicate code between related functions.
4983+             if (source === target) {
4984+                 return true;
4985+             }
4986+             if (!target.hasRestParameter && source.minArgumentCount > target.parameters.length) {
4987+                 return false;
4988+             }
4989+ 
4990+             // Spec 1.0 Section 3.8.3 & 3.8.4:
4991+             // M and N (the signatures) are instantiated using type Any as the type argument for all type parameters declared by M and N
4992+             source = getErasedSignature(source);
4993+             target = getErasedSignature(target);
4994+ 
4995+             const sourceMax = getNumNonRestParameters(source);
4996+             const targetMax = getNumNonRestParameters(target);
4997+             const checkCount = getNumParametersToCheckForSignatureRelatability(source, sourceMax, target, targetMax);
4998+             for (let i = 0; i < checkCount; i++) {
4999+                 const s = i < sourceMax ? getTypeOfSymbol(source.parameters[i]) : getRestTypeOfSignature(source);
5000+                 const t = i < targetMax ? getTypeOfSymbol(target.parameters[i]) : getRestTypeOfSignature(target);
5001+                 const related = isTypeAssignableTo(t, s) || isTypeAssignableTo(s, t);
5002+                 if (!related) {
5003+                     return false;
5004+                 }
5005+             }
5006+ 
5007+             if (!ignoreReturnTypes) {
5008+                 const targetReturnType = getReturnTypeOfSignature(target);
5009+                 if (targetReturnType === voidType) {
5010+                     return true;
5011+                 }
5012+                 const sourceReturnType = getReturnTypeOfSignature(source);
5013+ 
5014+                 // The following block preserves behavior forbidding boolean returning functions from being assignable to type guard returning functions
5015+                 if (targetReturnType.flags & TypeFlags.PredicateType && (targetReturnType as PredicateType).predicate.kind === TypePredicateKind.Identifier) {
5016+                     if (!(sourceReturnType.flags & TypeFlags.PredicateType)) {
5017+                         return false;
5018+                     }
5019+                 }
5020+ 
5021+                 return isTypeAssignableTo(sourceReturnType, targetReturnType);
5022+             }
5023+ 
5024+             return true;
49925025        }
49935026
49945027        function isImplementationCompatibleWithOverload(implementation: Signature, overload: Signature): boolean {
@@ -5002,15 +5035,35 @@ namespace ts {
50025035                || checkTypeRelatedTo(targetReturnType, sourceReturnType, assignableRelation, /*errorNode*/ undefined)
50035036                || checkTypeRelatedTo(sourceReturnType, targetReturnType, assignableRelation, /*errorNode*/ undefined)) {
50045037
5005-                 // The return types are compatible, so create versions of the signature with 'any' as the return type.
5006-                 // We need to do this so that we can check assignability while disregarding the return type.
5007-                 const anyReturningSource = getAnyReturningErasedSignature(implementation);
5008-                 const anyReturningTarget = getAnyReturningErasedSignature(overload);
5038+                 return isSignatureAssignableTo(erasedSource, erasedTarget, /*ignoreReturnTypes*/ true);
5039+             }
50095040
5010-                 // Create object types to actually perform relation checks.
5011-                 const anyReturningSourceType = getOrCreateTypeFromSignature(anyReturningSource);
5012-                 const anyReturningTargetType = getOrCreateTypeFromSignature(anyReturningTarget);
5013-                 return checkTypeRelatedTo(anyReturningSourceType, anyReturningTargetType, assignableRelation, /*errorNode*/ undefined);
5041+             return false;
5042+         }
5043+         
5044+         function getNumNonRestParameters(signature: Signature) {
5045+             const numParams = signature.parameters.length;
5046+             return signature.hasRestParameter ?
5047+                 numParams - 1 :
5048+                 numParams;
5049+         }
5050+ 
5051+         function getNumParametersToCheckForSignatureRelatability(source: Signature, sourceNonRestParamCount: number, target: Signature, targetNonRestParamCount: number) {
5052+             if (source.hasRestParameter === target.hasRestParameter) {
5053+                 if (source.hasRestParameter) {
5054+                     // If both have rest parameters, get the max and add 1 to
5055+                     // compensate for the rest parameter.
5056+                     return Math.max(sourceNonRestParamCount, targetNonRestParamCount) + 1;
5057+                 }
5058+                 else {
5059+                     return Math.min(sourceNonRestParamCount, targetNonRestParamCount);
5060+                 }
5061+             }
5062+             else {
5063+                 // Return the count for whichever signature doesn't have rest parameters.
5064+                 return source.hasRestParameter ?
5065+                     targetNonRestParamCount :
5066+                     sourceNonRestParamCount;
50145067            }
50155068        }
50165069
@@ -5645,7 +5698,11 @@ namespace ts {
56455698                }
56465699            }
56475700
5701+             /**
5702+              * See signatureAssignableTo, signatureAssignableTo
5703+              */
56485704            function signatureRelatedTo(source: Signature, target: Signature, reportErrors: boolean): Ternary {
5705+                 // TODO (drosen): De-duplicate code between related functions.
56495706                if (source === target) {
56505707                    return Ternary.True;
56515708                }
@@ -5697,10 +5754,12 @@ namespace ts {
56975754                }
56985755
56995756                const targetReturnType = getReturnTypeOfSignature(target);
5700-                 if (targetReturnType === voidType) return result;
5757+                 if (targetReturnType === voidType) {
5758+                     return result;
5759+                 }
57015760                const sourceReturnType = getReturnTypeOfSignature(source);
57025761
5703-                 // The follow  block preserves old  behavior forbidding boolean returning functions from being assignable to type guard returning functions
5762+                 // The following  block preserves behavior forbidding boolean returning functions from being assignable to type guard returning functions
57045763                if (targetReturnType.flags & TypeFlags.PredicateType && (targetReturnType as PredicateType).predicate.kind === TypePredicateKind.Identifier) {
57055764                    if (!(sourceReturnType.flags & TypeFlags.PredicateType)) {
57065765                        if (reportErrors) {
@@ -5721,7 +5780,7 @@ namespace ts {
57215780                }
57225781                let result = Ternary.True;
57235782                for (let i = 0, len = sourceSignatures.length; i < len; ++i) {
5724-                     const related = compareSignatures (sourceSignatures[i], targetSignatures[i], /*partialMatch*/ false, /*ignoreReturnTypes*/ false, isRelatedTo);
5783+                     const related = compareSignaturesIdentical (sourceSignatures[i], targetSignatures[i], /*partialMatch*/ false, /*ignoreReturnTypes*/ false, isRelatedTo);
57255784                    if (!related) {
57265785                        return Ternary.False;
57275786                    }
@@ -5833,7 +5892,7 @@ namespace ts {
58335892        }
58345893
58355894        function isPropertyIdenticalTo(sourceProp: Symbol, targetProp: Symbol): boolean {
5836-             return compareProperties(sourceProp, targetProp, compareTypes ) !== Ternary.False;
5895+             return compareProperties(sourceProp, targetProp, compareTypesIdentical ) !== Ternary.False;
58375896        }
58385897
58395898        function compareProperties(sourceProp: Symbol, targetProp: Symbol, compareTypes: (source: Type, target: Type) => Ternary): Ternary {
@@ -5880,7 +5939,11 @@ namespace ts {
58805939            return false;
58815940        }
58825941
5883-         function compareSignatures(source: Signature, target: Signature, partialMatch: boolean, ignoreReturnTypes: boolean, compareTypes: (s: Type, t: Type) => Ternary): Ternary {
5942+         /**
5943+          * See signatureRelatedTo, compareSignaturesIdentical
5944+          */
5945+         function compareSignaturesIdentical(source: Signature, target: Signature, partialMatch: boolean, ignoreReturnTypes: boolean, compareTypes: (s: Type, t: Type) => Ternary): Ternary {
5946+             // TODO (drosen): De-duplicate code between related functions.
58845947            if (source === target) {
58855948                return Ternary.True;
58865949            }
@@ -7571,7 +7634,7 @@ namespace ts {
75717634                        // This signature will contribute to contextual union signature
75727635                        signatureList = [signature];
75737636                    }
7574-                     else if (!compareSignatures (signatureList[0], signature, /*partialMatch*/ false, /*ignoreReturnTypes*/ true, compareTypes )) {
7637+                     else if (!compareSignaturesIdentical (signatureList[0], signature, /*partialMatch*/ false, /*ignoreReturnTypes*/ true, compareTypesIdentical )) {
75757638                        // Signatures aren't identical, do not use
75767639                        return undefined;
75777640                    }
@@ -11564,7 +11627,7 @@ namespace ts {
1156411627            }
1156511628
1156611629            for (const otherSignature of signaturesToCheck) {
11567-                 if (!otherSignature.hasStringLiterals && isSignatureAssignableTo(signature, otherSignature)) {
11630+                 if (!otherSignature.hasStringLiterals && isSignatureAssignableTo(signature, otherSignature, /*ignoreReturnTypes*/ false )) {
1156811631                    return;
1156911632                }
1157011633            }
0 commit comments