From 6909574973f10fd6735161c5cc90c37ca1ac8902 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 4 Apr 2017 14:48:57 -0700 Subject: [PATCH 1/2] Limit symbol instantiations to a maximum depth of 100 --- src/compiler/checker.ts | 24 +++++++++++++++++------- src/compiler/diagnosticMessages.json | 4 ++++ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7bdde91f286..1f558c7e579 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -47,6 +47,7 @@ namespace ts { let typeCount = 0; let symbolCount = 0; + let symbolInstantiationDepth = 0; const emptyArray: any[] = []; const emptySymbols = createMap(); @@ -4440,14 +4441,22 @@ namespace ts { function getTypeOfInstantiatedSymbol(symbol: Symbol): Type { const links = getSymbolLinks(symbol); if (!links.type) { - if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) { - return unknownType; + if (symbolInstantiationDepth === 100) { + error(symbol.valueDeclaration, Diagnostics.Generic_type_instantiation_is_excessively_deep_and_possibly_infinite); + links.type = unknownType; } - let type = instantiateType(getTypeOfSymbol(links.target), links.mapper); - if (!popTypeResolution()) { - type = reportCircularityError(symbol); + else { + if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) { + return unknownType; + } + symbolInstantiationDepth++; + let type = instantiateType(getTypeOfSymbol(links.target), links.mapper); + symbolInstantiationDepth--; + if (!popTypeResolution()) { + type = reportCircularityError(symbol); + } + links.type = type; } - links.type = type; } return links.type; } @@ -7257,8 +7266,9 @@ namespace ts { else { error(indexNode, Diagnostics.Type_0_cannot_be_used_as_an_index_type, typeToString(indexType)); } + return unknownType; } - return unknownType; + return anyType; } function getIndexedAccessForMappedType(type: MappedType, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode) { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 983e128ec7f..075d4247460 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1827,6 +1827,10 @@ "category": "Error", "code": 2549 }, + "Generic type instantiation is excessively deep and possibly infinite.": { + "category": "Error", + "code": 2550 + }, "JSX element attributes type '{0}' may not be a union type.": { "category": "Error", "code": 2600 From 68ab129fac529f1ed35bbb70edcc3093e88a4fcc Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 4 Apr 2017 14:53:48 -0700 Subject: [PATCH 2/2] Add regression test --- .../reference/limitDeepInstantiations.errors.txt | 15 +++++++++++++++ .../reference/limitDeepInstantiations.js | 12 ++++++++++++ tests/cases/compiler/limitDeepInstantiations.ts | 5 +++++ 3 files changed, 32 insertions(+) create mode 100644 tests/baselines/reference/limitDeepInstantiations.errors.txt create mode 100644 tests/baselines/reference/limitDeepInstantiations.js create mode 100644 tests/cases/compiler/limitDeepInstantiations.ts diff --git a/tests/baselines/reference/limitDeepInstantiations.errors.txt b/tests/baselines/reference/limitDeepInstantiations.errors.txt new file mode 100644 index 00000000000..330e5fbc8e4 --- /dev/null +++ b/tests/baselines/reference/limitDeepInstantiations.errors.txt @@ -0,0 +1,15 @@ +tests/cases/compiler/limitDeepInstantiations.ts(3,35): error TS2550: Generic type instantiation is excessively deep and possibly infinite. +tests/cases/compiler/limitDeepInstantiations.ts(5,13): error TS2344: Type '"false"' does not satisfy the constraint '"true"'. + + +==== tests/cases/compiler/limitDeepInstantiations.ts (2 errors) ==== + // Repro from #14837 + + type Foo = { "true": Foo> }[T]; + ~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2550: Generic type instantiation is excessively deep and possibly infinite. + let f1: Foo<"true", {}>; + let f2: Foo<"false", {}>; + ~~~~~~~ +!!! error TS2344: Type '"false"' does not satisfy the constraint '"true"'. + \ No newline at end of file diff --git a/tests/baselines/reference/limitDeepInstantiations.js b/tests/baselines/reference/limitDeepInstantiations.js new file mode 100644 index 00000000000..7b70cbd5956 --- /dev/null +++ b/tests/baselines/reference/limitDeepInstantiations.js @@ -0,0 +1,12 @@ +//// [limitDeepInstantiations.ts] +// Repro from #14837 + +type Foo = { "true": Foo> }[T]; +let f1: Foo<"true", {}>; +let f2: Foo<"false", {}>; + + +//// [limitDeepInstantiations.js] +// Repro from #14837 +var f1; +var f2; diff --git a/tests/cases/compiler/limitDeepInstantiations.ts b/tests/cases/compiler/limitDeepInstantiations.ts new file mode 100644 index 00000000000..f478157ecc2 --- /dev/null +++ b/tests/cases/compiler/limitDeepInstantiations.ts @@ -0,0 +1,5 @@ +// Repro from #14837 + +type Foo = { "true": Foo> }[T]; +let f1: Foo<"true", {}>; +let f2: Foo<"false", {}>;