Skip to content

Commit e24cc01

Browse files
authored
Cache instantiation expression types early enough to prevent reentrancy during printback (#59931)
1 parent 8880946 commit e24cc01

8 files changed

+204
-2
lines changed

src/compiler/checker.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37401,9 +37401,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3740137401
if (exprType === silentNeverType || isErrorType(exprType) || !some(typeArguments)) {
3740237402
return exprType;
3740337403
}
37404+
const links = getNodeLinks(node);
37405+
if (!links.instantiationExpressionTypes) {
37406+
links.instantiationExpressionTypes = new Map();
37407+
}
37408+
if (links.instantiationExpressionTypes.has(exprType.id)) {
37409+
return links.instantiationExpressionTypes.get(exprType.id)!;
37410+
}
3740437411
let hasSomeApplicableSignature = false;
3740537412
let nonApplicableType: Type | undefined;
3740637413
const result = getInstantiatedType(exprType);
37414+
links.instantiationExpressionTypes.set(exprType.id, result);
3740737415
const errorType = hasSomeApplicableSignature ? nonApplicableType : exprType;
3740837416
if (errorType) {
3740937417
diagnostics.add(createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Type_0_has_no_signatures_for_which_the_type_argument_list_is_applicable, typeToString(errorType)));

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6239,6 +6239,7 @@ export interface NodeLinks {
62396239
potentialReflectCollisions?: Node[];
62406240
potentialUnusedRenamedBindingElementsInTypes?: BindingElement[];
62416241
externalHelpersModule?: Symbol; // Resolved symbol for the external helpers module
6242+
instantiationExpressionTypes?: Map<number, Type>; // Cache of instantiation expression types for the node
62426243
}
62436244

62446245
/** @internal */
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
instantiationExpressionErrorNoCrash.ts(15,38): error TS2344: Type 'typeof createCacheReducer<QR>' does not satisfy the constraint '(...args: any) => any'.
2+
Type 'typeof createCacheReducer<QR>' provides no match for the signature '(...args: any): any'.
3+
instantiationExpressionErrorNoCrash.ts(15,64): error TS2635: Type '<N extends string, QR>(queries: { [QK in keyof QR]: any; }) => (state?: { queries: QR; }) => { queries: QR; }' has no signatures for which the type argument list is applicable.
4+
5+
6+
==== instantiationExpressionErrorNoCrash.ts (2 errors) ====
7+
const createCacheReducer = <N extends string, QR>(
8+
queries: Cache<N, QR>["queries"],
9+
) => {
10+
const queriesMap = {} as QR;
11+
12+
const initialState = {
13+
queries: queriesMap,
14+
};
15+
16+
return (state = initialState) => state;
17+
};
18+
19+
export type Cache<N extends string, QR> = {
20+
queries: {
21+
[QK in keyof QR]: ReturnType<typeof createCacheReducer<QR>>;
22+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23+
!!! error TS2344: Type 'typeof createCacheReducer<QR>' does not satisfy the constraint '(...args: any) => any'.
24+
!!! error TS2344: Type 'typeof createCacheReducer<QR>' provides no match for the signature '(...args: any): any'.
25+
~~
26+
!!! error TS2635: Type '<N extends string, QR>(queries: { [QK in keyof QR]: any; }) => (state?: { queries: QR; }) => { queries: QR; }' has no signatures for which the type argument list is applicable.
27+
};
28+
};
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//// [tests/cases/compiler/instantiationExpressionErrorNoCrash.ts] ////
2+
3+
//// [instantiationExpressionErrorNoCrash.ts]
4+
const createCacheReducer = <N extends string, QR>(
5+
queries: Cache<N, QR>["queries"],
6+
) => {
7+
const queriesMap = {} as QR;
8+
9+
const initialState = {
10+
queries: queriesMap,
11+
};
12+
13+
return (state = initialState) => state;
14+
};
15+
16+
export type Cache<N extends string, QR> = {
17+
queries: {
18+
[QK in keyof QR]: ReturnType<typeof createCacheReducer<QR>>;
19+
};
20+
};
21+
22+
//// [instantiationExpressionErrorNoCrash.js]
23+
"use strict";
24+
Object.defineProperty(exports, "__esModule", { value: true });
25+
var createCacheReducer = function (queries) {
26+
var queriesMap = {};
27+
var initialState = {
28+
queries: queriesMap,
29+
};
30+
return function (state) {
31+
if (state === void 0) { state = initialState; }
32+
return state;
33+
};
34+
};
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//// [tests/cases/compiler/instantiationExpressionErrorNoCrash.ts] ////
2+
3+
=== instantiationExpressionErrorNoCrash.ts ===
4+
const createCacheReducer = <N extends string, QR>(
5+
>createCacheReducer : Symbol(createCacheReducer, Decl(instantiationExpressionErrorNoCrash.ts, 0, 5))
6+
>N : Symbol(N, Decl(instantiationExpressionErrorNoCrash.ts, 0, 28))
7+
>QR : Symbol(QR, Decl(instantiationExpressionErrorNoCrash.ts, 0, 45))
8+
9+
queries: Cache<N, QR>["queries"],
10+
>queries : Symbol(queries, Decl(instantiationExpressionErrorNoCrash.ts, 0, 50))
11+
>Cache : Symbol(Cache, Decl(instantiationExpressionErrorNoCrash.ts, 10, 2))
12+
>N : Symbol(N, Decl(instantiationExpressionErrorNoCrash.ts, 0, 28))
13+
>QR : Symbol(QR, Decl(instantiationExpressionErrorNoCrash.ts, 0, 45))
14+
15+
) => {
16+
const queriesMap = {} as QR;
17+
>queriesMap : Symbol(queriesMap, Decl(instantiationExpressionErrorNoCrash.ts, 3, 9))
18+
>QR : Symbol(QR, Decl(instantiationExpressionErrorNoCrash.ts, 0, 45))
19+
20+
const initialState = {
21+
>initialState : Symbol(initialState, Decl(instantiationExpressionErrorNoCrash.ts, 5, 9))
22+
23+
queries: queriesMap,
24+
>queries : Symbol(queries, Decl(instantiationExpressionErrorNoCrash.ts, 5, 26))
25+
>queriesMap : Symbol(queriesMap, Decl(instantiationExpressionErrorNoCrash.ts, 3, 9))
26+
27+
};
28+
29+
return (state = initialState) => state;
30+
>state : Symbol(state, Decl(instantiationExpressionErrorNoCrash.ts, 9, 12))
31+
>initialState : Symbol(initialState, Decl(instantiationExpressionErrorNoCrash.ts, 5, 9))
32+
>state : Symbol(state, Decl(instantiationExpressionErrorNoCrash.ts, 9, 12))
33+
34+
};
35+
36+
export type Cache<N extends string, QR> = {
37+
>Cache : Symbol(Cache, Decl(instantiationExpressionErrorNoCrash.ts, 10, 2))
38+
>N : Symbol(N, Decl(instantiationExpressionErrorNoCrash.ts, 12, 18))
39+
>QR : Symbol(QR, Decl(instantiationExpressionErrorNoCrash.ts, 12, 35))
40+
41+
queries: {
42+
>queries : Symbol(queries, Decl(instantiationExpressionErrorNoCrash.ts, 12, 43))
43+
44+
[QK in keyof QR]: ReturnType<typeof createCacheReducer<QR>>;
45+
>QK : Symbol(QK, Decl(instantiationExpressionErrorNoCrash.ts, 14, 9))
46+
>QR : Symbol(QR, Decl(instantiationExpressionErrorNoCrash.ts, 12, 35))
47+
>ReturnType : Symbol(ReturnType, Decl(lib.es5.d.ts, --, --))
48+
>createCacheReducer : Symbol(createCacheReducer, Decl(instantiationExpressionErrorNoCrash.ts, 0, 5))
49+
>QR : Symbol(QR, Decl(instantiationExpressionErrorNoCrash.ts, 12, 35))
50+
51+
};
52+
};
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//// [tests/cases/compiler/instantiationExpressionErrorNoCrash.ts] ////
2+
3+
=== instantiationExpressionErrorNoCrash.ts ===
4+
const createCacheReducer = <N extends string, QR>(
5+
>createCacheReducer : <N extends string, QR>(queries: Cache<N, QR>["queries"]) => (state?: { queries: QR; }) => { queries: QR; }
6+
> : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7+
><N extends string, QR>( queries: Cache<N, QR>["queries"],) => { const queriesMap = {} as QR; const initialState = { queries: queriesMap, }; return (state = initialState) => state;} : <N extends string, QR>(queries: Cache<N, QR>["queries"]) => (state?: { queries: QR; }) => { queries: QR; }
8+
> : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
9+
10+
queries: Cache<N, QR>["queries"],
11+
>queries : { [QK in keyof QR]: any; }
12+
> : ^^^ ^^^^^^^^^^^^^^^^^^^^^
13+
14+
) => {
15+
const queriesMap = {} as QR;
16+
>queriesMap : QR
17+
> : ^^
18+
>{} as QR : QR
19+
> : ^^
20+
>{} : {}
21+
> : ^^
22+
23+
const initialState = {
24+
>initialState : { queries: QR; }
25+
> : ^^^^^^^^^^^^^^^^
26+
>{ queries: queriesMap, } : { queries: QR; }
27+
> : ^^^^^^^^^^^^^^^^
28+
29+
queries: queriesMap,
30+
>queries : QR
31+
> : ^^
32+
>queriesMap : QR
33+
> : ^^
34+
35+
};
36+
37+
return (state = initialState) => state;
38+
>(state = initialState) => state : (state?: { queries: QR; }) => { queries: QR; }
39+
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
40+
>state : { queries: QR; }
41+
> : ^^^^^^^^^^^^^^^^
42+
>initialState : { queries: QR; }
43+
> : ^^^^^^^^^^^^^^^^
44+
>state : { queries: QR; }
45+
> : ^^^^^^^^^^^^^^^^
46+
47+
};
48+
49+
export type Cache<N extends string, QR> = {
50+
>Cache : Cache<N, QR>
51+
> : ^^^^^^^^^^^^
52+
53+
queries: {
54+
>queries : { [QK in keyof QR]: any; }
55+
> : ^^^ ^^^^^^^^^^^^^^^^^^^^^
56+
57+
[QK in keyof QR]: ReturnType<typeof createCacheReducer<QR>>;
58+
>createCacheReducer : <N_1 extends string, QR_1>(queries: Cache<N_1, QR_1>["queries"]) => (state?: { queries: QR_1; }) => { queries: QR_1; }
59+
> : ^^^^^^^^^^^^^ ^^^^^^^^ ^^ ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
60+
61+
};
62+
};

tests/baselines/reference/instantiationExpressionErrors.types

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ const c1 = g<string> || ((x: string) => x);
179179
>c1 : (x: string) => string
180180
> : ^ ^^^^^^^^^^^^^^^^^^^
181181
>g<string> || ((x: string) => x) : (x: string) => string
182-
> : ^ ^^ ^^^^^^^^^^^
182+
> : ^ ^^^^^^^^^^^^^^^^^^^
183183
>g<string> : ((x: string) => string) | undefined
184184
> : ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
185185
>g : (<T>(x: T) => T) | undefined
@@ -197,7 +197,7 @@ const c2 = g<string> ?? ((x: string) => x);
197197
>c2 : (x: string) => string
198198
> : ^ ^^^^^^^^^^^^^^^^^^^
199199
>g<string> ?? ((x: string) => x) : (x: string) => string
200-
> : ^ ^^ ^^^^^^^^^^^
200+
> : ^ ^^^^^^^^^^^^^^^^^^^
201201
>g<string> : ((x: string) => string) | undefined
202202
> : ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
203203
>g : (<T>(x: T) => T) | undefined
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
const createCacheReducer = <N extends string, QR>(
2+
queries: Cache<N, QR>["queries"],
3+
) => {
4+
const queriesMap = {} as QR;
5+
6+
const initialState = {
7+
queries: queriesMap,
8+
};
9+
10+
return (state = initialState) => state;
11+
};
12+
13+
export type Cache<N extends string, QR> = {
14+
queries: {
15+
[QK in keyof QR]: ReturnType<typeof createCacheReducer<QR>>;
16+
};
17+
};

0 commit comments

Comments
 (0)