Skip to content

Commit 9d2b57a

Browse files
authored
Merge pull request #15011 from Microsoft/limitDeepInstantiations
Limit deep generic type instantiations
2 parents 90648fd + 6e58f61 commit 9d2b57a

File tree

5 files changed

+53
-7
lines changed

5 files changed

+53
-7
lines changed

src/compiler/checker.ts

+17-7
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ namespace ts {
4747

4848
let typeCount = 0;
4949
let symbolCount = 0;
50+
let symbolInstantiationDepth = 0;
5051

5152
const emptyArray: any[] = [];
5253
const emptySymbols = createMap<Symbol>();
@@ -4449,14 +4450,22 @@ namespace ts {
44494450
function getTypeOfInstantiatedSymbol(symbol: Symbol): Type {
44504451
const links = getSymbolLinks(symbol);
44514452
if (!links.type) {
4452-
if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
4453-
return unknownType;
4453+
if (symbolInstantiationDepth === 100) {
4454+
error(symbol.valueDeclaration, Diagnostics.Generic_type_instantiation_is_excessively_deep_and_possibly_infinite);
4455+
links.type = unknownType;
44544456
}
4455-
let type = instantiateType(getTypeOfSymbol(links.target), links.mapper);
4456-
if (!popTypeResolution()) {
4457-
type = reportCircularityError(symbol);
4457+
else {
4458+
if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
4459+
return unknownType;
4460+
}
4461+
symbolInstantiationDepth++;
4462+
let type = instantiateType(getTypeOfSymbol(links.target), links.mapper);
4463+
symbolInstantiationDepth--;
4464+
if (!popTypeResolution()) {
4465+
type = reportCircularityError(symbol);
4466+
}
4467+
links.type = type;
44584468
}
4459-
links.type = type;
44604469
}
44614470
return links.type;
44624471
}
@@ -7266,8 +7275,9 @@ namespace ts {
72667275
else {
72677276
error(indexNode, Diagnostics.Type_0_cannot_be_used_as_an_index_type, typeToString(indexType));
72687277
}
7278+
return unknownType;
72697279
}
7270-
return unknownType;
7280+
return anyType;
72717281
}
72727282

72737283
function getIndexedAccessForMappedType(type: MappedType, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode) {

src/compiler/diagnosticMessages.json

+4
Original file line numberDiff line numberDiff line change
@@ -1827,6 +1827,10 @@
18271827
"category": "Error",
18281828
"code": 2549
18291829
},
1830+
"Generic type instantiation is excessively deep and possibly infinite.": {
1831+
"category": "Error",
1832+
"code": 2550
1833+
},
18301834
"JSX element attributes type '{0}' may not be a union type.": {
18311835
"category": "Error",
18321836
"code": 2600
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
tests/cases/compiler/limitDeepInstantiations.ts(3,35): error TS2550: Generic type instantiation is excessively deep and possibly infinite.
2+
tests/cases/compiler/limitDeepInstantiations.ts(5,13): error TS2344: Type '"false"' does not satisfy the constraint '"true"'.
3+
4+
5+
==== tests/cases/compiler/limitDeepInstantiations.ts (2 errors) ====
6+
// Repro from #14837
7+
8+
type Foo<T extends "true", B> = { "true": Foo<T, Foo<T, B>> }[T];
9+
~~~~~~~~~~~~~~~~~~~~~~~~~
10+
!!! error TS2550: Generic type instantiation is excessively deep and possibly infinite.
11+
let f1: Foo<"true", {}>;
12+
let f2: Foo<"false", {}>;
13+
~~~~~~~
14+
!!! error TS2344: Type '"false"' does not satisfy the constraint '"true"'.
15+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//// [limitDeepInstantiations.ts]
2+
// Repro from #14837
3+
4+
type Foo<T extends "true", B> = { "true": Foo<T, Foo<T, B>> }[T];
5+
let f1: Foo<"true", {}>;
6+
let f2: Foo<"false", {}>;
7+
8+
9+
//// [limitDeepInstantiations.js]
10+
// Repro from #14837
11+
var f1;
12+
var f2;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Repro from #14837
2+
3+
type Foo<T extends "true", B> = { "true": Foo<T, Foo<T, B>> }[T];
4+
let f1: Foo<"true", {}>;
5+
let f2: Foo<"false", {}>;

0 commit comments

Comments
 (0)