@@ -3431,7 +3431,7 @@ namespace ts {
3431
3431
3432
3432
function findMatchingSignature(signatureList: Signature[], signature: Signature, partialMatch: boolean, ignoreReturnTypes: boolean): Signature {
3433
3433
for (const s of signatureList) {
3434
- if (compareSignatures (s, signature, partialMatch, ignoreReturnTypes, compareTypes )) {
3434
+ if (compareSignaturesIdentical (s, signature, partialMatch, ignoreReturnTypes, compareTypesIdentical )) {
3435
3435
return s;
3436
3436
}
3437
3437
}
@@ -4860,7 +4860,7 @@ namespace ts {
4860
4860
return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined);
4861
4861
}
4862
4862
4863
- function compareTypes (source: Type, target: Type): Ternary {
4863
+ function compareTypesIdentical (source: Type, target: Type): Ternary {
4864
4864
return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined) ? Ternary.True : Ternary.False;
4865
4865
}
4866
4866
@@ -4880,10 +4880,96 @@ namespace ts {
4880
4880
return checkTypeRelatedTo(source, target, assignableRelation, errorNode, headMessage, containingMessageChain);
4881
4881
}
4882
4882
4883
- function isSignatureAssignableTo(source: Signature, target: Signature): boolean {
4884
- const sourceType = getOrCreateTypeFromSignature(source);
4885
- const targetType = getOrCreateTypeFromSignature(target);
4886
- return checkTypeRelatedTo(sourceType, targetType, assignableRelation, /*errorNode*/ undefined);
4883
+ /**
4884
+ * See signatureRelatedTo, compareSignaturesIdentical
4885
+ */
4886
+ function isSignatureAssignableTo(source: Signature, target: Signature, ignoreReturnTypes: boolean): boolean {
4887
+ // TODO (drosen): De-duplicate code between related functions.
4888
+ if (source === target) {
4889
+ return true;
4890
+ }
4891
+ if (!target.hasRestParameter && source.minArgumentCount > target.parameters.length) {
4892
+ return false;
4893
+ }
4894
+
4895
+ // Spec 1.0 Section 3.8.3 & 3.8.4:
4896
+ // M and N (the signatures) are instantiated using type Any as the type argument for all type parameters declared by M and N
4897
+ source = getErasedSignature(source);
4898
+ target = getErasedSignature(target);
4899
+
4900
+ const sourceMax = getNumNonRestParameters(source);
4901
+ const targetMax = getNumNonRestParameters(target);
4902
+ const checkCount = getNumParametersToCheckForSignatureRelatability(source, sourceMax, target, targetMax);
4903
+ for (let i = 0; i < checkCount; i++) {
4904
+ const s = i < sourceMax ? getTypeOfSymbol(source.parameters[i]) : getRestTypeOfSignature(source);
4905
+ const t = i < targetMax ? getTypeOfSymbol(target.parameters[i]) : getRestTypeOfSignature(target);
4906
+ const related = isTypeAssignableTo(t, s) || isTypeAssignableTo(s, t);
4907
+ if (!related) {
4908
+ return false;
4909
+ }
4910
+ }
4911
+
4912
+ if (!ignoreReturnTypes) {
4913
+ const targetReturnType = getReturnTypeOfSignature(target);
4914
+ if (targetReturnType === voidType) {
4915
+ return true;
4916
+ }
4917
+ const sourceReturnType = getReturnTypeOfSignature(source);
4918
+
4919
+ // The following block preserves behavior forbidding boolean returning functions from being assignable to type guard returning functions
4920
+ if (targetReturnType.flags & TypeFlags.PredicateType && (targetReturnType as PredicateType).predicate.kind === TypePredicateKind.Identifier) {
4921
+ if (!(sourceReturnType.flags & TypeFlags.PredicateType)) {
4922
+ return false;
4923
+ }
4924
+ }
4925
+
4926
+ return isTypeAssignableTo(sourceReturnType, targetReturnType);
4927
+ }
4928
+
4929
+ return true;
4930
+ }
4931
+
4932
+ function isImplementationCompatibleWithOverload(implementation: Signature, overload: Signature): boolean {
4933
+ const erasedSource = getErasedSignature(implementation);
4934
+ const erasedTarget = getErasedSignature(overload);
4935
+
4936
+ // First see if the return types are compatible in either direction.
4937
+ const sourceReturnType = getReturnTypeOfSignature(erasedSource);
4938
+ const targetReturnType = getReturnTypeOfSignature(erasedTarget);
4939
+ if (targetReturnType === voidType
4940
+ || checkTypeRelatedTo(targetReturnType, sourceReturnType, assignableRelation, /*errorNode*/ undefined)
4941
+ || checkTypeRelatedTo(sourceReturnType, targetReturnType, assignableRelation, /*errorNode*/ undefined)) {
4942
+
4943
+ return isSignatureAssignableTo(erasedSource, erasedTarget, /*ignoreReturnTypes*/ true);
4944
+ }
4945
+
4946
+ return false;
4947
+ }
4948
+
4949
+ function getNumNonRestParameters(signature: Signature) {
4950
+ const numParams = signature.parameters.length;
4951
+ return signature.hasRestParameter ?
4952
+ numParams - 1 :
4953
+ numParams;
4954
+ }
4955
+
4956
+ function getNumParametersToCheckForSignatureRelatability(source: Signature, sourceNonRestParamCount: number, target: Signature, targetNonRestParamCount: number) {
4957
+ if (source.hasRestParameter === target.hasRestParameter) {
4958
+ if (source.hasRestParameter) {
4959
+ // If both have rest parameters, get the max and add 1 to
4960
+ // compensate for the rest parameter.
4961
+ return Math.max(sourceNonRestParamCount, targetNonRestParamCount) + 1;
4962
+ }
4963
+ else {
4964
+ return Math.min(sourceNonRestParamCount, targetNonRestParamCount);
4965
+ }
4966
+ }
4967
+ else {
4968
+ // Return the count for whichever signature doesn't have rest parameters.
4969
+ return source.hasRestParameter ?
4970
+ targetNonRestParamCount :
4971
+ sourceNonRestParamCount;
4972
+ }
4887
4973
}
4888
4974
4889
4975
/**
@@ -4967,6 +5053,11 @@ namespace ts {
4967
5053
if (source === undefinedType) return Ternary.True;
4968
5054
if (source === nullType && target !== undefinedType) return Ternary.True;
4969
5055
if (source.flags & TypeFlags.Enum && target === numberType) return Ternary.True;
5056
+ if (source.flags & TypeFlags.Enum && target.flags & TypeFlags.Enum) {
5057
+ if (result = enumRelatedTo(source, target)) {
5058
+ return result;
5059
+ }
5060
+ }
4970
5061
if (source.flags & TypeFlags.StringLiteral && target === stringType) return Ternary.True;
4971
5062
if (relation === assignableRelation) {
4972
5063
if (isTypeAny(source)) return Ternary.True;
@@ -5470,7 +5561,7 @@ namespace ts {
5470
5561
shouldElaborateErrors = false;
5471
5562
}
5472
5563
}
5473
- // don't elaborate the primitive apparent types (like Number)
5564
+ // don't elaborate the primitive apparent types (like Number)
5474
5565
// because the actual primitives will have already been reported.
5475
5566
if (shouldElaborateErrors && !isPrimitiveApparentType(source)) {
5476
5567
reportError(Diagnostics.Type_0_provides_no_match_for_the_signature_1,
@@ -5517,7 +5608,11 @@ namespace ts {
5517
5608
}
5518
5609
}
5519
5610
5611
+ /**
5612
+ * See signatureAssignableTo, signatureAssignableTo
5613
+ */
5520
5614
function signatureRelatedTo(source: Signature, target: Signature, reportErrors: boolean): Ternary {
5615
+ // TODO (drosen): De-duplicate code between related functions.
5521
5616
if (source === target) {
5522
5617
return Ternary.True;
5523
5618
}
@@ -5569,10 +5664,12 @@ namespace ts {
5569
5664
}
5570
5665
5571
5666
const targetReturnType = getReturnTypeOfSignature(target);
5572
- if (targetReturnType === voidType) return result;
5667
+ if (targetReturnType === voidType) {
5668
+ return result;
5669
+ }
5573
5670
const sourceReturnType = getReturnTypeOfSignature(source);
5574
5671
5575
- // The follow block preserves old behavior forbidding boolean returning functions from being assignable to type guard returning functions
5672
+ // The following block preserves behavior forbidding boolean returning functions from being assignable to type guard returning functions
5576
5673
if (targetReturnType.flags & TypeFlags.PredicateType && (targetReturnType as PredicateType).predicate.kind === TypePredicateKind.Identifier) {
5577
5674
if (!(sourceReturnType.flags & TypeFlags.PredicateType)) {
5578
5675
if (reportErrors) {
@@ -5593,7 +5690,7 @@ namespace ts {
5593
5690
}
5594
5691
let result = Ternary.True;
5595
5692
for (let i = 0, len = sourceSignatures.length; i < len; ++i) {
5596
- const related = compareSignatures (sourceSignatures[i], targetSignatures[i], /*partialMatch*/ false, /*ignoreReturnTypes*/ false, isRelatedTo);
5693
+ const related = compareSignaturesIdentical (sourceSignatures[i], targetSignatures[i], /*partialMatch*/ false, /*ignoreReturnTypes*/ false, isRelatedTo);
5597
5694
if (!related) {
5598
5695
return Ternary.False;
5599
5696
}
@@ -5681,6 +5778,27 @@ namespace ts {
5681
5778
}
5682
5779
return Ternary.False;
5683
5780
}
5781
+
5782
+ function enumRelatedTo(source: Type, target: Type) {
5783
+ if (source.symbol.name !== target.symbol.name ||
5784
+ source.symbol.flags & SymbolFlags.ConstEnum ||
5785
+ target.symbol.flags & SymbolFlags.ConstEnum) {
5786
+ return Ternary.False;
5787
+ }
5788
+ const targetEnumType = getTypeOfSymbol(target.symbol);
5789
+ for (const property of getPropertiesOfType(getTypeOfSymbol(source.symbol))) {
5790
+ if (property.flags & SymbolFlags.EnumMember) {
5791
+ const targetProperty = getPropertyOfType(targetEnumType, property.name);
5792
+ if (!targetProperty || !(targetProperty.flags & SymbolFlags.EnumMember)) {
5793
+ reportError(Diagnostics.Property_0_is_missing_in_type_1,
5794
+ property.name,
5795
+ typeToString(target, /*enclosingDeclaration*/ undefined, TypeFormatFlags.UseFullyQualifiedType));
5796
+ return Ternary.False;
5797
+ }
5798
+ }
5799
+ }
5800
+ return Ternary.True;
5801
+ }
5684
5802
}
5685
5803
5686
5804
// Return true if the given type is part of a deeply nested chain of generic instantiations. We consider this to be the case
@@ -5705,7 +5823,7 @@ namespace ts {
5705
5823
}
5706
5824
5707
5825
function isPropertyIdenticalTo(sourceProp: Symbol, targetProp: Symbol): boolean {
5708
- return compareProperties(sourceProp, targetProp, compareTypes ) !== Ternary.False;
5826
+ return compareProperties(sourceProp, targetProp, compareTypesIdentical ) !== Ternary.False;
5709
5827
}
5710
5828
5711
5829
function compareProperties(sourceProp: Symbol, targetProp: Symbol, compareTypes: (source: Type, target: Type) => Ternary): Ternary {
@@ -5752,7 +5870,11 @@ namespace ts {
5752
5870
return false;
5753
5871
}
5754
5872
5755
- function compareSignatures(source: Signature, target: Signature, partialMatch: boolean, ignoreReturnTypes: boolean, compareTypes: (s: Type, t: Type) => Ternary): Ternary {
5873
+ /**
5874
+ * See signatureRelatedTo, compareSignaturesIdentical
5875
+ */
5876
+ function compareSignaturesIdentical(source: Signature, target: Signature, partialMatch: boolean, ignoreReturnTypes: boolean, compareTypes: (s: Type, t: Type) => Ternary): Ternary {
5877
+ // TODO (drosen): De-duplicate code between related functions.
5756
5878
if (source === target) {
5757
5879
return Ternary.True;
5758
5880
}
@@ -7460,7 +7582,7 @@ namespace ts {
7460
7582
// This signature will contribute to contextual union signature
7461
7583
signatureList = [signature];
7462
7584
}
7463
- else if (!compareSignatures (signatureList[0], signature, /*partialMatch*/ false, /*ignoreReturnTypes*/ true, compareTypes )) {
7585
+ else if (!compareSignaturesIdentical (signatureList[0], signature, /*partialMatch*/ false, /*ignoreReturnTypes*/ true, compareTypesIdentical )) {
7464
7586
// Signatures aren't identical, do not use
7465
7587
return undefined;
7466
7588
}
@@ -11480,7 +11602,7 @@ namespace ts {
11480
11602
}
11481
11603
11482
11604
for (const otherSignature of signaturesToCheck) {
11483
- if (!otherSignature.hasStringLiterals && isSignatureAssignableTo(signature, otherSignature)) {
11605
+ if (!otherSignature.hasStringLiterals && isSignatureAssignableTo(signature, otherSignature, /*ignoreReturnTypes*/ false )) {
11484
11606
return;
11485
11607
}
11486
11608
}
@@ -11727,7 +11849,7 @@ namespace ts {
11727
11849
//
11728
11850
// The implementation is completely unrelated to the specialized signature, yet we do not check this.
11729
11851
for (const signature of signatures) {
11730
- if (!signature.hasStringLiterals && !isSignatureAssignableTo (bodySignature, signature)) {
11852
+ if (!signature.hasStringLiterals && !isImplementationCompatibleWithOverload (bodySignature, signature)) {
11731
11853
error(signature.declaration, Diagnostics.Overload_signature_is_not_compatible_with_function_implementation);
11732
11854
break;
11733
11855
}
0 commit comments