mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Elaborate relational errors at least once when reporting them
This commit is contained in:
+24
-12
@@ -3365,9 +3365,9 @@ module ts {
|
||||
|
||||
// TYPE CHECKING
|
||||
|
||||
var subtypeRelation: Map<boolean> = {};
|
||||
var assignableRelation: Map<boolean> = {};
|
||||
var identityRelation: Map<boolean> = {};
|
||||
var subtypeRelation: Map<RelationComparisonResult> = {};
|
||||
var assignableRelation: Map<RelationComparisonResult> = {};
|
||||
var identityRelation: Map<RelationComparisonResult> = {};
|
||||
|
||||
function isTypeIdenticalTo(source: Type, target: Type): boolean {
|
||||
return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined);
|
||||
@@ -3402,7 +3402,7 @@ module ts {
|
||||
function checkTypeRelatedTo(
|
||||
source: Type,
|
||||
target: Type,
|
||||
relation: Map<boolean>,
|
||||
relation: Map<RelationComparisonResult>,
|
||||
errorNode: Node,
|
||||
headMessage?: DiagnosticMessage,
|
||||
containingMessageChain?: DiagnosticMessageChain): boolean {
|
||||
@@ -3422,6 +3422,14 @@ module ts {
|
||||
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 !== undefined, headMessage, true);
|
||||
}
|
||||
if (containingMessageChain) {
|
||||
errorInfo = concatenateDiagnosticMessageChains(containingMessageChain, errorInfo);
|
||||
}
|
||||
@@ -3437,7 +3445,7 @@ module 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?: boolean, headMessage?: DiagnosticMessage): Ternary {
|
||||
function isRelatedTo(source: Type, target: Type, reportErrors?: boolean, headMessage?: DiagnosticMessage, mustRecompute = false): Ternary {
|
||||
var 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;
|
||||
@@ -3504,7 +3512,7 @@ module ts {
|
||||
// identity relation does not use apparent type
|
||||
var sourceOrApparentType = relation === identityRelation ? source : getApparentType(source);
|
||||
if (sourceOrApparentType.flags & TypeFlags.ObjectType && target.flags & TypeFlags.ObjectType &&
|
||||
(result = objectTypeRelatedTo(sourceOrApparentType, <ObjectType>target, reportStructuralErrors))) {
|
||||
(result = objectTypeRelatedTo(sourceOrApparentType, <ObjectType>target, reportStructuralErrors, mustRecompute))) {
|
||||
errorInfo = saveErrorInfo;
|
||||
return result;
|
||||
}
|
||||
@@ -3595,14 +3603,16 @@ module 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: ObjectType, target: ObjectType, reportErrors: boolean): Ternary {
|
||||
function objectTypeRelatedTo(source: ObjectType, target: ObjectType, reportErrors: boolean, elaborateErrors = false): Ternary {
|
||||
if (overflow) {
|
||||
return Ternary.False;
|
||||
}
|
||||
var id = relation !== identityRelation || source.id < target.id ? source.id + "," + target.id : target.id + "," + source.id;
|
||||
var related = relation[id];
|
||||
if (related !== undefined) {
|
||||
return related ? Ternary.True : Ternary.False;
|
||||
if (!elaborateErrors || related === RelationComparisonResult.FailedAndReported) {
|
||||
return related === RelationComparisonResult.Succeeded ? Ternary.True : Ternary.False;
|
||||
}
|
||||
}
|
||||
if (depth > 0) {
|
||||
for (var i = 0; i < depth; i++) {
|
||||
@@ -3654,12 +3664,14 @@ module ts {
|
||||
var maybeCache = maybeStack[depth];
|
||||
// If result is definitely true, copy assumptions to global cache, else copy to next level up
|
||||
var destinationCache = result === Ternary.True || depth === 0 ? relation : maybeStack[depth - 1];
|
||||
copyMap(/*source*/maybeCache, /*target*/destinationCache);
|
||||
for (var key in maybeCache) {
|
||||
destinationCache[key] = maybeCache[key] ? RelationComparisonResult.Succeeded : RelationComparisonResult.Failed;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// A false result goes straight into global cache (when something is false under assumptions it
|
||||
// will also be false without assumptions)
|
||||
relation[id] = false;
|
||||
relation[id] = reportErrors ? RelationComparisonResult.FailedAndReported : RelationComparisonResult.Failed;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -5865,7 +5877,7 @@ module ts {
|
||||
return typeArgumentsAreAssignable;
|
||||
}
|
||||
|
||||
function checkApplicableSignature(node: CallLikeExpression, args: Node[], signature: Signature, relation: Map<boolean>, excludeArgument: boolean[], reportErrors: boolean) {
|
||||
function checkApplicableSignature(node: CallLikeExpression, args: Node[], signature: Signature, relation: Map<RelationComparisonResult>, excludeArgument: boolean[], reportErrors: boolean) {
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
var arg = args[i];
|
||||
var argType: Type;
|
||||
@@ -6059,7 +6071,7 @@ module ts {
|
||||
|
||||
return resolveErrorCall(node);
|
||||
|
||||
function chooseOverload(candidates: Signature[], relation: Map<boolean>) {
|
||||
function chooseOverload(candidates: Signature[], relation: Map<RelationComparisonResult>) {
|
||||
for (var i = 0; i < candidates.length; i++) {
|
||||
if (!hasCorrectArity(node, args, candidates[i])) {
|
||||
continue;
|
||||
|
||||
@@ -330,6 +330,12 @@ module ts {
|
||||
HasAggregatedChildData = 1 << 6
|
||||
}
|
||||
|
||||
export const enum RelationComparisonResult {
|
||||
Succeeded = 0,
|
||||
Failed = 1,
|
||||
FailedAndReported = 2
|
||||
}
|
||||
|
||||
export interface Node extends TextRange {
|
||||
kind: SyntaxKind;
|
||||
flags: NodeFlags;
|
||||
|
||||
Reference in New Issue
Block a user