@@ -3501,7 +3501,7 @@ namespace ts {
3501
3501
3502
3502
function findMatchingSignature(signatureList: Signature[], signature: Signature, partialMatch: boolean, ignoreReturnTypes: boolean): Signature {
3503
3503
for (const s of signatureList) {
3504
- if (compareSignatures (s, signature, partialMatch, ignoreReturnTypes, compareTypes )) {
3504
+ if (compareSignaturesIdentical (s, signature, partialMatch, ignoreReturnTypes, compareTypesIdentical )) {
3505
3505
return s;
3506
3506
}
3507
3507
}
@@ -4115,16 +4115,6 @@ namespace ts {
4115
4115
return signature.erasedSignatureCache;
4116
4116
}
4117
4117
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
-
4128
4118
function getOrCreateTypeFromSignature(signature: Signature): ObjectType {
4129
4119
// There are two ways to declare a construct signature, one is by declaring a class constructor
4130
4120
// using the constructor keyword, and the other is declaring a bare construct signature in an
@@ -4965,7 +4955,7 @@ namespace ts {
4965
4955
return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined);
4966
4956
}
4967
4957
4968
- function compareTypes (source: Type, target: Type): Ternary {
4958
+ function compareTypesIdentical (source: Type, target: Type): Ternary {
4969
4959
return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined) ? Ternary.True : Ternary.False;
4970
4960
}
4971
4961
@@ -4985,10 +4975,53 @@ namespace ts {
4985
4975
return checkTypeRelatedTo(source, target, assignableRelation, errorNode, headMessage, containingMessageChain);
4986
4976
}
4987
4977
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;
4992
5025
}
4993
5026
4994
5027
function isImplementationCompatibleWithOverload(implementation: Signature, overload: Signature): boolean {
@@ -5002,15 +5035,35 @@ namespace ts {
5002
5035
|| checkTypeRelatedTo(targetReturnType, sourceReturnType, assignableRelation, /*errorNode*/ undefined)
5003
5036
|| checkTypeRelatedTo(sourceReturnType, targetReturnType, assignableRelation, /*errorNode*/ undefined)) {
5004
5037
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
+ }
5009
5040
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;
5014
5067
}
5015
5068
}
5016
5069
@@ -5645,7 +5698,11 @@ namespace ts {
5645
5698
}
5646
5699
}
5647
5700
5701
+ /**
5702
+ * See signatureAssignableTo, signatureAssignableTo
5703
+ */
5648
5704
function signatureRelatedTo(source: Signature, target: Signature, reportErrors: boolean): Ternary {
5705
+ // TODO (drosen): De-duplicate code between related functions.
5649
5706
if (source === target) {
5650
5707
return Ternary.True;
5651
5708
}
@@ -5697,10 +5754,12 @@ namespace ts {
5697
5754
}
5698
5755
5699
5756
const targetReturnType = getReturnTypeOfSignature(target);
5700
- if (targetReturnType === voidType) return result;
5757
+ if (targetReturnType === voidType) {
5758
+ return result;
5759
+ }
5701
5760
const sourceReturnType = getReturnTypeOfSignature(source);
5702
5761
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
5704
5763
if (targetReturnType.flags & TypeFlags.PredicateType && (targetReturnType as PredicateType).predicate.kind === TypePredicateKind.Identifier) {
5705
5764
if (!(sourceReturnType.flags & TypeFlags.PredicateType)) {
5706
5765
if (reportErrors) {
@@ -5721,7 +5780,7 @@ namespace ts {
5721
5780
}
5722
5781
let result = Ternary.True;
5723
5782
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);
5725
5784
if (!related) {
5726
5785
return Ternary.False;
5727
5786
}
@@ -5833,7 +5892,7 @@ namespace ts {
5833
5892
}
5834
5893
5835
5894
function isPropertyIdenticalTo(sourceProp: Symbol, targetProp: Symbol): boolean {
5836
- return compareProperties(sourceProp, targetProp, compareTypes ) !== Ternary.False;
5895
+ return compareProperties(sourceProp, targetProp, compareTypesIdentical ) !== Ternary.False;
5837
5896
}
5838
5897
5839
5898
function compareProperties(sourceProp: Symbol, targetProp: Symbol, compareTypes: (source: Type, target: Type) => Ternary): Ternary {
@@ -5880,7 +5939,11 @@ namespace ts {
5880
5939
return false;
5881
5940
}
5882
5941
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.
5884
5947
if (source === target) {
5885
5948
return Ternary.True;
5886
5949
}
@@ -7571,7 +7634,7 @@ namespace ts {
7571
7634
// This signature will contribute to contextual union signature
7572
7635
signatureList = [signature];
7573
7636
}
7574
- else if (!compareSignatures (signatureList[0], signature, /*partialMatch*/ false, /*ignoreReturnTypes*/ true, compareTypes )) {
7637
+ else if (!compareSignaturesIdentical (signatureList[0], signature, /*partialMatch*/ false, /*ignoreReturnTypes*/ true, compareTypesIdentical )) {
7575
7638
// Signatures aren't identical, do not use
7576
7639
return undefined;
7577
7640
}
@@ -11564,7 +11627,7 @@ namespace ts {
11564
11627
}
11565
11628
11566
11629
for (const otherSignature of signaturesToCheck) {
11567
- if (!otherSignature.hasStringLiterals && isSignatureAssignableTo(signature, otherSignature)) {
11630
+ if (!otherSignature.hasStringLiterals && isSignatureAssignableTo(signature, otherSignature, /*ignoreReturnTypes*/ false )) {
11568
11631
return;
11569
11632
}
11570
11633
}
0 commit comments