diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4a73e071061..2ce41bb4878 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2,24 +2,6 @@ /* @internal */ namespace ts { - const enum ReportErrors { - /** - * Do not report errors at all. - */ - None, - /** - * Report errors in any fashion if any are encountered. - * This option implies that if an error has already been cached for a relationship - * between two types, it is okay to use the top-level error without elaboration. - */ - Basic, - /** - * Always force elaboration when comparing two types, - * even if the relation has been cached - */ - Elaborate, - } - let nextSymbolId = 1; let nextNodeId = 1; let nextMergeId = 1; @@ -4937,7 +4919,7 @@ namespace ts { function isSignatureAssignableTo(source: Signature, target: Signature, ignoreReturnTypes: boolean): boolean { - return compareSignaturesRelated(source, target, ignoreReturnTypes, ReportErrors.None, /*errorReporter*/ undefined, compareTypesAssignable) !== Ternary.False; + return compareSignaturesRelated(source, target, ignoreReturnTypes, /*reportErrors*/ false, /*errorReporter*/ undefined, compareTypesAssignable) !== Ternary.False; } /** @@ -4946,9 +4928,9 @@ namespace ts { function compareSignaturesRelated(source: Signature, target: Signature, ignoreReturnTypes: boolean, - reportErrors: ReportErrors, + reportErrors: boolean, errorReporter: (d: DiagnosticMessage, arg0?: string, arg1?: string) => void, - compareTypes: (s: Type, t: Type, reportErrors?: ReportErrors) => Ternary): Ternary { + compareTypes: (s: Type, t: Type, reportErrors?: boolean) => Ternary): Ternary { // TODO (drosen): De-duplicate code between related functions. if (source === target) { return Ternary.True; @@ -4972,7 +4954,7 @@ namespace ts { for (let i = 0; i < checkCount; i++) { const s = i < sourceMax ? getTypeOfSymbol(sourceParams[i]) : getRestTypeOfSignature(source); const t = i < targetMax ? getTypeOfSymbol(targetParams[i]) : getRestTypeOfSignature(target); - const related = compareTypes(t, s, /*reportErrors*/ ReportErrors.None) || compareTypes(s, t, reportErrors); + const related = compareTypes(t, s, /*reportErrors*/ false) || compareTypes(s, t, reportErrors); if (!related) { if (reportErrors) { errorReporter(Diagnostics.Types_of_parameters_0_and_1_are_incompatible, @@ -5078,19 +5060,11 @@ namespace ts { Debug.assert(relation !== identityRelation || !errorNode, "no error reporting in identity checking"); - const result = isRelatedTo(source, target, !!errorNode ? ReportErrors.Basic : ReportErrors.None, headMessage); + const result = isRelatedTo(source, target, /*reportErrors*/ !!errorNode, headMessage); if (overflow) { error(errorNode, Diagnostics.Excessive_stack_depth_comparing_types_0_and_1, typeToString(source), typeToString(target)); } else if (errorInfo) { - // If we already computed this relation, but in a context where we didn't want to report errors (e.g. overload resolution), - // then we'll only have a top-level error (e.g. 'Class X does not implement interface Y') without any details. If this happened, - // request a recompuation to get a complete error message. This will be skipped if we've already done this computation in a context - // where errors were being reported. - if (errorInfo.next === undefined) { - errorInfo = undefined; - isRelatedTo(source, target, !!errorNode ? ReportErrors.Elaborate : ReportErrors.None, headMessage); - } if (containingMessageChain) { errorInfo = concatenateDiagnosticMessageChains(containingMessageChain, errorInfo); } @@ -5118,7 +5092,7 @@ namespace ts { // Ternary.True if they are related with no assumptions, // Ternary.Maybe if they are related with assumptions of other relationships, or // Ternary.False if they are not related. - function isRelatedTo(source: Type, target: Type, reportErrors?: ReportErrors, headMessage?: DiagnosticMessage): Ternary { + function isRelatedTo(source: Type, target: Type, reportErrors?: boolean, headMessage?: DiagnosticMessage): Ternary { let result: Ternary; // both types are the same - covers 'they are the same primitive type or both are Any' or the same type parameter cases if (source === target) return Ternary.True; @@ -5206,7 +5180,7 @@ namespace ts { // A & B = (A & B) | (C & D). if (source.flags & TypeFlags.Intersection) { // If target is a union type the following check will report errors so we suppress them here - if (result = someTypeRelatedToType(source, target, !(target.flags & TypeFlags.Union) ? reportErrors : ReportErrors.None)) { + if (result = someTypeRelatedToType(source, target, reportErrors && !(target.flags & TypeFlags.Union))) { return result; } } @@ -5223,7 +5197,7 @@ namespace ts { constraint = emptyObjectType; } // Report constraint errors only if the constraint is not the empty object type - const reportConstraintErrors = constraint !== emptyObjectType ? reportErrors : ReportErrors.None; + const reportConstraintErrors = reportErrors && constraint !== emptyObjectType; if (result = isRelatedTo(constraint, target, reportConstraintErrors)) { errorInfo = saveErrorInfo; return result; @@ -5244,9 +5218,7 @@ namespace ts { // relates to X. Thus, we include intersection types on the source side here. if (apparentSource.flags & (TypeFlags.ObjectType | TypeFlags.Intersection) && target.flags & TypeFlags.ObjectType) { // Report structural errors only if we haven't reported any errors yet - const reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo && !(source.flags & TypeFlags.Primitive) - ? ReportErrors.Elaborate - : ReportErrors.None; + const reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo && !(source.flags & TypeFlags.Primitive); if (result = objectTypeRelatedTo(apparentSource, source, target, reportStructuralErrors)) { errorInfo = saveErrorInfo; return result; @@ -5265,11 +5237,11 @@ namespace ts { if (source.flags & TypeFlags.ObjectType && target.flags & TypeFlags.ObjectType) { if (source.flags & TypeFlags.Reference && target.flags & TypeFlags.Reference && (source).target === (target).target) { // We have type references to same target type, see if all type arguments are identical - if (result = typeArgumentsRelatedTo(source, target, ReportErrors.None)) { + if (result = typeArgumentsRelatedTo(source, target, /*reportErrors*/ false)) { return result; } } - return objectTypeRelatedTo(source, source, target, ReportErrors.None); + return objectTypeRelatedTo(source, source, target, /*reportErrors*/ false); } if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union || source.flags & TypeFlags.Intersection && target.flags & TypeFlags.Intersection) { @@ -5304,7 +5276,7 @@ namespace ts { return false; } - function hasExcessProperties(source: FreshObjectLiteralType, target: Type, reportErrors: ReportErrors): boolean { + function hasExcessProperties(source: FreshObjectLiteralType, target: Type, reportErrors: boolean): boolean { if (!(target.flags & TypeFlags.ObjectLiteralPatternWithComputedProperties) && someConstituentTypeHasKind(target, TypeFlags.ObjectType)) { for (const prop of getPropertiesOfObjectType(source)) { if (!isKnownProperty(target, prop.name)) { @@ -5328,7 +5300,7 @@ namespace ts { let result = Ternary.True; const sourceTypes = source.types; for (const sourceType of sourceTypes) { - const related = typeRelatedToSomeType(sourceType, target, ReportErrors.None); + const related = typeRelatedToSomeType(sourceType, target, /*reportErrors*/ false); if (!related) { return Ternary.False; } @@ -5337,10 +5309,10 @@ namespace ts { return result; } - function typeRelatedToSomeType(source: Type, target: UnionOrIntersectionType, reportErrors: ReportErrors): Ternary { + function typeRelatedToSomeType(source: Type, target: UnionOrIntersectionType, reportErrors: boolean): Ternary { const targetTypes = target.types; for (let i = 0, len = targetTypes.length; i < len; i++) { - const related = isRelatedTo(source, targetTypes[i], i === len - 1 ? reportErrors : ReportErrors.None); + const related = isRelatedTo(source, targetTypes[i], reportErrors && i === len - 1); if (related) { return related; } @@ -5348,7 +5320,7 @@ namespace ts { return Ternary.False; } - function typeRelatedToEachType(source: Type, target: UnionOrIntersectionType, reportErrors: ReportErrors): Ternary { + function typeRelatedToEachType(source: Type, target: UnionOrIntersectionType, reportErrors: boolean): Ternary { let result = Ternary.True; const targetTypes = target.types; for (const targetType of targetTypes) { @@ -5361,10 +5333,10 @@ namespace ts { return result; } - function someTypeRelatedToType(source: UnionOrIntersectionType, target: Type, reportErrors: ReportErrors): Ternary { + function someTypeRelatedToType(source: UnionOrIntersectionType, target: Type, reportErrors: boolean): Ternary { const sourceTypes = source.types; for (let i = 0, len = sourceTypes.length; i < len; i++) { - const related = isRelatedTo(sourceTypes[i], target, i === len - 1 ? reportErrors : ReportErrors.None); + const related = isRelatedTo(sourceTypes[i], target, reportErrors && i === len - 1); if (related) { return related; } @@ -5372,7 +5344,7 @@ namespace ts { return Ternary.False; } - function eachTypeRelatedToType(source: UnionOrIntersectionType, target: Type, reportErrors: ReportErrors): Ternary { + function eachTypeRelatedToType(source: UnionOrIntersectionType, target: Type, reportErrors: boolean): Ternary { let result = Ternary.True; const sourceTypes = source.types; for (const sourceType of sourceTypes) { @@ -5385,7 +5357,7 @@ namespace ts { return result; } - function typeArgumentsRelatedTo(source: TypeReference, target: TypeReference, reportErrors: ReportErrors): Ternary { + function typeArgumentsRelatedTo(source: TypeReference, target: TypeReference, reportErrors: boolean): Ternary { const sources = source.typeArguments || emptyArray; const targets = target.typeArguments || emptyArray; if (sources.length !== targets.length && relation === identityRelation) { @@ -5408,14 +5380,14 @@ namespace ts { // Third, check if both types are part of deeply nested chains of generic type instantiations and if so assume the types are // equal and infinitely expanding. Fourth, if we have reached a depth of 100 nested comparisons, assume we have runaway recursion // and issue an error. Otherwise, actually compare the structure of the two types. - function objectTypeRelatedTo(source: Type, originalSource: Type, target: Type, reportErrors: ReportErrors): Ternary { + function objectTypeRelatedTo(source: Type, originalSource: Type, target: Type, reportErrors: boolean): Ternary { if (overflow) { return Ternary.False; } const id = relation !== identityRelation || source.id < target.id ? source.id + "," + target.id : target.id + "," + source.id; const related = relation[id]; if (related !== undefined) { - if (reportErrors === ReportErrors.Elaborate && related === RelationComparisonResult.Failed) { + if (reportErrors && related === RelationComparisonResult.Failed) { // We are elaborating errors and the cached result is an unreported failure. Record the result as a reported // failure and continue computing the relation such that errors get reported. relation[id] = RelationComparisonResult.FailedAndReported; @@ -5485,7 +5457,7 @@ namespace ts { return result; } - function propertiesRelatedTo(source: Type, target: Type, reportErrors: ReportErrors): Ternary { + function propertiesRelatedTo(source: Type, target: Type, reportErrors: boolean): Ternary { if (relation === identityRelation) { return propertiesIdenticalTo(source, target); } @@ -5593,7 +5565,7 @@ namespace ts { return result; } - function signaturesRelatedTo(source: Type, target: Type, kind: SignatureKind, reportErrors: ReportErrors): Ternary { + function signaturesRelatedTo(source: Type, target: Type, kind: SignatureKind, reportErrors: boolean): Ternary { if (relation === identityRelation) { return signaturesIdenticalTo(source, target, kind); } @@ -5630,7 +5602,7 @@ namespace ts { errorInfo = saveErrorInfo; continue outer; } - shouldElaborateErrors = ReportErrors.None; + shouldElaborateErrors = false; } } // don't elaborate the primitive apparent types (like Number) @@ -5649,7 +5621,7 @@ namespace ts { /** * See signatureAssignableTo, compareSignaturesIdentical */ - function signatureRelatedTo(source: Signature, target: Signature, reportErrors: ReportErrors): Ternary { + function signatureRelatedTo(source: Signature, target: Signature, reportErrors: boolean): Ternary { return compareSignaturesRelated(source, target, /*ignoreReturnTypes*/ false, reportErrors, reportError, isRelatedTo); } @@ -5670,7 +5642,7 @@ namespace ts { return result; } - function stringIndexTypesRelatedTo(source: Type, originalSource: Type, target: Type, reportErrors: ReportErrors): Ternary { + function stringIndexTypesRelatedTo(source: Type, originalSource: Type, target: Type, reportErrors: boolean): Ternary { if (relation === identityRelation) { return indexTypesIdenticalTo(IndexKind.String, source, target); } @@ -5700,7 +5672,7 @@ namespace ts { return Ternary.True; } - function numberIndexTypesRelatedTo(source: Type, originalSource: Type, target: Type, reportErrors: ReportErrors): Ternary { + function numberIndexTypesRelatedTo(source: Type, originalSource: Type, target: Type, reportErrors: boolean): Ternary { if (relation === identityRelation) { return indexTypesIdenticalTo(IndexKind.Number, source, target); } @@ -5722,7 +5694,7 @@ namespace ts { let related: Ternary; if (sourceStringType && sourceNumberType) { // If we know for sure we're testing both string and numeric index types then only report errors from the second one - related = isRelatedTo(sourceStringType, targetType, ReportErrors.None) || isRelatedTo(sourceNumberType, targetType, reportErrors); + related = isRelatedTo(sourceStringType, targetType, /*reportErrors*/ false) || isRelatedTo(sourceNumberType, targetType, reportErrors); } else { related = isRelatedTo(sourceStringType || sourceNumberType, targetType, reportErrors); @@ -9003,7 +8975,7 @@ namespace ts { getInferredTypes(context); } - function checkTypeArguments(signature: Signature, typeArgumentNodes: TypeNode[], typeArgumentTypes: Type[], reportErrors: ReportErrors, headMessage?: DiagnosticMessage): boolean { + function checkTypeArguments(signature: Signature, typeArgumentNodes: TypeNode[], typeArgumentTypes: Type[], reportErrors: boolean, headMessage?: DiagnosticMessage): boolean { const typeParameters = signature.typeParameters; let typeArgumentsAreAssignable = true; let mapper: TypeMapper; @@ -9033,7 +9005,7 @@ namespace ts { return typeArgumentsAreAssignable; } - function checkApplicableSignature(node: CallLikeExpression, args: Expression[], signature: Signature, relation: Map, excludeArgument: boolean[], reportErrors: ReportErrors) { + function checkApplicableSignature(node: CallLikeExpression, args: Expression[], signature: Signature, relation: Map, excludeArgument: boolean[], reportErrors: boolean) { const argCount = getEffectiveArgumentCount(node, args, signature); for (let i = 0; i < argCount; i++) { const arg = getEffectiveArgument(node, args, i); @@ -9481,12 +9453,12 @@ namespace ts { // in arguments too early. If possible, we'd like to only type them once we know the correct // overload. However, this matters for the case where the call is correct. When the call is // an error, we don't need to exclude any arguments, although it would cause no harm to do so. - checkApplicableSignature(node, args, candidateForArgumentError, assignableRelation, /*excludeArgument*/ undefined, ReportErrors.Basic); + checkApplicableSignature(node, args, candidateForArgumentError, assignableRelation, /*excludeArgument*/ undefined, /*reportErrors*/ true); } else if (candidateForTypeArgumentError) { if (!isTaggedTemplate && !isDecorator && typeArguments) { const typeArguments = (node).typeArguments; - checkTypeArguments(candidateForTypeArgumentError, typeArguments, map(typeArguments, getTypeFromTypeNode), ReportErrors.Basic, headMessage); + checkTypeArguments(candidateForTypeArgumentError, typeArguments, map(typeArguments, getTypeFromTypeNode), /*reportErrors*/ true, headMessage); } else { Debug.assert(resultOfFailedInference.failedTypeParameterIndex >= 0); @@ -9554,7 +9526,7 @@ namespace ts { let typeArgumentTypes: Type[]; if (typeArguments) { typeArgumentTypes = map(typeArguments, getTypeFromTypeNode); - typeArgumentsAreValid = checkTypeArguments(candidate, typeArguments, typeArgumentTypes, ReportErrors.None); + typeArgumentsAreValid = checkTypeArguments(candidate, typeArguments, typeArgumentTypes, /*reportErrors*/ false); } else { inferTypeArguments(node, candidate, args, excludeArgument, inferenceContext); @@ -9566,7 +9538,7 @@ namespace ts { } candidate = getSignatureInstantiation(candidate, typeArgumentTypes); } - if (!checkApplicableSignature(node, args, candidate, relation, excludeArgument, ReportErrors.None)) { + if (!checkApplicableSignature(node, args, candidate, relation, excludeArgument, /*reportErrors*/ false)) { break; } const index = excludeArgument ? indexOf(excludeArgument, true) : -1;