Skip to content

Commit 19b44e0

Browse files
Merge branch 'master' into noUnused
2 parents f625317 + 710a5be commit 19b44e0

File tree

57 files changed

+2964
-766
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+2964
-766
lines changed

Jakefile.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -924,7 +924,8 @@ function lintFileAsync(options, path, cb) {
924924
var lintTargets = compilerSources
925925
.concat(harnessCoreSources)
926926
.concat(serverCoreSources)
927-
.concat(scriptSources);
927+
.concat(scriptSources)
928+
.concat([path.join(servicesDirectory, "services.ts")]);
928929

929930
desc("Runs tslint on the compiler sources");
930931
task("lint", ["build-rules"], function() {

src/compiler/checker.ts

Lines changed: 137 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3431,7 +3431,7 @@ namespace ts {
34313431

34323432
function findMatchingSignature(signatureList: Signature[], signature: Signature, partialMatch: boolean, ignoreReturnTypes: boolean): Signature {
34333433
for (const s of signatureList) {
3434-
if (compareSignatures(s, signature, partialMatch, ignoreReturnTypes, compareTypes)) {
3434+
if (compareSignaturesIdentical(s, signature, partialMatch, ignoreReturnTypes, compareTypesIdentical)) {
34353435
return s;
34363436
}
34373437
}
@@ -4860,7 +4860,7 @@ namespace ts {
48604860
return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined);
48614861
}
48624862

4863-
function compareTypes(source: Type, target: Type): Ternary {
4863+
function compareTypesIdentical(source: Type, target: Type): Ternary {
48644864
return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined) ? Ternary.True : Ternary.False;
48654865
}
48664866

@@ -4880,10 +4880,96 @@ namespace ts {
48804880
return checkTypeRelatedTo(source, target, assignableRelation, errorNode, headMessage, containingMessageChain);
48814881
}
48824882

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+
}
48874973
}
48884974

48894975
/**
@@ -4967,6 +5053,11 @@ namespace ts {
49675053
if (source === undefinedType) return Ternary.True;
49685054
if (source === nullType && target !== undefinedType) return Ternary.True;
49695055
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+
}
49705061
if (source.flags & TypeFlags.StringLiteral && target === stringType) return Ternary.True;
49715062
if (relation === assignableRelation) {
49725063
if (isTypeAny(source)) return Ternary.True;
@@ -5470,7 +5561,7 @@ namespace ts {
54705561
shouldElaborateErrors = false;
54715562
}
54725563
}
5473-
// don't elaborate the primitive apparent types (like Number)
5564+
// don't elaborate the primitive apparent types (like Number)
54745565
// because the actual primitives will have already been reported.
54755566
if (shouldElaborateErrors && !isPrimitiveApparentType(source)) {
54765567
reportError(Diagnostics.Type_0_provides_no_match_for_the_signature_1,
@@ -5517,7 +5608,11 @@ namespace ts {
55175608
}
55185609
}
55195610

5611+
/**
5612+
* See signatureAssignableTo, signatureAssignableTo
5613+
*/
55205614
function signatureRelatedTo(source: Signature, target: Signature, reportErrors: boolean): Ternary {
5615+
// TODO (drosen): De-duplicate code between related functions.
55215616
if (source === target) {
55225617
return Ternary.True;
55235618
}
@@ -5569,10 +5664,12 @@ namespace ts {
55695664
}
55705665

55715666
const targetReturnType = getReturnTypeOfSignature(target);
5572-
if (targetReturnType === voidType) return result;
5667+
if (targetReturnType === voidType) {
5668+
return result;
5669+
}
55735670
const sourceReturnType = getReturnTypeOfSignature(source);
55745671

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
55765673
if (targetReturnType.flags & TypeFlags.PredicateType && (targetReturnType as PredicateType).predicate.kind === TypePredicateKind.Identifier) {
55775674
if (!(sourceReturnType.flags & TypeFlags.PredicateType)) {
55785675
if (reportErrors) {
@@ -5593,7 +5690,7 @@ namespace ts {
55935690
}
55945691
let result = Ternary.True;
55955692
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);
55975694
if (!related) {
55985695
return Ternary.False;
55995696
}
@@ -5681,6 +5778,27 @@ namespace ts {
56815778
}
56825779
return Ternary.False;
56835780
}
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+
}
56845802
}
56855803

56865804
// 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 {
57055823
}
57065824

57075825
function isPropertyIdenticalTo(sourceProp: Symbol, targetProp: Symbol): boolean {
5708-
return compareProperties(sourceProp, targetProp, compareTypes) !== Ternary.False;
5826+
return compareProperties(sourceProp, targetProp, compareTypesIdentical) !== Ternary.False;
57095827
}
57105828

57115829
function compareProperties(sourceProp: Symbol, targetProp: Symbol, compareTypes: (source: Type, target: Type) => Ternary): Ternary {
@@ -5752,7 +5870,11 @@ namespace ts {
57525870
return false;
57535871
}
57545872

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.
57565878
if (source === target) {
57575879
return Ternary.True;
57585880
}
@@ -7460,7 +7582,7 @@ namespace ts {
74607582
// This signature will contribute to contextual union signature
74617583
signatureList = [signature];
74627584
}
7463-
else if (!compareSignatures(signatureList[0], signature, /*partialMatch*/ false, /*ignoreReturnTypes*/ true, compareTypes)) {
7585+
else if (!compareSignaturesIdentical(signatureList[0], signature, /*partialMatch*/ false, /*ignoreReturnTypes*/ true, compareTypesIdentical)) {
74647586
// Signatures aren't identical, do not use
74657587
return undefined;
74667588
}
@@ -11480,7 +11602,7 @@ namespace ts {
1148011602
}
1148111603

1148211604
for (const otherSignature of signaturesToCheck) {
11483-
if (!otherSignature.hasStringLiterals && isSignatureAssignableTo(signature, otherSignature)) {
11605+
if (!otherSignature.hasStringLiterals && isSignatureAssignableTo(signature, otherSignature, /*ignoreReturnTypes*/ false)) {
1148411606
return;
1148511607
}
1148611608
}
@@ -11727,7 +11849,7 @@ namespace ts {
1172711849
//
1172811850
// The implementation is completely unrelated to the specialized signature, yet we do not check this.
1172911851
for (const signature of signatures) {
11730-
if (!signature.hasStringLiterals && !isSignatureAssignableTo(bodySignature, signature)) {
11852+
if (!signature.hasStringLiterals && !isImplementationCompatibleWithOverload(bodySignature, signature)) {
1173111853
error(signature.declaration, Diagnostics.Overload_signature_is_not_compatible_with_function_implementation);
1173211854
break;
1173311855
}

0 commit comments

Comments
 (0)