Skip to content

Commit 6d3be98

Browse files
Andaristgabritto
andauthored
Fixed regression in reverse mapped type inference caused by cache leak (#59232)
Co-authored-by: Gabriela Araujo Britto <[email protected]>
1 parent 9c093c1 commit 6d3be98

6 files changed

+300
-13
lines changed

src/compiler/checker.ts

+24-5
Original file line numberDiff line numberDiff line change
@@ -2194,6 +2194,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
21942194
/** Key is "/path/to/a.ts|/path/to/b.ts". */
21952195
var amalgamatedDuplicates: Map<string, DuplicateInfoForFiles> | undefined;
21962196
var reverseMappedCache = new Map<string, Type | undefined>();
2197+
var reverseHomomorphicMappedCache = new Map<string, Type | undefined>();
21972198
var ambientModulesCache: Symbol[] | undefined;
21982199
/**
21992200
* List of every ambient module with a "*" wildcard.
@@ -7030,20 +7031,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
70307031
}
70317032

70327033
function shouldUsePlaceholderForProperty(propertySymbol: Symbol, context: NodeBuilderContext) {
7033-
// Use placeholders for reverse mapped types we've either already descended into, or which
7034-
// are nested reverse mappings within a mapping over a non-anonymous type. The later is a restriction mostly just to
7034+
// Use placeholders for reverse mapped types we've either
7035+
// (1) already descended into, or
7036+
// (2) are nested reverse mappings within a mapping over a non-anonymous type, or
7037+
// (3) are deeply nested properties that originate from the same mapped type.
7038+
// Condition (2) is a restriction mostly just to
70357039
// reduce the blowup in printback size from doing, eg, a deep reverse mapping over `Window`.
70367040
// Since anonymous types usually come from expressions, this allows us to preserve the output
70377041
// for deep mappings which likely come from expressions, while truncating those parts which
70387042
// come from mappings over library functions.
7043+
// Condition (3) limits printing of possibly infinitely deep reverse mapped types.
7044+
const depth = 3;
70397045
return !!(getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped)
70407046
&& (
70417047
contains(context.reverseMappedStack, propertySymbol as ReverseMappedSymbol)
70427048
|| (
70437049
context.reverseMappedStack?.[0]
70447050
&& !(getObjectFlags(last(context.reverseMappedStack).links.propertyType) & ObjectFlags.Anonymous)
70457051
)
7052+
|| isDeeplyNestedReverseMappedTypeProperty()
70467053
);
7054+
function isDeeplyNestedReverseMappedTypeProperty() {
7055+
if ((context.reverseMappedStack?.length ?? 0) < depth) {
7056+
return false;
7057+
}
7058+
for (let i = 0; i < depth; i++) {
7059+
const prop = context.reverseMappedStack![context.reverseMappedStack!.length - 1 - i];
7060+
if (prop.links.mappedType.symbol !== (propertySymbol as ReverseMappedSymbol).links.mappedType.symbol) {
7061+
return false;
7062+
}
7063+
}
7064+
return true;
7065+
}
70477066
}
70487067

70497068
function addPropertyToElementList(propertySymbol: Symbol, context: NodeBuilderContext, typeElements: TypeElement[]) {
@@ -25657,11 +25676,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2565725676
*/
2565825677
function inferTypeForHomomorphicMappedType(source: Type, target: MappedType, constraint: IndexType): Type | undefined {
2565925678
const cacheKey = source.id + "," + target.id + "," + constraint.id;
25660-
if (reverseMappedCache.has(cacheKey)) {
25661-
return reverseMappedCache.get(cacheKey);
25679+
if (reverseHomomorphicMappedCache.has(cacheKey)) {
25680+
return reverseHomomorphicMappedCache.get(cacheKey);
2566225681
}
2566325682
const type = createReverseMappedType(source, target, constraint);
25664-
reverseMappedCache.set(cacheKey, type);
25683+
reverseHomomorphicMappedCache.set(cacheKey, type);
2566525684
return type;
2566625685
}
2566725686

0 commit comments

Comments
 (0)