@@ -20361,6 +20361,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2036120361 let errorInfo: DiagnosticMessageChain | undefined;
2036220362 let relatedInfo: [DiagnosticRelatedInformation, ...DiagnosticRelatedInformation[]] | undefined;
2036320363 let maybeKeys: string[];
20364+ let maybeKeysSet: Set<string>;
2036420365 let sourceStack: Type[];
2036520366 let targetStack: Type[];
2036620367 let maybeCount = 0;
@@ -21237,27 +21238,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2123721238 }
2123821239 if (!maybeKeys) {
2123921240 maybeKeys = [];
21241+ maybeKeysSet = new Set();
2124021242 sourceStack = [];
2124121243 targetStack = [];
2124221244 }
2124321245 else {
21246+ // If source and target are already being compared, consider them related with assumptions
21247+ if (maybeKeysSet.has(id)) {
21248+ return Ternary.Maybe;
21249+ }
21250+
2124421251 // A key that starts with "*" is an indication that we have type references that reference constrained
2124521252 // type parameters. For such keys we also check against the key we would have gotten if all type parameters
2124621253 // were unconstrained.
2124721254 const broadestEquivalentId = id.startsWith("*") ? getRelationKey(source, target, intersectionState, relation, /*ignoreConstraints*/ true) : undefined;
21248- for (let i = 0; i < maybeCount; i++) {
21249- // If source and target are already being compared, consider them related with assumptions
21250- if (id === maybeKeys[i] || broadestEquivalentId && broadestEquivalentId === maybeKeys[i]) {
21251- return Ternary.Maybe;
21252- }
21255+ if (broadestEquivalentId && maybeKeysSet.has(broadestEquivalentId)) {
21256+ return Ternary.Maybe;
2125321257 }
21258+
2125421259 if (sourceDepth === 100 || targetDepth === 100) {
2125521260 overflow = true;
2125621261 return Ternary.False;
2125721262 }
2125821263 }
2125921264 const maybeStart = maybeCount;
2126021265 maybeKeys[maybeCount] = id;
21266+ maybeKeysSet.add(id);
2126121267 maybeCount++;
2126221268 const saveExpandingFlags = expandingFlags;
2126321269 if (recursionFlags & RecursionFlags.Source) {
@@ -21313,20 +21319,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2131321319 if (result === Ternary.True || result === Ternary.Maybe) {
2131421320 // If result is definitely true, record all maybe keys as having succeeded. Also, record Ternary.Maybe
2131521321 // results as having succeeded once we reach depth 0, but never record Ternary.Unknown results.
21316- for (let i = maybeStart; i < maybeCount; i++) {
21317- relation.set(maybeKeys[i], RelationComparisonResult.Succeeded | propagatingVarianceFlags);
21318- }
21322+ resetMaybeStack(/*markAllAsSucceeded*/ true);
21323+ }
21324+ else {
21325+ resetMaybeStack(/*markAllAsSucceeded*/ false);
2131921326 }
21320- maybeCount = maybeStart;
2132121327 }
21328+ // Note: it's intentional that we don't reset in the else case;
21329+ // we leave them on the stack such that when we hit depth zero
21330+ // above, we can report all of them as successful.
2132221331 }
2132321332 else {
2132421333 // A false result goes straight into global cache (when something is false under
2132521334 // assumptions it will also be false without assumptions)
2132621335 relation.set(id, (reportErrors ? RelationComparisonResult.Reported : 0) | RelationComparisonResult.Failed | propagatingVarianceFlags);
21327- maybeCount = maybeStart ;
21336+ resetMaybeStack(/*markAllAsSucceeded*/ false) ;
2132821337 }
2132921338 return result;
21339+
21340+ function resetMaybeStack(markAllAsSucceeded: boolean) {
21341+ for (let i = maybeStart; i < maybeCount; i++) {
21342+ maybeKeysSet.delete(maybeKeys[i]);
21343+ if (markAllAsSucceeded) {
21344+ relation.set(maybeKeys[i], RelationComparisonResult.Succeeded | propagatingVarianceFlags);
21345+ }
21346+ }
21347+ maybeCount = maybeStart;
21348+ }
2133021349 }
2133121350
2133221351 function structuredTypeRelatedTo(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary {
0 commit comments