@@ -3507,7 +3507,7 @@ namespace ts {
3507
3507
3508
3508
function findMatchingSignature(signatureList: Signature[], signature: Signature, partialMatch: boolean, ignoreReturnTypes: boolean): Signature {
3509
3509
for (const s of signatureList) {
3510
- if (compareSignatures (s, signature, partialMatch, ignoreReturnTypes, compareTypes )) {
3510
+ if (compareSignaturesIdentical (s, signature, partialMatch, ignoreReturnTypes, compareTypesIdentical )) {
3511
3511
return s;
3512
3512
}
3513
3513
}
@@ -4959,7 +4959,7 @@ namespace ts {
4959
4959
return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined);
4960
4960
}
4961
4961
4962
- function compareTypes (source: Type, target: Type): Ternary {
4962
+ function compareTypesIdentical (source: Type, target: Type): Ternary {
4963
4963
return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined) ? Ternary.True : Ternary.False;
4964
4964
}
4965
4965
@@ -4979,10 +4979,96 @@ namespace ts {
4979
4979
return checkTypeRelatedTo(source, target, assignableRelation, errorNode, headMessage, containingMessageChain);
4980
4980
}
4981
4981
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
+ }
4986
5072
}
4987
5073
4988
5074
/**
@@ -5574,7 +5660,7 @@ namespace ts {
5574
5660
shouldElaborateErrors = false;
5575
5661
}
5576
5662
}
5577
- // don't elaborate the primitive apparent types (like Number)
5663
+ // don't elaborate the primitive apparent types (like Number)
5578
5664
// because the actual primitives will have already been reported.
5579
5665
if (shouldElaborateErrors && !isPrimitiveApparentType(source)) {
5580
5666
reportError(Diagnostics.Type_0_provides_no_match_for_the_signature_1,
@@ -5621,7 +5707,11 @@ namespace ts {
5621
5707
}
5622
5708
}
5623
5709
5710
+ /**
5711
+ * See signatureAssignableTo, signatureAssignableTo
5712
+ */
5624
5713
function signatureRelatedTo(source: Signature, target: Signature, reportErrors: boolean): Ternary {
5714
+ // TODO (drosen): De-duplicate code between related functions.
5625
5715
if (source === target) {
5626
5716
return Ternary.True;
5627
5717
}
@@ -5673,10 +5763,12 @@ namespace ts {
5673
5763
}
5674
5764
5675
5765
const targetReturnType = getReturnTypeOfSignature(target);
5676
- if (targetReturnType === voidType) return result;
5766
+ if (targetReturnType === voidType) {
5767
+ return result;
5768
+ }
5677
5769
const sourceReturnType = getReturnTypeOfSignature(source);
5678
5770
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
5680
5772
if (targetReturnType.flags & TypeFlags.PredicateType && (targetReturnType as PredicateType).predicate.kind === TypePredicateKind.Identifier) {
5681
5773
if (!(sourceReturnType.flags & TypeFlags.PredicateType)) {
5682
5774
if (reportErrors) {
@@ -5697,7 +5789,7 @@ namespace ts {
5697
5789
}
5698
5790
let result = Ternary.True;
5699
5791
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);
5701
5793
if (!related) {
5702
5794
return Ternary.False;
5703
5795
}
@@ -5830,7 +5922,7 @@ namespace ts {
5830
5922
}
5831
5923
5832
5924
function isPropertyIdenticalTo(sourceProp: Symbol, targetProp: Symbol): boolean {
5833
- return compareProperties(sourceProp, targetProp, compareTypes ) !== Ternary.False;
5925
+ return compareProperties(sourceProp, targetProp, compareTypesIdentical ) !== Ternary.False;
5834
5926
}
5835
5927
5836
5928
function compareProperties(sourceProp: Symbol, targetProp: Symbol, compareTypes: (source: Type, target: Type) => Ternary): Ternary {
@@ -5877,7 +5969,11 @@ namespace ts {
5877
5969
return false;
5878
5970
}
5879
5971
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.
5881
5977
if (source === target) {
5882
5978
return Ternary.True;
5883
5979
}
@@ -7585,7 +7681,7 @@ namespace ts {
7585
7681
// This signature will contribute to contextual union signature
7586
7682
signatureList = [signature];
7587
7683
}
7588
- else if (!compareSignatures (signatureList[0], signature, /*partialMatch*/ false, /*ignoreReturnTypes*/ true, compareTypes )) {
7684
+ else if (!compareSignaturesIdentical (signatureList[0], signature, /*partialMatch*/ false, /*ignoreReturnTypes*/ true, compareTypesIdentical )) {
7589
7685
// Signatures aren't identical, do not use
7590
7686
return undefined;
7591
7687
}
@@ -11606,7 +11702,7 @@ namespace ts {
11606
11702
}
11607
11703
11608
11704
for (const otherSignature of signaturesToCheck) {
11609
- if (!otherSignature.hasStringLiterals && isSignatureAssignableTo(signature, otherSignature)) {
11705
+ if (!otherSignature.hasStringLiterals && isSignatureAssignableTo(signature, otherSignature, /*ignoreReturnTypes*/ false )) {
11610
11706
return;
11611
11707
}
11612
11708
}
@@ -11853,7 +11949,7 @@ namespace ts {
11853
11949
//
11854
11950
// The implementation is completely unrelated to the specialized signature, yet we do not check this.
11855
11951
for (const signature of signatures) {
11856
- if (!signature.hasStringLiterals && !isSignatureAssignableTo (bodySignature, signature)) {
11952
+ if (!signature.hasStringLiterals && !isImplementationCompatibleWithOverload (bodySignature, signature)) {
11857
11953
error(signature.declaration, Diagnostics.Overload_signature_is_not_compatible_with_function_implementation);
11858
11954
break;
11859
11955
}
0 commit comments