mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-29 16:29:19 -05:00
Merge branch 'master' into noUnused
This commit is contained in:
@@ -3431,7 +3431,7 @@ namespace ts {
|
||||
|
||||
function findMatchingSignature(signatureList: Signature[], signature: Signature, partialMatch: boolean, ignoreReturnTypes: boolean): Signature {
|
||||
for (const s of signatureList) {
|
||||
if (compareSignatures(s, signature, partialMatch, ignoreReturnTypes, compareTypes)) {
|
||||
if (compareSignaturesIdentical(s, signature, partialMatch, ignoreReturnTypes, compareTypesIdentical)) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
@@ -4860,7 +4860,7 @@ namespace ts {
|
||||
return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined);
|
||||
}
|
||||
|
||||
function compareTypes(source: Type, target: Type): Ternary {
|
||||
function compareTypesIdentical(source: Type, target: Type): Ternary {
|
||||
return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined) ? Ternary.True : Ternary.False;
|
||||
}
|
||||
|
||||
@@ -4880,10 +4880,96 @@ namespace ts {
|
||||
return checkTypeRelatedTo(source, target, assignableRelation, errorNode, headMessage, containingMessageChain);
|
||||
}
|
||||
|
||||
function isSignatureAssignableTo(source: Signature, target: Signature): boolean {
|
||||
const sourceType = getOrCreateTypeFromSignature(source);
|
||||
const targetType = getOrCreateTypeFromSignature(target);
|
||||
return checkTypeRelatedTo(sourceType, targetType, assignableRelation, /*errorNode*/ undefined);
|
||||
/**
|
||||
* See signatureRelatedTo, compareSignaturesIdentical
|
||||
*/
|
||||
function isSignatureAssignableTo(source: Signature, target: Signature, ignoreReturnTypes: boolean): boolean {
|
||||
// TODO (drosen): De-duplicate code between related functions.
|
||||
if (source === target) {
|
||||
return true;
|
||||
}
|
||||
if (!target.hasRestParameter && source.minArgumentCount > target.parameters.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Spec 1.0 Section 3.8.3 & 3.8.4:
|
||||
// M and N (the signatures) are instantiated using type Any as the type argument for all type parameters declared by M and N
|
||||
source = getErasedSignature(source);
|
||||
target = getErasedSignature(target);
|
||||
|
||||
const sourceMax = getNumNonRestParameters(source);
|
||||
const targetMax = getNumNonRestParameters(target);
|
||||
const checkCount = getNumParametersToCheckForSignatureRelatability(source, sourceMax, target, targetMax);
|
||||
for (let i = 0; i < checkCount; i++) {
|
||||
const s = i < sourceMax ? getTypeOfSymbol(source.parameters[i]) : getRestTypeOfSignature(source);
|
||||
const t = i < targetMax ? getTypeOfSymbol(target.parameters[i]) : getRestTypeOfSignature(target);
|
||||
const related = isTypeAssignableTo(t, s) || isTypeAssignableTo(s, t);
|
||||
if (!related) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ignoreReturnTypes) {
|
||||
const targetReturnType = getReturnTypeOfSignature(target);
|
||||
if (targetReturnType === voidType) {
|
||||
return true;
|
||||
}
|
||||
const sourceReturnType = getReturnTypeOfSignature(source);
|
||||
|
||||
// The following block preserves behavior forbidding boolean returning functions from being assignable to type guard returning functions
|
||||
if (targetReturnType.flags & TypeFlags.PredicateType && (targetReturnType as PredicateType).predicate.kind === TypePredicateKind.Identifier) {
|
||||
if (!(sourceReturnType.flags & TypeFlags.PredicateType)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return isTypeAssignableTo(sourceReturnType, targetReturnType);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function isImplementationCompatibleWithOverload(implementation: Signature, overload: Signature): boolean {
|
||||
const erasedSource = getErasedSignature(implementation);
|
||||
const erasedTarget = getErasedSignature(overload);
|
||||
|
||||
// First see if the return types are compatible in either direction.
|
||||
const sourceReturnType = getReturnTypeOfSignature(erasedSource);
|
||||
const targetReturnType = getReturnTypeOfSignature(erasedTarget);
|
||||
if (targetReturnType === voidType
|
||||
|| checkTypeRelatedTo(targetReturnType, sourceReturnType, assignableRelation, /*errorNode*/ undefined)
|
||||
|| checkTypeRelatedTo(sourceReturnType, targetReturnType, assignableRelation, /*errorNode*/ undefined)) {
|
||||
|
||||
return isSignatureAssignableTo(erasedSource, erasedTarget, /*ignoreReturnTypes*/ true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function getNumNonRestParameters(signature: Signature) {
|
||||
const numParams = signature.parameters.length;
|
||||
return signature.hasRestParameter ?
|
||||
numParams - 1 :
|
||||
numParams;
|
||||
}
|
||||
|
||||
function getNumParametersToCheckForSignatureRelatability(source: Signature, sourceNonRestParamCount: number, target: Signature, targetNonRestParamCount: number) {
|
||||
if (source.hasRestParameter === target.hasRestParameter) {
|
||||
if (source.hasRestParameter) {
|
||||
// If both have rest parameters, get the max and add 1 to
|
||||
// compensate for the rest parameter.
|
||||
return Math.max(sourceNonRestParamCount, targetNonRestParamCount) + 1;
|
||||
}
|
||||
else {
|
||||
return Math.min(sourceNonRestParamCount, targetNonRestParamCount);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Return the count for whichever signature doesn't have rest parameters.
|
||||
return source.hasRestParameter ?
|
||||
targetNonRestParamCount :
|
||||
sourceNonRestParamCount;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4967,6 +5053,11 @@ namespace ts {
|
||||
if (source === undefinedType) return Ternary.True;
|
||||
if (source === nullType && target !== undefinedType) return Ternary.True;
|
||||
if (source.flags & TypeFlags.Enum && target === numberType) return Ternary.True;
|
||||
if (source.flags & TypeFlags.Enum && target.flags & TypeFlags.Enum) {
|
||||
if (result = enumRelatedTo(source, target)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (source.flags & TypeFlags.StringLiteral && target === stringType) return Ternary.True;
|
||||
if (relation === assignableRelation) {
|
||||
if (isTypeAny(source)) return Ternary.True;
|
||||
@@ -5470,7 +5561,7 @@ namespace ts {
|
||||
shouldElaborateErrors = false;
|
||||
}
|
||||
}
|
||||
// don't elaborate the primitive apparent types (like Number)
|
||||
// don't elaborate the primitive apparent types (like Number)
|
||||
// because the actual primitives will have already been reported.
|
||||
if (shouldElaborateErrors && !isPrimitiveApparentType(source)) {
|
||||
reportError(Diagnostics.Type_0_provides_no_match_for_the_signature_1,
|
||||
@@ -5517,7 +5608,11 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See signatureAssignableTo, signatureAssignableTo
|
||||
*/
|
||||
function signatureRelatedTo(source: Signature, target: Signature, reportErrors: boolean): Ternary {
|
||||
// TODO (drosen): De-duplicate code between related functions.
|
||||
if (source === target) {
|
||||
return Ternary.True;
|
||||
}
|
||||
@@ -5569,10 +5664,12 @@ namespace ts {
|
||||
}
|
||||
|
||||
const targetReturnType = getReturnTypeOfSignature(target);
|
||||
if (targetReturnType === voidType) return result;
|
||||
if (targetReturnType === voidType) {
|
||||
return result;
|
||||
}
|
||||
const sourceReturnType = getReturnTypeOfSignature(source);
|
||||
|
||||
// The follow block preserves old behavior forbidding boolean returning functions from being assignable to type guard returning functions
|
||||
// The following block preserves behavior forbidding boolean returning functions from being assignable to type guard returning functions
|
||||
if (targetReturnType.flags & TypeFlags.PredicateType && (targetReturnType as PredicateType).predicate.kind === TypePredicateKind.Identifier) {
|
||||
if (!(sourceReturnType.flags & TypeFlags.PredicateType)) {
|
||||
if (reportErrors) {
|
||||
@@ -5593,7 +5690,7 @@ namespace ts {
|
||||
}
|
||||
let result = Ternary.True;
|
||||
for (let i = 0, len = sourceSignatures.length; i < len; ++i) {
|
||||
const related = compareSignatures(sourceSignatures[i], targetSignatures[i], /*partialMatch*/ false, /*ignoreReturnTypes*/ false, isRelatedTo);
|
||||
const related = compareSignaturesIdentical(sourceSignatures[i], targetSignatures[i], /*partialMatch*/ false, /*ignoreReturnTypes*/ false, isRelatedTo);
|
||||
if (!related) {
|
||||
return Ternary.False;
|
||||
}
|
||||
@@ -5681,6 +5778,27 @@ namespace ts {
|
||||
}
|
||||
return Ternary.False;
|
||||
}
|
||||
|
||||
function enumRelatedTo(source: Type, target: Type) {
|
||||
if (source.symbol.name !== target.symbol.name ||
|
||||
source.symbol.flags & SymbolFlags.ConstEnum ||
|
||||
target.symbol.flags & SymbolFlags.ConstEnum) {
|
||||
return Ternary.False;
|
||||
}
|
||||
const targetEnumType = getTypeOfSymbol(target.symbol);
|
||||
for (const property of getPropertiesOfType(getTypeOfSymbol(source.symbol))) {
|
||||
if (property.flags & SymbolFlags.EnumMember) {
|
||||
const targetProperty = getPropertyOfType(targetEnumType, property.name);
|
||||
if (!targetProperty || !(targetProperty.flags & SymbolFlags.EnumMember)) {
|
||||
reportError(Diagnostics.Property_0_is_missing_in_type_1,
|
||||
property.name,
|
||||
typeToString(target, /*enclosingDeclaration*/ undefined, TypeFormatFlags.UseFullyQualifiedType));
|
||||
return Ternary.False;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Ternary.True;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
}
|
||||
|
||||
function isPropertyIdenticalTo(sourceProp: Symbol, targetProp: Symbol): boolean {
|
||||
return compareProperties(sourceProp, targetProp, compareTypes) !== Ternary.False;
|
||||
return compareProperties(sourceProp, targetProp, compareTypesIdentical) !== Ternary.False;
|
||||
}
|
||||
|
||||
function compareProperties(sourceProp: Symbol, targetProp: Symbol, compareTypes: (source: Type, target: Type) => Ternary): Ternary {
|
||||
@@ -5752,7 +5870,11 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
function compareSignatures(source: Signature, target: Signature, partialMatch: boolean, ignoreReturnTypes: boolean, compareTypes: (s: Type, t: Type) => Ternary): Ternary {
|
||||
/**
|
||||
* See signatureRelatedTo, compareSignaturesIdentical
|
||||
*/
|
||||
function compareSignaturesIdentical(source: Signature, target: Signature, partialMatch: boolean, ignoreReturnTypes: boolean, compareTypes: (s: Type, t: Type) => Ternary): Ternary {
|
||||
// TODO (drosen): De-duplicate code between related functions.
|
||||
if (source === target) {
|
||||
return Ternary.True;
|
||||
}
|
||||
@@ -7460,7 +7582,7 @@ namespace ts {
|
||||
// This signature will contribute to contextual union signature
|
||||
signatureList = [signature];
|
||||
}
|
||||
else if (!compareSignatures(signatureList[0], signature, /*partialMatch*/ false, /*ignoreReturnTypes*/ true, compareTypes)) {
|
||||
else if (!compareSignaturesIdentical(signatureList[0], signature, /*partialMatch*/ false, /*ignoreReturnTypes*/ true, compareTypesIdentical)) {
|
||||
// Signatures aren't identical, do not use
|
||||
return undefined;
|
||||
}
|
||||
@@ -11480,7 +11602,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
for (const otherSignature of signaturesToCheck) {
|
||||
if (!otherSignature.hasStringLiterals && isSignatureAssignableTo(signature, otherSignature)) {
|
||||
if (!otherSignature.hasStringLiterals && isSignatureAssignableTo(signature, otherSignature, /*ignoreReturnTypes*/ false)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -11727,7 +11849,7 @@ namespace ts {
|
||||
//
|
||||
// The implementation is completely unrelated to the specialized signature, yet we do not check this.
|
||||
for (const signature of signatures) {
|
||||
if (!signature.hasStringLiterals && !isSignatureAssignableTo(bodySignature, signature)) {
|
||||
if (!signature.hasStringLiterals && !isImplementationCompatibleWithOverload(bodySignature, signature)) {
|
||||
error(signature.declaration, Diagnostics.Overload_signature_is_not_compatible_with_function_implementation);
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user