diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 781afe2cf9a84..a781628ee4061 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -17175,7 +17175,8 @@ namespace ts { let errorInfo: DiagnosticMessageChain | undefined; let relatedInfo: [DiagnosticRelatedInformation, ...DiagnosticRelatedInformation[]] | undefined; - let maybeKeys: string[]; + let maybeKeyList: string[]; + let maybeKeySet: Set; let sourceStack: Type[]; let targetStack: Type[]; let maybeCount = 0; @@ -18024,8 +18025,9 @@ namespace ts { return entry & RelationComparisonResult.Succeeded ? Ternary.True : Ternary.False; } } - if (!maybeKeys) { - maybeKeys = []; + if (!maybeKeyList) { + maybeKeyList = []; + maybeKeySet = new Set(); sourceStack = []; targetStack = []; } @@ -18037,11 +18039,9 @@ namespace ts { const index = length(id.slice(0, offset).match(/[-=]/g) || undefined); return `=${index}`; })).join(","); - for (let i = 0; i < maybeCount; i++) { + if (maybeKeySet.has(id) || maybeKeySet.has(broadestEquivalentId)) { // If source and target are already being compared, consider them related with assumptions - if (id === maybeKeys[i] || broadestEquivalentId === maybeKeys[i]) { - return Ternary.Maybe; - } + return Ternary.Maybe; } if (depth === 100) { overflow = true; @@ -18049,8 +18049,9 @@ namespace ts { } } const maybeStart = maybeCount; - maybeKeys[maybeCount] = id; + maybeKeyList[maybeCount] = id; maybeCount++; + maybeKeySet.add(id); sourceStack[depth] = source; targetStack[depth] = target; depth++; @@ -18083,22 +18084,27 @@ namespace ts { } expandingFlags = saveExpandingFlags; depth--; - if (result) { - if (result === Ternary.True || depth === 0) { - if (result === Ternary.True || result === Ternary.Maybe) { - // If result is definitely true, record all maybe keys as having succeeded. Also, record Ternary.Maybe - // results as having succeeded once we reach depth 0, but never record Ternary.Unknown results. - for (let i = maybeStart; i < maybeCount; i++) { - relation.set(maybeKeys[i], RelationComparisonResult.Succeeded | propagatingVarianceFlags); - } + if (result === Ternary.True || result === Ternary.False || depth === 0) { + if (result === Ternary.True || result === Ternary.Maybe) { + // If result is definitely true, record all maybe keys as having succeeded. Also, record Ternary.Maybe + // results as having succeeded once we reach depth 0, but never record Ternary.Unknown results. + for (let i = maybeStart; i < maybeCount; i++) { + relation.set(maybeKeyList[i], RelationComparisonResult.Succeeded | propagatingVarianceFlags); + } + } + else if (result === Ternary.False) { + // A false result goes straight into global cache (when something is false under + // assumptions it will also be false without assumptions) + relation.set(id, (reportErrors ? RelationComparisonResult.Reported : 0) | RelationComparisonResult.Failed | propagatingVarianceFlags); + } + if (maybeStart === 0) { + maybeKeySet.clear(); + } + else { + for (let i = maybeStart; i < maybeCount; i++) { + maybeKeySet.delete(maybeKeyList[i]); } - maybeCount = maybeStart; } - } - else { - // A false result goes straight into global cache (when something is false under - // assumptions it will also be false without assumptions) - relation.set(id, (reportErrors ? RelationComparisonResult.Reported : 0) | RelationComparisonResult.Failed | propagatingVarianceFlags); maybeCount = maybeStart; } return result;