@@ -20361,6 +20361,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
20361
20361
let errorInfo: DiagnosticMessageChain | undefined;
20362
20362
let relatedInfo: [DiagnosticRelatedInformation, ...DiagnosticRelatedInformation[]] | undefined;
20363
20363
let maybeKeys: string[];
20364
+ let maybeKeysSet: Set<string>;
20364
20365
let sourceStack: Type[];
20365
20366
let targetStack: Type[];
20366
20367
let maybeCount = 0;
@@ -21237,27 +21238,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
21237
21238
}
21238
21239
if (!maybeKeys) {
21239
21240
maybeKeys = [];
21241
+ maybeKeysSet = new Set();
21240
21242
sourceStack = [];
21241
21243
targetStack = [];
21242
21244
}
21243
21245
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
+
21244
21251
// A key that starts with "*" is an indication that we have type references that reference constrained
21245
21252
// type parameters. For such keys we also check against the key we would have gotten if all type parameters
21246
21253
// were unconstrained.
21247
21254
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;
21253
21257
}
21258
+
21254
21259
if (sourceDepth === 100 || targetDepth === 100) {
21255
21260
overflow = true;
21256
21261
return Ternary.False;
21257
21262
}
21258
21263
}
21259
21264
const maybeStart = maybeCount;
21260
21265
maybeKeys[maybeCount] = id;
21266
+ maybeKeysSet.add(id);
21261
21267
maybeCount++;
21262
21268
const saveExpandingFlags = expandingFlags;
21263
21269
if (recursionFlags & RecursionFlags.Source) {
@@ -21313,20 +21319,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
21313
21319
if (result === Ternary.True || result === Ternary.Maybe) {
21314
21320
// If result is definitely true, record all maybe keys as having succeeded. Also, record Ternary.Maybe
21315
21321
// 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);
21319
21326
}
21320
- maybeCount = maybeStart;
21321
21327
}
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.
21322
21331
}
21323
21332
else {
21324
21333
// A false result goes straight into global cache (when something is false under
21325
21334
// assumptions it will also be false without assumptions)
21326
21335
relation.set(id, (reportErrors ? RelationComparisonResult.Reported : 0) | RelationComparisonResult.Failed | propagatingVarianceFlags);
21327
- maybeCount = maybeStart ;
21336
+ resetMaybeStack(/*markAllAsSucceeded*/ false) ;
21328
21337
}
21329
21338
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
+ }
21330
21349
}
21331
21350
21332
21351
function structuredTypeRelatedTo(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary {
0 commit comments