@@ -3507,7 +3507,7 @@ namespace ts {
35073507
35083508 function findMatchingSignature(signatureList: Signature[], signature: Signature, partialMatch: boolean, ignoreReturnTypes: boolean): Signature {
35093509 for (const s of signatureList) {
3510- if (compareSignatures (s, signature, partialMatch, ignoreReturnTypes, compareTypes )) {
3510+ if (compareSignaturesIdentical (s, signature, partialMatch, ignoreReturnTypes, compareTypesIdentical )) {
35113511 return s;
35123512 }
35133513 }
@@ -4959,7 +4959,7 @@ namespace ts {
49594959 return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined);
49604960 }
49614961
4962- function compareTypes (source: Type, target: Type): Ternary {
4962+ function compareTypesIdentical (source: Type, target: Type): Ternary {
49634963 return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined) ? Ternary.True : Ternary.False;
49644964 }
49654965
@@ -4979,10 +4979,96 @@ namespace ts {
49794979 return checkTypeRelatedTo(source, target, assignableRelation, errorNode, headMessage, containingMessageChain);
49804980 }
49814981
4982- function isSignatureAssignableTo(source: Signature, target: Signature): boolean {
4983- const sourceType = getOrCreateTypeFromSignature(source);
4984- const targetType = getOrCreateTypeFromSignature(target);
4985- return checkTypeRelatedTo(sourceType, targetType, assignableRelation, /*errorNode*/ undefined);
4982+ /**
4983+ * See signatureRelatedTo, compareSignaturesIdentical
4984+ */
4985+ function isSignatureAssignableTo(source: Signature, target: Signature, ignoreReturnTypes: boolean): boolean {
4986+ // TODO (drosen): De-duplicate code between related functions.
4987+ if (source === target) {
4988+ return true;
4989+ }
4990+ if (!target.hasRestParameter && source.minArgumentCount > target.parameters.length) {
4991+ return false;
4992+ }
4993+
4994+ // Spec 1.0 Section 3.8.3 & 3.8.4:
4995+ // M and N (the signatures) are instantiated using type Any as the type argument for all type parameters declared by M and N
4996+ source = getErasedSignature(source);
4997+ target = getErasedSignature(target);
4998+
4999+ const sourceMax = getNumNonRestParameters(source);
5000+ const targetMax = getNumNonRestParameters(target);
5001+ const checkCount = getNumParametersToCheckForSignatureRelatability(source, sourceMax, target, targetMax);
5002+ for (let i = 0; i < checkCount; i++) {
5003+ const s = i < sourceMax ? getTypeOfSymbol(source.parameters[i]) : getRestTypeOfSignature(source);
5004+ const t = i < targetMax ? getTypeOfSymbol(target.parameters[i]) : getRestTypeOfSignature(target);
5005+ const related = isTypeAssignableTo(t, s) || isTypeAssignableTo(s, t);
5006+ if (!related) {
5007+ return false;
5008+ }
5009+ }
5010+
5011+ if (!ignoreReturnTypes) {
5012+ const targetReturnType = getReturnTypeOfSignature(target);
5013+ if (targetReturnType === voidType) {
5014+ return true;
5015+ }
5016+ const sourceReturnType = getReturnTypeOfSignature(source);
5017+
5018+ // The following block preserves behavior forbidding boolean returning functions from being assignable to type guard returning functions
5019+ if (targetReturnType.flags & TypeFlags.PredicateType && (targetReturnType as PredicateType).predicate.kind === TypePredicateKind.Identifier) {
5020+ if (!(sourceReturnType.flags & TypeFlags.PredicateType)) {
5021+ return false;
5022+ }
5023+ }
5024+
5025+ return isTypeAssignableTo(sourceReturnType, targetReturnType);
5026+ }
5027+
5028+ return true;
5029+ }
5030+
5031+ function isImplementationCompatibleWithOverload(implementation: Signature, overload: Signature): boolean {
5032+ const erasedSource = getErasedSignature(implementation);
5033+ const erasedTarget = getErasedSignature(overload);
5034+
5035+ // First see if the return types are compatible in either direction.
5036+ const sourceReturnType = getReturnTypeOfSignature(erasedSource);
5037+ const targetReturnType = getReturnTypeOfSignature(erasedTarget);
5038+ if (targetReturnType === voidType
5039+ || checkTypeRelatedTo(targetReturnType, sourceReturnType, assignableRelation, /*errorNode*/ undefined)
5040+ || checkTypeRelatedTo(sourceReturnType, targetReturnType, assignableRelation, /*errorNode*/ undefined)) {
5041+
5042+ return isSignatureAssignableTo(erasedSource, erasedTarget, /*ignoreReturnTypes*/ true);
5043+ }
5044+
5045+ return false;
5046+ }
5047+
5048+ function getNumNonRestParameters(signature: Signature) {
5049+ const numParams = signature.parameters.length;
5050+ return signature.hasRestParameter ?
5051+ numParams - 1 :
5052+ numParams;
5053+ }
5054+
5055+ function getNumParametersToCheckForSignatureRelatability(source: Signature, sourceNonRestParamCount: number, target: Signature, targetNonRestParamCount: number) {
5056+ if (source.hasRestParameter === target.hasRestParameter) {
5057+ if (source.hasRestParameter) {
5058+ // If both have rest parameters, get the max and add 1 to
5059+ // compensate for the rest parameter.
5060+ return Math.max(sourceNonRestParamCount, targetNonRestParamCount) + 1;
5061+ }
5062+ else {
5063+ return Math.min(sourceNonRestParamCount, targetNonRestParamCount);
5064+ }
5065+ }
5066+ else {
5067+ // Return the count for whichever signature doesn't have rest parameters.
5068+ return source.hasRestParameter ?
5069+ targetNonRestParamCount :
5070+ sourceNonRestParamCount;
5071+ }
49865072 }
49875073
49885074 /**
@@ -5574,7 +5660,7 @@ namespace ts {
55745660 shouldElaborateErrors = false;
55755661 }
55765662 }
5577- // don't elaborate the primitive apparent types (like Number)
5663+ // don't elaborate the primitive apparent types (like Number)
55785664 // because the actual primitives will have already been reported.
55795665 if (shouldElaborateErrors && !isPrimitiveApparentType(source)) {
55805666 reportError(Diagnostics.Type_0_provides_no_match_for_the_signature_1,
@@ -5621,7 +5707,11 @@ namespace ts {
56215707 }
56225708 }
56235709
5710+ /**
5711+ * See signatureAssignableTo, signatureAssignableTo
5712+ */
56245713 function signatureRelatedTo(source: Signature, target: Signature, reportErrors: boolean): Ternary {
5714+ // TODO (drosen): De-duplicate code between related functions.
56255715 if (source === target) {
56265716 return Ternary.True;
56275717 }
@@ -5673,10 +5763,12 @@ namespace ts {
56735763 }
56745764
56755765 const targetReturnType = getReturnTypeOfSignature(target);
5676- if (targetReturnType === voidType) return result;
5766+ if (targetReturnType === voidType) {
5767+ return result;
5768+ }
56775769 const sourceReturnType = getReturnTypeOfSignature(source);
56785770
5679- // The follow block preserves old behavior forbidding boolean returning functions from being assignable to type guard returning functions
5771+ // The following block preserves behavior forbidding boolean returning functions from being assignable to type guard returning functions
56805772 if (targetReturnType.flags & TypeFlags.PredicateType && (targetReturnType as PredicateType).predicate.kind === TypePredicateKind.Identifier) {
56815773 if (!(sourceReturnType.flags & TypeFlags.PredicateType)) {
56825774 if (reportErrors) {
@@ -5697,7 +5789,7 @@ namespace ts {
56975789 }
56985790 let result = Ternary.True;
56995791 for (let i = 0, len = sourceSignatures.length; i < len; ++i) {
5700- const related = compareSignatures (sourceSignatures[i], targetSignatures[i], /*partialMatch*/ false, /*ignoreReturnTypes*/ false, isRelatedTo);
5792+ const related = compareSignaturesIdentical (sourceSignatures[i], targetSignatures[i], /*partialMatch*/ false, /*ignoreReturnTypes*/ false, isRelatedTo);
57015793 if (!related) {
57025794 return Ternary.False;
57035795 }
@@ -5830,7 +5922,7 @@ namespace ts {
58305922 }
58315923
58325924 function isPropertyIdenticalTo(sourceProp: Symbol, targetProp: Symbol): boolean {
5833- return compareProperties(sourceProp, targetProp, compareTypes ) !== Ternary.False;
5925+ return compareProperties(sourceProp, targetProp, compareTypesIdentical ) !== Ternary.False;
58345926 }
58355927
58365928 function compareProperties(sourceProp: Symbol, targetProp: Symbol, compareTypes: (source: Type, target: Type) => Ternary): Ternary {
@@ -5877,7 +5969,11 @@ namespace ts {
58775969 return false;
58785970 }
58795971
5880- function compareSignatures(source: Signature, target: Signature, partialMatch: boolean, ignoreReturnTypes: boolean, compareTypes: (s: Type, t: Type) => Ternary): Ternary {
5972+ /**
5973+ * See signatureRelatedTo, compareSignaturesIdentical
5974+ */
5975+ function compareSignaturesIdentical(source: Signature, target: Signature, partialMatch: boolean, ignoreReturnTypes: boolean, compareTypes: (s: Type, t: Type) => Ternary): Ternary {
5976+ // TODO (drosen): De-duplicate code between related functions.
58815977 if (source === target) {
58825978 return Ternary.True;
58835979 }
@@ -7585,7 +7681,7 @@ namespace ts {
75857681 // This signature will contribute to contextual union signature
75867682 signatureList = [signature];
75877683 }
7588- else if (!compareSignatures (signatureList[0], signature, /*partialMatch*/ false, /*ignoreReturnTypes*/ true, compareTypes )) {
7684+ else if (!compareSignaturesIdentical (signatureList[0], signature, /*partialMatch*/ false, /*ignoreReturnTypes*/ true, compareTypesIdentical )) {
75897685 // Signatures aren't identical, do not use
75907686 return undefined;
75917687 }
@@ -11606,7 +11702,7 @@ namespace ts {
1160611702 }
1160711703
1160811704 for (const otherSignature of signaturesToCheck) {
11609- if (!otherSignature.hasStringLiterals && isSignatureAssignableTo(signature, otherSignature)) {
11705+ if (!otherSignature.hasStringLiterals && isSignatureAssignableTo(signature, otherSignature, /*ignoreReturnTypes*/ false )) {
1161011706 return;
1161111707 }
1161211708 }
@@ -11853,7 +11949,7 @@ namespace ts {
1185311949 //
1185411950 // The implementation is completely unrelated to the specialized signature, yet we do not check this.
1185511951 for (const signature of signatures) {
11856- if (!signature.hasStringLiterals && !isSignatureAssignableTo (bodySignature, signature)) {
11952+ if (!signature.hasStringLiterals && !isImplementationCompatibleWithOverload (bodySignature, signature)) {
1185711953 error(signature.declaration, Diagnostics.Overload_signature_is_not_compatible_with_function_implementation);
1185811954 break;
1185911955 }
0 commit comments