Fixed regression in reverse mapped type inference caused by cache leak (#59232)
Co-authored-by: Gabriela Araujo Britto <gabrielaa@microsoft.com>
This commit is contained in:
Родитель
9c093c13e6
Коммит
6d3be985c8
|
@ -2194,6 +2194,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
|||
/** Key is "/path/to/a.ts|/path/to/b.ts". */
|
||||
var amalgamatedDuplicates: Map<string, DuplicateInfoForFiles> | undefined;
|
||||
var reverseMappedCache = new Map<string, Type | undefined>();
|
||||
var reverseHomomorphicMappedCache = new Map<string, Type | undefined>();
|
||||
var ambientModulesCache: Symbol[] | undefined;
|
||||
/**
|
||||
* List of every ambient module with a "*" wildcard.
|
||||
|
@ -7030,12 +7031,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
|||
}
|
||||
|
||||
function shouldUsePlaceholderForProperty(propertySymbol: Symbol, context: NodeBuilderContext) {
|
||||
// Use placeholders for reverse mapped types we've either already descended into, or which
|
||||
// are nested reverse mappings within a mapping over a non-anonymous type. The later is a restriction mostly just to
|
||||
// Use placeholders for reverse mapped types we've either
|
||||
// (1) already descended into, or
|
||||
// (2) are nested reverse mappings within a mapping over a non-anonymous type, or
|
||||
// (3) are deeply nested properties that originate from the same mapped type.
|
||||
// Condition (2) is a restriction mostly just to
|
||||
// reduce the blowup in printback size from doing, eg, a deep reverse mapping over `Window`.
|
||||
// Since anonymous types usually come from expressions, this allows us to preserve the output
|
||||
// for deep mappings which likely come from expressions, while truncating those parts which
|
||||
// come from mappings over library functions.
|
||||
// Condition (3) limits printing of possibly infinitely deep reverse mapped types.
|
||||
const depth = 3;
|
||||
return !!(getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped)
|
||||
&& (
|
||||
contains(context.reverseMappedStack, propertySymbol as ReverseMappedSymbol)
|
||||
|
@ -7043,7 +7049,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
|||
context.reverseMappedStack?.[0]
|
||||
&& !(getObjectFlags(last(context.reverseMappedStack).links.propertyType) & ObjectFlags.Anonymous)
|
||||
)
|
||||
|| isDeeplyNestedReverseMappedTypeProperty()
|
||||
);
|
||||
function isDeeplyNestedReverseMappedTypeProperty() {
|
||||
if ((context.reverseMappedStack?.length ?? 0) < depth) {
|
||||
return false;
|
||||
}
|
||||
for (let i = 0; i < depth; i++) {
|
||||
const prop = context.reverseMappedStack![context.reverseMappedStack!.length - 1 - i];
|
||||
if (prop.links.mappedType.symbol !== (propertySymbol as ReverseMappedSymbol).links.mappedType.symbol) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function addPropertyToElementList(propertySymbol: Symbol, context: NodeBuilderContext, typeElements: TypeElement[]) {
|
||||
|
@ -25657,11 +25676,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
|||
*/
|
||||
function inferTypeForHomomorphicMappedType(source: Type, target: MappedType, constraint: IndexType): Type | undefined {
|
||||
const cacheKey = source.id + "," + target.id + "," + constraint.id;
|
||||
if (reverseMappedCache.has(cacheKey)) {
|
||||
return reverseMappedCache.get(cacheKey);
|
||||
if (reverseHomomorphicMappedCache.has(cacheKey)) {
|
||||
return reverseHomomorphicMappedCache.get(cacheKey);
|
||||
}
|
||||
const type = createReverseMappedType(source, target, constraint);
|
||||
reverseMappedCache.set(cacheKey, type);
|
||||
reverseHomomorphicMappedCache.set(cacheKey, type);
|
||||
return type;
|
||||
}
|
||||
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -2,8 +2,8 @@
|
|||
|
||||
=== Performance Stats ===
|
||||
Assignability cache: 5,000
|
||||
Type Count: 10,000
|
||||
Instantiation count: 250,000
|
||||
Type Count: 25,000
|
||||
Instantiation count: 500,000
|
||||
Symbol count: 250,000
|
||||
|
||||
=== mappedTypeRecursiveInference.ts ===
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
//// [tests/cases/compiler/reverseMappedTypeInferenceSameSource1.ts] ////
|
||||
|
||||
=== reverseMappedTypeInferenceSameSource1.ts ===
|
||||
type Action<T extends string = string> = {
|
||||
>Action : Symbol(Action, Decl(reverseMappedTypeInferenceSameSource1.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(reverseMappedTypeInferenceSameSource1.ts, 0, 12))
|
||||
|
||||
type: T;
|
||||
>type : Symbol(type, Decl(reverseMappedTypeInferenceSameSource1.ts, 0, 42))
|
||||
>T : Symbol(T, Decl(reverseMappedTypeInferenceSameSource1.ts, 0, 12))
|
||||
|
||||
};
|
||||
interface UnknownAction extends Action {
|
||||
>UnknownAction : Symbol(UnknownAction, Decl(reverseMappedTypeInferenceSameSource1.ts, 2, 2))
|
||||
>Action : Symbol(Action, Decl(reverseMappedTypeInferenceSameSource1.ts, 0, 0))
|
||||
|
||||
[extraProps: string]: unknown;
|
||||
>extraProps : Symbol(extraProps, Decl(reverseMappedTypeInferenceSameSource1.ts, 4, 3))
|
||||
}
|
||||
type Reducer<S = any, A extends Action = UnknownAction> = (
|
||||
>Reducer : Symbol(Reducer, Decl(reverseMappedTypeInferenceSameSource1.ts, 5, 1))
|
||||
>S : Symbol(S, Decl(reverseMappedTypeInferenceSameSource1.ts, 6, 13))
|
||||
>A : Symbol(A, Decl(reverseMappedTypeInferenceSameSource1.ts, 6, 21))
|
||||
>Action : Symbol(Action, Decl(reverseMappedTypeInferenceSameSource1.ts, 0, 0))
|
||||
>UnknownAction : Symbol(UnknownAction, Decl(reverseMappedTypeInferenceSameSource1.ts, 2, 2))
|
||||
|
||||
state: S | undefined,
|
||||
>state : Symbol(state, Decl(reverseMappedTypeInferenceSameSource1.ts, 6, 59))
|
||||
>S : Symbol(S, Decl(reverseMappedTypeInferenceSameSource1.ts, 6, 13))
|
||||
|
||||
action: A,
|
||||
>action : Symbol(action, Decl(reverseMappedTypeInferenceSameSource1.ts, 7, 23))
|
||||
>A : Symbol(A, Decl(reverseMappedTypeInferenceSameSource1.ts, 6, 21))
|
||||
|
||||
) => S;
|
||||
>S : Symbol(S, Decl(reverseMappedTypeInferenceSameSource1.ts, 6, 13))
|
||||
|
||||
type ReducersMapObject<S = any, A extends Action = UnknownAction> = {
|
||||
>ReducersMapObject : Symbol(ReducersMapObject, Decl(reverseMappedTypeInferenceSameSource1.ts, 9, 7))
|
||||
>S : Symbol(S, Decl(reverseMappedTypeInferenceSameSource1.ts, 11, 23))
|
||||
>A : Symbol(A, Decl(reverseMappedTypeInferenceSameSource1.ts, 11, 31))
|
||||
>Action : Symbol(Action, Decl(reverseMappedTypeInferenceSameSource1.ts, 0, 0))
|
||||
>UnknownAction : Symbol(UnknownAction, Decl(reverseMappedTypeInferenceSameSource1.ts, 2, 2))
|
||||
|
||||
[K in keyof S]: Reducer<S[K], A>;
|
||||
>K : Symbol(K, Decl(reverseMappedTypeInferenceSameSource1.ts, 12, 3))
|
||||
>S : Symbol(S, Decl(reverseMappedTypeInferenceSameSource1.ts, 11, 23))
|
||||
>Reducer : Symbol(Reducer, Decl(reverseMappedTypeInferenceSameSource1.ts, 5, 1))
|
||||
>S : Symbol(S, Decl(reverseMappedTypeInferenceSameSource1.ts, 11, 23))
|
||||
>K : Symbol(K, Decl(reverseMappedTypeInferenceSameSource1.ts, 12, 3))
|
||||
>A : Symbol(A, Decl(reverseMappedTypeInferenceSameSource1.ts, 11, 31))
|
||||
|
||||
};
|
||||
|
||||
interface ConfigureStoreOptions<S = any, A extends Action = UnknownAction> {
|
||||
>ConfigureStoreOptions : Symbol(ConfigureStoreOptions, Decl(reverseMappedTypeInferenceSameSource1.ts, 13, 2))
|
||||
>S : Symbol(S, Decl(reverseMappedTypeInferenceSameSource1.ts, 15, 32))
|
||||
>A : Symbol(A, Decl(reverseMappedTypeInferenceSameSource1.ts, 15, 40))
|
||||
>Action : Symbol(Action, Decl(reverseMappedTypeInferenceSameSource1.ts, 0, 0))
|
||||
>UnknownAction : Symbol(UnknownAction, Decl(reverseMappedTypeInferenceSameSource1.ts, 2, 2))
|
||||
|
||||
reducer: Reducer<S, A> | ReducersMapObject<S, A>;
|
||||
>reducer : Symbol(ConfigureStoreOptions.reducer, Decl(reverseMappedTypeInferenceSameSource1.ts, 15, 76))
|
||||
>Reducer : Symbol(Reducer, Decl(reverseMappedTypeInferenceSameSource1.ts, 5, 1))
|
||||
>S : Symbol(S, Decl(reverseMappedTypeInferenceSameSource1.ts, 15, 32))
|
||||
>A : Symbol(A, Decl(reverseMappedTypeInferenceSameSource1.ts, 15, 40))
|
||||
>ReducersMapObject : Symbol(ReducersMapObject, Decl(reverseMappedTypeInferenceSameSource1.ts, 9, 7))
|
||||
>S : Symbol(S, Decl(reverseMappedTypeInferenceSameSource1.ts, 15, 32))
|
||||
>A : Symbol(A, Decl(reverseMappedTypeInferenceSameSource1.ts, 15, 40))
|
||||
}
|
||||
|
||||
declare function configureStore<S = any, A extends Action = UnknownAction>(
|
||||
>configureStore : Symbol(configureStore, Decl(reverseMappedTypeInferenceSameSource1.ts, 17, 1))
|
||||
>S : Symbol(S, Decl(reverseMappedTypeInferenceSameSource1.ts, 19, 32))
|
||||
>A : Symbol(A, Decl(reverseMappedTypeInferenceSameSource1.ts, 19, 40))
|
||||
>Action : Symbol(Action, Decl(reverseMappedTypeInferenceSameSource1.ts, 0, 0))
|
||||
>UnknownAction : Symbol(UnknownAction, Decl(reverseMappedTypeInferenceSameSource1.ts, 2, 2))
|
||||
|
||||
options: ConfigureStoreOptions<S, A>,
|
||||
>options : Symbol(options, Decl(reverseMappedTypeInferenceSameSource1.ts, 19, 75))
|
||||
>ConfigureStoreOptions : Symbol(ConfigureStoreOptions, Decl(reverseMappedTypeInferenceSameSource1.ts, 13, 2))
|
||||
>S : Symbol(S, Decl(reverseMappedTypeInferenceSameSource1.ts, 19, 32))
|
||||
>A : Symbol(A, Decl(reverseMappedTypeInferenceSameSource1.ts, 19, 40))
|
||||
|
||||
): void;
|
||||
|
||||
{
|
||||
const reducer: Reducer<number> = () => 0;
|
||||
>reducer : Symbol(reducer, Decl(reverseMappedTypeInferenceSameSource1.ts, 24, 7))
|
||||
>Reducer : Symbol(Reducer, Decl(reverseMappedTypeInferenceSameSource1.ts, 5, 1))
|
||||
|
||||
const store1 = configureStore({ reducer });
|
||||
>store1 : Symbol(store1, Decl(reverseMappedTypeInferenceSameSource1.ts, 25, 7))
|
||||
>configureStore : Symbol(configureStore, Decl(reverseMappedTypeInferenceSameSource1.ts, 17, 1))
|
||||
>reducer : Symbol(reducer, Decl(reverseMappedTypeInferenceSameSource1.ts, 25, 33))
|
||||
}
|
||||
|
||||
const counterReducer1: Reducer<number> = () => 0;
|
||||
>counterReducer1 : Symbol(counterReducer1, Decl(reverseMappedTypeInferenceSameSource1.ts, 28, 5))
|
||||
>Reducer : Symbol(Reducer, Decl(reverseMappedTypeInferenceSameSource1.ts, 5, 1))
|
||||
|
||||
const store2 = configureStore({
|
||||
>store2 : Symbol(store2, Decl(reverseMappedTypeInferenceSameSource1.ts, 30, 5))
|
||||
>configureStore : Symbol(configureStore, Decl(reverseMappedTypeInferenceSameSource1.ts, 17, 1))
|
||||
|
||||
reducer: {
|
||||
>reducer : Symbol(reducer, Decl(reverseMappedTypeInferenceSameSource1.ts, 30, 31))
|
||||
|
||||
counter1: counterReducer1,
|
||||
>counter1 : Symbol(counter1, Decl(reverseMappedTypeInferenceSameSource1.ts, 31, 12))
|
||||
>counterReducer1 : Symbol(counterReducer1, Decl(reverseMappedTypeInferenceSameSource1.ts, 28, 5))
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
export {}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
//// [tests/cases/compiler/reverseMappedTypeInferenceSameSource1.ts] ////
|
||||
|
||||
=== reverseMappedTypeInferenceSameSource1.ts ===
|
||||
type Action<T extends string = string> = {
|
||||
>Action : Action<T>
|
||||
> : ^^^^^^^^^
|
||||
|
||||
type: T;
|
||||
>type : T
|
||||
> : ^
|
||||
|
||||
};
|
||||
interface UnknownAction extends Action {
|
||||
[extraProps: string]: unknown;
|
||||
>extraProps : string
|
||||
> : ^^^^^^
|
||||
}
|
||||
type Reducer<S = any, A extends Action = UnknownAction> = (
|
||||
>Reducer : Reducer<S, A>
|
||||
> : ^^^^^^^^^^^^^
|
||||
|
||||
state: S | undefined,
|
||||
>state : S | undefined
|
||||
> : ^^^^^^^^^^^^^
|
||||
|
||||
action: A,
|
||||
>action : A
|
||||
> : ^
|
||||
|
||||
) => S;
|
||||
|
||||
type ReducersMapObject<S = any, A extends Action = UnknownAction> = {
|
||||
>ReducersMapObject : ReducersMapObject<S, A>
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
[K in keyof S]: Reducer<S[K], A>;
|
||||
};
|
||||
|
||||
interface ConfigureStoreOptions<S = any, A extends Action = UnknownAction> {
|
||||
reducer: Reducer<S, A> | ReducersMapObject<S, A>;
|
||||
>reducer : Reducer<S, A> | ReducersMapObject<S, A>
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
}
|
||||
|
||||
declare function configureStore<S = any, A extends Action = UnknownAction>(
|
||||
>configureStore : <S = any, A extends Action = UnknownAction>(options: ConfigureStoreOptions<S, A>) => void
|
||||
> : ^ ^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ ^^ ^^^^^
|
||||
|
||||
options: ConfigureStoreOptions<S, A>,
|
||||
>options : ConfigureStoreOptions<S, A>
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
): void;
|
||||
|
||||
{
|
||||
const reducer: Reducer<number> = () => 0;
|
||||
>reducer : Reducer<number, UnknownAction>
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>() => 0 : () => number
|
||||
> : ^^^^^^^^^^^^
|
||||
>0 : 0
|
||||
> : ^
|
||||
|
||||
const store1 = configureStore({ reducer });
|
||||
>store1 : void
|
||||
> : ^^^^
|
||||
>configureStore({ reducer }) : void
|
||||
> : ^^^^
|
||||
>configureStore : <S = any, A extends Action = UnknownAction>(options: ConfigureStoreOptions<S, A>) => void
|
||||
> : ^ ^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ ^^ ^^^^^
|
||||
>{ reducer } : { reducer: Reducer<number, UnknownAction>; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>reducer : Reducer<number, UnknownAction>
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
}
|
||||
|
||||
const counterReducer1: Reducer<number> = () => 0;
|
||||
>counterReducer1 : Reducer<number, UnknownAction>
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>() => 0 : () => number
|
||||
> : ^^^^^^^^^^^^
|
||||
>0 : 0
|
||||
> : ^
|
||||
|
||||
const store2 = configureStore({
|
||||
>store2 : void
|
||||
> : ^^^^
|
||||
>configureStore({ reducer: { counter1: counterReducer1, },}) : void
|
||||
> : ^^^^
|
||||
>configureStore : <S = any, A extends Action = UnknownAction>(options: ConfigureStoreOptions<S, A>) => void
|
||||
> : ^ ^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ ^^ ^^^^^
|
||||
>{ reducer: { counter1: counterReducer1, },} : { reducer: { counter1: Reducer<number, UnknownAction>; }; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
reducer: {
|
||||
>reducer : { counter1: Reducer<number, UnknownAction>; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>{ counter1: counterReducer1, } : { counter1: Reducer<number, UnknownAction>; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
counter1: counterReducer1,
|
||||
>counter1 : Reducer<number, UnknownAction>
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>counterReducer1 : Reducer<number, UnknownAction>
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
export {}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
// @strict: true
|
||||
// @noEmit: true
|
||||
|
||||
type Action<T extends string = string> = {
|
||||
type: T;
|
||||
};
|
||||
interface UnknownAction extends Action {
|
||||
[extraProps: string]: unknown;
|
||||
}
|
||||
type Reducer<S = any, A extends Action = UnknownAction> = (
|
||||
state: S | undefined,
|
||||
action: A,
|
||||
) => S;
|
||||
|
||||
type ReducersMapObject<S = any, A extends Action = UnknownAction> = {
|
||||
[K in keyof S]: Reducer<S[K], A>;
|
||||
};
|
||||
|
||||
interface ConfigureStoreOptions<S = any, A extends Action = UnknownAction> {
|
||||
reducer: Reducer<S, A> | ReducersMapObject<S, A>;
|
||||
}
|
||||
|
||||
declare function configureStore<S = any, A extends Action = UnknownAction>(
|
||||
options: ConfigureStoreOptions<S, A>,
|
||||
): void;
|
||||
|
||||
{
|
||||
const reducer: Reducer<number> = () => 0;
|
||||
const store1 = configureStore({ reducer });
|
||||
}
|
||||
|
||||
const counterReducer1: Reducer<number> = () => 0;
|
||||
|
||||
const store2 = configureStore({
|
||||
reducer: {
|
||||
counter1: counterReducer1,
|
||||
},
|
||||
});
|
||||
|
||||
export {}
|
Загрузка…
Ссылка в новой задаче