From 0009999fa8b01ef71ff1782c50eddd3cca9a25dc Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 31 Jul 2023 21:45:12 -0700 Subject: [PATCH 1/9] Improve performance of maybe stack in recursiveTypeRelatedTo --- src/compiler/checker.ts | 43 +++++++++++++++++++++++++++-------------- src/compiler/core.ts | 42 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 15 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f24cb91da6394..6200925843f1f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -118,6 +118,7 @@ import { createPrinterWithRemoveCommentsNeverAsciiEscape, createPrinterWithRemoveCommentsOmitTrailingSemicolon, createPropertyNameNodeForIdentifierOrLiteral, + createStackSet, createSymbolTable, createTextWriter, Debug, @@ -962,6 +963,7 @@ import { SourceFile, SpreadAssignment, SpreadElement, + StackSet, startsWith, Statement, stringContains, @@ -20348,10 +20350,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let errorInfo: DiagnosticMessageChain | undefined; let relatedInfo: [DiagnosticRelatedInformation, ...DiagnosticRelatedInformation[]] | undefined; - let maybeKeys: string[]; + let maybeKeys: StackSet; let sourceStack: Type[]; let targetStack: Type[]; - let maybeCount = 0; let sourceDepth = 0; let targetDepth = 0; let expandingFlags = ExpandingFlags.None; @@ -21224,29 +21225,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } if (!maybeKeys) { - maybeKeys = []; + maybeKeys = createStackSet(); sourceStack = []; targetStack = []; } else { + // If source and target are already being compared, consider them related with assumptions + if (maybeKeys.has(id)) { + return Ternary.Maybe; + } + // A key that starts with "*" is an indication that we have type references that reference constrained // type parameters. For such keys we also check against the key we would have gotten if all type parameters // were unconstrained. const broadestEquivalentId = id.startsWith("*") ? getRelationKey(source, target, intersectionState, relation, /*ignoreConstraints*/ true) : undefined; - for (let i = 0; i < maybeCount; i++) { - // If source and target are already being compared, consider them related with assumptions - if (id === maybeKeys[i] || broadestEquivalentId && broadestEquivalentId === maybeKeys[i]) { - return Ternary.Maybe; - } + if (broadestEquivalentId && maybeKeys.has(broadestEquivalentId)) { + return Ternary.Maybe; } + if (sourceDepth === 100 || targetDepth === 100) { overflow = true; return Ternary.False; } } - const maybeStart = maybeCount; - maybeKeys[maybeCount] = id; - maybeCount++; + const maybeStart = maybeKeys.size; + maybeKeys.push(id); const saveExpandingFlags = expandingFlags; if (recursionFlags & RecursionFlags.Source) { sourceStack[sourceDepth] = source; @@ -21301,18 +21304,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { 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); + while (maybeKeys.size > maybeStart) { + const id = maybeKeys.pop(); + relation.set(id, RelationComparisonResult.Succeeded | propagatingVarianceFlags); + } + } + else { + while (maybeKeys.size > maybeStart) { + maybeKeys.pop(); } } - maybeCount = maybeStart; } + // Note: it's intentional that we don't pop in the else case; + // we leave them on the stack such that when we hit depth zero + // above, we can report all of them as successful. } 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; + while (maybeKeys.size > maybeStart) { + maybeKeys.pop(); + } } return result; } diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 6f80f5f145d30..28bcc58874730 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -2882,3 +2882,45 @@ export function isNodeLikeSystem(): boolean { && !(process as any).browser && typeof module === "object"; } + + +/** @internal */ +export interface StackSet { + has(value: T): boolean; + push(value: T): void; + pop(): T; + get size(): number; +} + +/** @internal */ +export function createStackSet(): StackSet { + const refs = new Map(); + const stack: T[] = []; + let end = 0; + return { + has(value) { + return refs.has(value); + }, + push(value) { + refs.set(value, (refs.get(value) ?? 0) + 1); + stack[end] = value; + end++; + }, + pop() { + end--; + Debug.assertGreaterThanOrEqual(end, 0); + const value = stack[end]; + const refCount = refs.get(value)! - 1; + if (refCount === 0) { + refs.delete(value); + } + else { + refs.set(value, refCount); + } + return value; + }, + get size() { + return end; + }, + }; +} From a703f482a86e6a53fba24fde6032c5fbf08a0df8 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Tue, 1 Aug 2023 11:22:55 -0700 Subject: [PATCH 2/9] Maybe improve perf --- src/compiler/checker.ts | 25 +++++++++++++++++-------- src/compiler/core.ts | 34 +++++++++++++++++----------------- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6200925843f1f..0903cb169c058 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -21248,7 +21248,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return Ternary.False; } } - const maybeStart = maybeKeys.size; + // const maybeStart = maybeKeys.size; maybeKeys.push(id); const saveExpandingFlags = expandingFlags; if (recursionFlags & RecursionFlags.Source) { @@ -21304,14 +21304,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { 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. - while (maybeKeys.size > maybeStart) { - const id = maybeKeys.pop(); - relation.set(id, RelationComparisonResult.Succeeded | propagatingVarianceFlags); + while (true) { + const popped = maybeKeys.pop(); + relation.set(popped, RelationComparisonResult.Succeeded | propagatingVarianceFlags); + if (popped === id) { + break; + } } } else { - while (maybeKeys.size > maybeStart) { - maybeKeys.pop(); + while (true) { + const popped = maybeKeys.pop(); + if (popped === id) { + break; + } } } } @@ -21323,8 +21329,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // 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); - while (maybeKeys.size > maybeStart) { - maybeKeys.pop(); + while (true) { + const popped = maybeKeys.pop(); + if (popped === id) { + break; + } } } return result; diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 28bcc58874730..f02b062d3de55 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -2889,38 +2889,38 @@ export interface StackSet { has(value: T): boolean; push(value: T): void; pop(): T; - get size(): number; + // get size(): number; } /** @internal */ export function createStackSet(): StackSet { - const refs = new Map(); - const stack: T[] = []; - let end = 0; + // Why var? It avoids TDZ checks in the runtime which can be costly. + // See: https://github.com/microsoft/TypeScript/issues/52924 + /* eslint-disable no-var */ + var set = new Set(); + var stack: T[] = []; + var end = 0; + /* eslint-enable no-var */ + return { has(value) { - return refs.has(value); + return set.has(value); }, push(value) { - refs.set(value, (refs.get(value) ?? 0) + 1); + // Debug.assert(!set.has(value), "Value already pushed"); + set.add(value); stack[end] = value; end++; }, pop() { end--; - Debug.assertGreaterThanOrEqual(end, 0); + // Debug.assertGreaterThanOrEqual(end, 0); const value = stack[end]; - const refCount = refs.get(value)! - 1; - if (refCount === 0) { - refs.delete(value); - } - else { - refs.set(value, refCount); - } + set.delete(value); return value; }, - get size() { - return end; - }, + // get size() { + // return end; + // }, }; } From 9e0cf58a69e18e39a229f66610a0506469c7b940 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Tue, 1 Aug 2023 12:20:59 -0700 Subject: [PATCH 3/9] Cleanup and docs --- src/compiler/checker.ts | 25 ++++++------------------- src/compiler/core.ts | 35 +++++++++++++++++++++++------------ 2 files changed, 29 insertions(+), 31 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0903cb169c058..5752981d28b84 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -21304,21 +21304,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { 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. - while (true) { - const popped = maybeKeys.pop(); - relation.set(popped, RelationComparisonResult.Succeeded | propagatingVarianceFlags); - if (popped === id) { - break; - } - } + maybeKeys.popAll(v => { + relation.set(v, RelationComparisonResult.Succeeded | propagatingVarianceFlags); + return v === id; + }); } else { - while (true) { - const popped = maybeKeys.pop(); - if (popped === id) { - break; - } - } + maybeKeys.popAll(v => v === id); } } // Note: it's intentional that we don't pop in the else case; @@ -21329,12 +21321,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // 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); - while (true) { - const popped = maybeKeys.pop(); - if (popped === id) { - break; - } - } + maybeKeys.popAll(v => v === id); } return result; } diff --git a/src/compiler/core.ts b/src/compiler/core.ts index f02b062d3de55..8a1212ad8c9b2 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -2886,10 +2886,22 @@ export function isNodeLikeSystem(): boolean { /** @internal */ export interface StackSet { + /** + * Returns true if the value has already been pushed. + */ has(value: T): boolean; + /** + * Pushes to the stack. The value pushed must not have been pushed before. + */ push(value: T): void; - pop(): T; - // get size(): number; + /** + * This pops from the stack until the callback returns true. + * + * Note that a value is popped, _then_ the callback is evaluated, meaning + * that if you return true to stop iteration, the value that the callback + * returned true for will still have been popped. + */ + popAll(callback: (v: T) => boolean): void; } /** @internal */ @@ -2907,20 +2919,19 @@ export function createStackSet(): StackSet { return set.has(value); }, push(value) { - // Debug.assert(!set.has(value), "Value already pushed"); set.add(value); stack[end] = value; end++; }, - pop() { - end--; - // Debug.assertGreaterThanOrEqual(end, 0); - const value = stack[end]; - set.delete(value); - return value; + popAll(callback) { + while (end > 0) { + end--; + const value = stack[end]; + set.delete(value); + if (callback(value)) { + break; + } + } }, - // get size() { - // return end; - // }, }; } From 0907e761b67e1cdae771d6f1d62a6113a77bc068 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Tue, 1 Aug 2023 12:22:04 -0700 Subject: [PATCH 4/9] Remove commented out code --- src/compiler/checker.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5752981d28b84..ec541e449834b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -21248,7 +21248,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return Ternary.False; } } - // const maybeStart = maybeKeys.size; maybeKeys.push(id); const saveExpandingFlags = expandingFlags; if (recursionFlags & RecursionFlags.Source) { From c31d069fe1f5e014e756af4e10133e57a77b41ab Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Tue, 1 Aug 2023 14:35:31 -0700 Subject: [PATCH 5/9] Re-add debug check on push, it's fast enough --- src/compiler/core.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 8a1212ad8c9b2..0c15e8697d6f1 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -2919,6 +2919,7 @@ export function createStackSet(): StackSet { return set.has(value); }, push(value) { + Debug.assert(!set.has(value)); set.add(value); stack[end] = value; end++; From 42d68cbae59c87bf97d28707607c9aeb52d3593f Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Tue, 1 Aug 2023 14:38:06 -0700 Subject: [PATCH 6/9] Pass the value to stop after rather than calling each time --- src/compiler/checker.ts | 7 +++---- src/compiler/core.ts | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ec541e449834b..871ad415db60a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -21303,13 +21303,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { 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. - maybeKeys.popAll(v => { + maybeKeys.popUntilInclusive(id, v => { relation.set(v, RelationComparisonResult.Succeeded | propagatingVarianceFlags); - return v === id; }); } else { - maybeKeys.popAll(v => v === id); + maybeKeys.popUntilInclusive(id); } } // Note: it's intentional that we don't pop in the else case; @@ -21320,7 +21319,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // 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); - maybeKeys.popAll(v => v === id); + maybeKeys.popUntilInclusive(id); } return result; } diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 0c15e8697d6f1..ad3e267888d78 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -2885,7 +2885,7 @@ export function isNodeLikeSystem(): boolean { /** @internal */ -export interface StackSet { +export interface StackSet { /** * Returns true if the value has already been pushed. */ @@ -2895,17 +2895,16 @@ export interface StackSet { */ push(value: T): void; /** - * This pops from the stack until the callback returns true. + * This pops from the stack, stopping iteration after v is found. * - * Note that a value is popped, _then_ the callback is evaluated, meaning - * that if you return true to stop iteration, the value that the callback - * returned true for will still have been popped. + * Note that the callback is evaluated _after_ the item is popped, meaning + * the callback will execute for v and it will not remain on the stack. */ - popAll(callback: (v: T) => boolean): void; + popUntilInclusive(v: T, callback?: (v: T) => void): void; } /** @internal */ -export function createStackSet(): StackSet { +export function createStackSet(): StackSet { // Why var? It avoids TDZ checks in the runtime which can be costly. // See: https://github.com/microsoft/TypeScript/issues/52924 /* eslint-disable no-var */ @@ -2924,13 +2923,14 @@ export function createStackSet(): StackSet { stack[end] = value; end++; }, - popAll(callback) { + popUntilInclusive(v, callback) { while (end > 0) { end--; const value = stack[end]; set.delete(value); - if (callback(value)) { - break; + callback?.(value); + if (value === v) { + return; } } }, From 6e3f4c54db1c7c1c420d1c50228320569eabf896 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Thu, 3 Aug 2023 14:09:35 -0700 Subject: [PATCH 7/9] Remove abstraction per Anders' feedback --- src/compiler/checker.ts | 36 ++++++++++++++++++--------- src/compiler/core.ts | 54 ----------------------------------------- 2 files changed, 24 insertions(+), 66 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index eb8c78d7c4068..00a0786e0f0eb 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -118,7 +118,6 @@ import { createPrinterWithRemoveCommentsNeverAsciiEscape, createPrinterWithRemoveCommentsOmitTrailingSemicolon, createPropertyNameNodeForIdentifierOrLiteral, - createStackSet, createSymbolTable, createTextWriter, Debug, @@ -963,7 +962,6 @@ import { SourceFile, SpreadAssignment, SpreadElement, - StackSet, startsWith, Statement, stringContains, @@ -20362,9 +20360,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let errorInfo: DiagnosticMessageChain | undefined; let relatedInfo: [DiagnosticRelatedInformation, ...DiagnosticRelatedInformation[]] | undefined; - let maybeKeys: StackSet; + let maybeKeys: string[]; + let maybeKeysSet: Set; let sourceStack: Type[]; let targetStack: Type[]; + let maybeCount = 0; let sourceDepth = 0; let targetDepth = 0; let expandingFlags = ExpandingFlags.None; @@ -21237,13 +21237,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } if (!maybeKeys) { - maybeKeys = createStackSet(); + maybeKeys = []; + maybeKeysSet = new Set(); sourceStack = []; targetStack = []; } else { // If source and target are already being compared, consider them related with assumptions - if (maybeKeys.has(id)) { + if (maybeKeysSet.has(id)) { return Ternary.Maybe; } @@ -21251,7 +21252,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // type parameters. For such keys we also check against the key we would have gotten if all type parameters // were unconstrained. const broadestEquivalentId = id.startsWith("*") ? getRelationKey(source, target, intersectionState, relation, /*ignoreConstraints*/ true) : undefined; - if (broadestEquivalentId && maybeKeys.has(broadestEquivalentId)) { + if (broadestEquivalentId && maybeKeysSet.has(broadestEquivalentId)) { return Ternary.Maybe; } @@ -21260,7 +21261,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return Ternary.False; } } - maybeKeys.push(id); + const maybeStart = maybeCount; + maybeKeys[maybeCount] = id; + maybeKeysSet.add(id); + maybeCount++; const saveExpandingFlags = expandingFlags; if (recursionFlags & RecursionFlags.Source) { sourceStack[sourceDepth] = source; @@ -21315,12 +21319,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { 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. - maybeKeys.popUntilInclusive(id, v => { - relation.set(v, RelationComparisonResult.Succeeded | propagatingVarianceFlags); - }); + resetMaybeStack(/*markAllAsSucceeded*/ true); } else { - maybeKeys.popUntilInclusive(id); + resetMaybeStack(); } } // Note: it's intentional that we don't pop in the else case; @@ -21331,9 +21333,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // 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); - maybeKeys.popUntilInclusive(id); + resetMaybeStack(); } return result; + + function resetMaybeStack(markAllAsSucceeded = false) { + for (let i = maybeStart; i < maybeCount; i++) { + maybeKeysSet.delete(maybeKeys[i]); + if (markAllAsSucceeded) { + relation.set(maybeKeys[i], RelationComparisonResult.Succeeded | propagatingVarianceFlags); + } + } + maybeCount = maybeStart; + } } function structuredTypeRelatedTo(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary { diff --git a/src/compiler/core.ts b/src/compiler/core.ts index ad3e267888d78..6f80f5f145d30 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -2882,57 +2882,3 @@ export function isNodeLikeSystem(): boolean { && !(process as any).browser && typeof module === "object"; } - - -/** @internal */ -export interface StackSet { - /** - * Returns true if the value has already been pushed. - */ - has(value: T): boolean; - /** - * Pushes to the stack. The value pushed must not have been pushed before. - */ - push(value: T): void; - /** - * This pops from the stack, stopping iteration after v is found. - * - * Note that the callback is evaluated _after_ the item is popped, meaning - * the callback will execute for v and it will not remain on the stack. - */ - popUntilInclusive(v: T, callback?: (v: T) => void): void; -} - -/** @internal */ -export function createStackSet(): StackSet { - // Why var? It avoids TDZ checks in the runtime which can be costly. - // See: https://github.com/microsoft/TypeScript/issues/52924 - /* eslint-disable no-var */ - var set = new Set(); - var stack: T[] = []; - var end = 0; - /* eslint-enable no-var */ - - return { - has(value) { - return set.has(value); - }, - push(value) { - Debug.assert(!set.has(value)); - set.add(value); - stack[end] = value; - end++; - }, - popUntilInclusive(v, callback) { - while (end > 0) { - end--; - const value = stack[end]; - set.delete(value); - callback?.(value); - if (value === v) { - return; - } - } - }, - }; -} From b59f2b6b623cd1df584b03de658d946bb1b24681 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Thu, 3 Aug 2023 14:10:17 -0700 Subject: [PATCH 8/9] Remove reference to popping from comment --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 00a0786e0f0eb..e3a189f94978f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -21325,7 +21325,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { resetMaybeStack(); } } - // Note: it's intentional that we don't pop in the else case; + // Note: it's intentional that we don't reset in the else case; // we leave them on the stack such that when we hit depth zero // above, we can report all of them as successful. } From 6156ade8ba27990868824946057a03be2f09dcd2 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Thu, 3 Aug 2023 14:20:21 -0700 Subject: [PATCH 9/9] Make parameter required --- src/compiler/checker.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e3a189f94978f..c150f281a3041 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -21322,7 +21322,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { resetMaybeStack(/*markAllAsSucceeded*/ true); } else { - resetMaybeStack(); + resetMaybeStack(/*markAllAsSucceeded*/ false); } } // Note: it's intentional that we don't reset in the else case; @@ -21333,11 +21333,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // 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); - resetMaybeStack(); + resetMaybeStack(/*markAllAsSucceeded*/ false); } return result; - function resetMaybeStack(markAllAsSucceeded = false) { + function resetMaybeStack(markAllAsSucceeded: boolean) { for (let i = maybeStart; i < maybeCount; i++) { maybeKeysSet.delete(maybeKeys[i]); if (markAllAsSucceeded) {