Merge pull request #32079 from microsoft/instantiationCountLimiter
Add type instantiation count limiter
This commit is contained in:
commit
440ed83f29
6 changed files with 120 additions and 2 deletions
|
@ -65,6 +65,7 @@ namespace ts {
|
||||||
let typeCount = 0;
|
let typeCount = 0;
|
||||||
let symbolCount = 0;
|
let symbolCount = 0;
|
||||||
let enumCount = 0;
|
let enumCount = 0;
|
||||||
|
let instantiationCount = 0;
|
||||||
let instantiationDepth = 0;
|
let instantiationDepth = 0;
|
||||||
let constraintDepth = 0;
|
let constraintDepth = 0;
|
||||||
let currentNode: Node | undefined;
|
let currentNode: Node | undefined;
|
||||||
|
@ -11425,13 +11426,14 @@ namespace ts {
|
||||||
if (!type || !mapper || mapper === identityMapper) {
|
if (!type || !mapper || mapper === identityMapper) {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
if (instantiationDepth === 50) {
|
if (instantiationDepth === 50 || instantiationCount >= 5000000) {
|
||||||
// We have reached 50 recursive type instantiations and there is a very high likelyhood we're dealing
|
// We have reached 50 recursive type instantiations and there is a very high likelyhood we're dealing
|
||||||
// with a combination of infinite generic types that perpetually generate new type identities. We stop
|
// with a combination of infinite generic types that perpetually generate new type identities. We stop
|
||||||
// the recursion here by yielding the error type.
|
// the recursion here by yielding the error type.
|
||||||
error(currentNode, Diagnostics.Type_instantiation_is_excessively_deep_and_possibly_infinite);
|
error(currentNode, Diagnostics.Type_instantiation_is_excessively_deep_and_possibly_infinite);
|
||||||
return errorType;
|
return errorType;
|
||||||
}
|
}
|
||||||
|
instantiationCount++;
|
||||||
instantiationDepth++;
|
instantiationDepth++;
|
||||||
const result = instantiateTypeWorker(type, mapper);
|
const result = instantiateTypeWorker(type, mapper);
|
||||||
instantiationDepth--;
|
instantiationDepth--;
|
||||||
|
@ -24619,6 +24621,7 @@ namespace ts {
|
||||||
function checkExpression(node: Expression | QualifiedName, checkMode?: CheckMode, forceTuple?: boolean): Type {
|
function checkExpression(node: Expression | QualifiedName, checkMode?: CheckMode, forceTuple?: boolean): Type {
|
||||||
const saveCurrentNode = currentNode;
|
const saveCurrentNode = currentNode;
|
||||||
currentNode = node;
|
currentNode = node;
|
||||||
|
instantiationCount = 0;
|
||||||
const uninstantiatedType = checkExpressionWorker(node, checkMode, forceTuple);
|
const uninstantiatedType = checkExpressionWorker(node, checkMode, forceTuple);
|
||||||
const type = instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, checkMode);
|
const type = instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, checkMode);
|
||||||
if (isConstEnumObjectType(type)) {
|
if (isConstEnumObjectType(type)) {
|
||||||
|
@ -29340,6 +29343,7 @@ namespace ts {
|
||||||
if (node) {
|
if (node) {
|
||||||
const saveCurrentNode = currentNode;
|
const saveCurrentNode = currentNode;
|
||||||
currentNode = node;
|
currentNode = node;
|
||||||
|
instantiationCount = 0;
|
||||||
checkSourceElementWorker(node);
|
checkSourceElementWorker(node);
|
||||||
currentNode = saveCurrentNode;
|
currentNode = saveCurrentNode;
|
||||||
}
|
}
|
||||||
|
@ -29611,6 +29615,7 @@ namespace ts {
|
||||||
function checkDeferredNode(node: Node) {
|
function checkDeferredNode(node: Node) {
|
||||||
const saveCurrentNode = currentNode;
|
const saveCurrentNode = currentNode;
|
||||||
currentNode = node;
|
currentNode = node;
|
||||||
|
instantiationCount = 0;
|
||||||
switch (node.kind) {
|
switch (node.kind) {
|
||||||
case SyntaxKind.FunctionExpression:
|
case SyntaxKind.FunctionExpression:
|
||||||
case SyntaxKind.ArrowFunction:
|
case SyntaxKind.ArrowFunction:
|
||||||
|
|
|
@ -2,9 +2,10 @@ tests/cases/compiler/infiniteConstraints.ts(4,37): error TS2536: Type '"val"' ca
|
||||||
tests/cases/compiler/infiniteConstraints.ts(31,43): error TS2322: Type 'Record<"val", "dup">' is not assignable to type 'never'.
|
tests/cases/compiler/infiniteConstraints.ts(31,43): error TS2322: Type 'Record<"val", "dup">' is not assignable to type 'never'.
|
||||||
tests/cases/compiler/infiniteConstraints.ts(31,63): error TS2322: Type 'Record<"val", "dup">' is not assignable to type 'never'.
|
tests/cases/compiler/infiniteConstraints.ts(31,63): error TS2322: Type 'Record<"val", "dup">' is not assignable to type 'never'.
|
||||||
tests/cases/compiler/infiniteConstraints.ts(36,71): error TS2536: Type '"foo"' cannot be used to index type 'T[keyof T]'.
|
tests/cases/compiler/infiniteConstraints.ts(36,71): error TS2536: Type '"foo"' cannot be used to index type 'T[keyof T]'.
|
||||||
|
tests/cases/compiler/infiniteConstraints.ts(48,16): error TS2589: Type instantiation is excessively deep and possibly infinite.
|
||||||
|
|
||||||
|
|
||||||
==== tests/cases/compiler/infiniteConstraints.ts (4 errors) ====
|
==== tests/cases/compiler/infiniteConstraints.ts (5 errors) ====
|
||||||
// Both of the following types trigger the recursion limiter in getImmediateBaseConstraint
|
// Both of the following types trigger the recursion limiter in getImmediateBaseConstraint
|
||||||
|
|
||||||
type T1<B extends { [K in keyof B]: Extract<B[Exclude<keyof B, K>], { val: string }>["val"] }> = B;
|
type T1<B extends { [K in keyof B]: Extract<B[Exclude<keyof B, K>], { val: string }>["val"] }> = B;
|
||||||
|
@ -51,4 +52,18 @@ tests/cases/compiler/infiniteConstraints.ts(36,71): error TS2536: Type '"foo"' c
|
||||||
declare function function1<T extends {[K in keyof T]: Cond<T[K]>}>(): T[keyof T]["foo"];
|
declare function function1<T extends {[K in keyof T]: Cond<T[K]>}>(): T[keyof T]["foo"];
|
||||||
~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~
|
||||||
!!! error TS2536: Type '"foo"' cannot be used to index type 'T[keyof T]'.
|
!!! error TS2536: Type '"foo"' cannot be used to index type 'T[keyof T]'.
|
||||||
|
|
||||||
|
// Repro from #31823
|
||||||
|
|
||||||
|
export type Prepend<Elm, T extends unknown[]> =
|
||||||
|
T extends unknown ?
|
||||||
|
((arg: Elm, ...rest: T) => void) extends ((...args: infer T2) => void) ? T2 :
|
||||||
|
never :
|
||||||
|
never;
|
||||||
|
export type ExactExtract<T, U> = T extends U ? U extends T ? T : never : never;
|
||||||
|
|
||||||
|
type Conv<T, U = T> =
|
||||||
|
{ 0: [T]; 1: Prepend<T, Conv<ExactExtract<U, T>>>;}[U extends T ? 0 : 1];
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
!!! error TS2589: Type instantiation is excessively deep and possibly infinite.
|
||||||
|
|
|
@ -35,11 +35,24 @@ const shouldBeError = ensureNoDuplicates({main: value("dup"), alternate: value("
|
||||||
|
|
||||||
type Cond<T> = T extends number ? number : never;
|
type Cond<T> = T extends number ? number : never;
|
||||||
declare function function1<T extends {[K in keyof T]: Cond<T[K]>}>(): T[keyof T]["foo"];
|
declare function function1<T extends {[K in keyof T]: Cond<T[K]>}>(): T[keyof T]["foo"];
|
||||||
|
|
||||||
|
// Repro from #31823
|
||||||
|
|
||||||
|
export type Prepend<Elm, T extends unknown[]> =
|
||||||
|
T extends unknown ?
|
||||||
|
((arg: Elm, ...rest: T) => void) extends ((...args: infer T2) => void) ? T2 :
|
||||||
|
never :
|
||||||
|
never;
|
||||||
|
export type ExactExtract<T, U> = T extends U ? U extends T ? T : never : never;
|
||||||
|
|
||||||
|
type Conv<T, U = T> =
|
||||||
|
{ 0: [T]; 1: Prepend<T, Conv<ExactExtract<U, T>>>;}[U extends T ? 0 : 1];
|
||||||
|
|
||||||
|
|
||||||
//// [infiniteConstraints.js]
|
//// [infiniteConstraints.js]
|
||||||
"use strict";
|
"use strict";
|
||||||
// Both of the following types trigger the recursion limiter in getImmediateBaseConstraint
|
// Both of the following types trigger the recursion limiter in getImmediateBaseConstraint
|
||||||
|
exports.__esModule = true;
|
||||||
var out = myBug({ obj1: { a: "test" } });
|
var out = myBug({ obj1: { a: "test" } });
|
||||||
var noError = ensureNoDuplicates({ main: value("test"), alternate: value("test2") });
|
var noError = ensureNoDuplicates({ main: value("test"), alternate: value("test2") });
|
||||||
var shouldBeNoError = ensureNoDuplicates({ main: value("test") });
|
var shouldBeNoError = ensureNoDuplicates({ main: value("test") });
|
||||||
|
|
|
@ -138,3 +138,53 @@ declare function function1<T extends {[K in keyof T]: Cond<T[K]>}>(): T[keyof T]
|
||||||
>T : Symbol(T, Decl(infiniteConstraints.ts, 35, 27))
|
>T : Symbol(T, Decl(infiniteConstraints.ts, 35, 27))
|
||||||
>T : Symbol(T, Decl(infiniteConstraints.ts, 35, 27))
|
>T : Symbol(T, Decl(infiniteConstraints.ts, 35, 27))
|
||||||
|
|
||||||
|
// Repro from #31823
|
||||||
|
|
||||||
|
export type Prepend<Elm, T extends unknown[]> =
|
||||||
|
>Prepend : Symbol(Prepend, Decl(infiniteConstraints.ts, 35, 88))
|
||||||
|
>Elm : Symbol(Elm, Decl(infiniteConstraints.ts, 39, 20))
|
||||||
|
>T : Symbol(T, Decl(infiniteConstraints.ts, 39, 24))
|
||||||
|
|
||||||
|
T extends unknown ?
|
||||||
|
>T : Symbol(T, Decl(infiniteConstraints.ts, 39, 24))
|
||||||
|
|
||||||
|
((arg: Elm, ...rest: T) => void) extends ((...args: infer T2) => void) ? T2 :
|
||||||
|
>arg : Symbol(arg, Decl(infiniteConstraints.ts, 41, 4))
|
||||||
|
>Elm : Symbol(Elm, Decl(infiniteConstraints.ts, 39, 20))
|
||||||
|
>rest : Symbol(rest, Decl(infiniteConstraints.ts, 41, 13))
|
||||||
|
>T : Symbol(T, Decl(infiniteConstraints.ts, 39, 24))
|
||||||
|
>args : Symbol(args, Decl(infiniteConstraints.ts, 41, 45))
|
||||||
|
>T2 : Symbol(T2, Decl(infiniteConstraints.ts, 41, 59))
|
||||||
|
>T2 : Symbol(T2, Decl(infiniteConstraints.ts, 41, 59))
|
||||||
|
|
||||||
|
never :
|
||||||
|
never;
|
||||||
|
export type ExactExtract<T, U> = T extends U ? U extends T ? T : never : never;
|
||||||
|
>ExactExtract : Symbol(ExactExtract, Decl(infiniteConstraints.ts, 43, 8))
|
||||||
|
>T : Symbol(T, Decl(infiniteConstraints.ts, 44, 25))
|
||||||
|
>U : Symbol(U, Decl(infiniteConstraints.ts, 44, 27))
|
||||||
|
>T : Symbol(T, Decl(infiniteConstraints.ts, 44, 25))
|
||||||
|
>U : Symbol(U, Decl(infiniteConstraints.ts, 44, 27))
|
||||||
|
>U : Symbol(U, Decl(infiniteConstraints.ts, 44, 27))
|
||||||
|
>T : Symbol(T, Decl(infiniteConstraints.ts, 44, 25))
|
||||||
|
>T : Symbol(T, Decl(infiniteConstraints.ts, 44, 25))
|
||||||
|
|
||||||
|
type Conv<T, U = T> =
|
||||||
|
>Conv : Symbol(Conv, Decl(infiniteConstraints.ts, 44, 79))
|
||||||
|
>T : Symbol(T, Decl(infiniteConstraints.ts, 46, 10))
|
||||||
|
>U : Symbol(U, Decl(infiniteConstraints.ts, 46, 12))
|
||||||
|
>T : Symbol(T, Decl(infiniteConstraints.ts, 46, 10))
|
||||||
|
|
||||||
|
{ 0: [T]; 1: Prepend<T, Conv<ExactExtract<U, T>>>;}[U extends T ? 0 : 1];
|
||||||
|
>0 : Symbol(0, Decl(infiniteConstraints.ts, 47, 3))
|
||||||
|
>T : Symbol(T, Decl(infiniteConstraints.ts, 46, 10))
|
||||||
|
>1 : Symbol(1, Decl(infiniteConstraints.ts, 47, 11))
|
||||||
|
>Prepend : Symbol(Prepend, Decl(infiniteConstraints.ts, 35, 88))
|
||||||
|
>T : Symbol(T, Decl(infiniteConstraints.ts, 46, 10))
|
||||||
|
>Conv : Symbol(Conv, Decl(infiniteConstraints.ts, 44, 79))
|
||||||
|
>ExactExtract : Symbol(ExactExtract, Decl(infiniteConstraints.ts, 43, 8))
|
||||||
|
>U : Symbol(U, Decl(infiniteConstraints.ts, 46, 12))
|
||||||
|
>T : Symbol(T, Decl(infiniteConstraints.ts, 46, 10))
|
||||||
|
>U : Symbol(U, Decl(infiniteConstraints.ts, 46, 12))
|
||||||
|
>T : Symbol(T, Decl(infiniteConstraints.ts, 46, 10))
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -36,3 +36,15 @@ const shouldBeError = ensureNoDuplicates({main: value("dup"), alternate: value("
|
||||||
|
|
||||||
type Cond<T> = T extends number ? number : never;
|
type Cond<T> = T extends number ? number : never;
|
||||||
declare function function1<T extends {[K in keyof T]: Cond<T[K]>}>(): T[keyof T]["foo"];
|
declare function function1<T extends {[K in keyof T]: Cond<T[K]>}>(): T[keyof T]["foo"];
|
||||||
|
|
||||||
|
// Repro from #31823
|
||||||
|
|
||||||
|
export type Prepend<Elm, T extends unknown[]> =
|
||||||
|
T extends unknown ?
|
||||||
|
((arg: Elm, ...rest: T) => void) extends ((...args: infer T2) => void) ? T2 :
|
||||||
|
never :
|
||||||
|
never;
|
||||||
|
export type ExactExtract<T, U> = T extends U ? U extends T ? T : never : never;
|
||||||
|
|
||||||
|
type Conv<T, U = T> =
|
||||||
|
{ 0: [T]; 1: Prepend<T, Conv<ExactExtract<U, T>>>;}[U extends T ? 0 : 1];
|
||||||
|
|
Loading…
Reference in a new issue