Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit ddc106b

Browse files
committedOct 29, 2021
Decrease recursion depth limit to 3 + smarter check for recursion
1 parent fd620c9 commit ddc106b

File tree

1 file changed

+9
-18
lines changed

1 file changed

+9
-18
lines changed
 

‎src/compiler/checker.ts

+9-18
Original file line numberDiff line numberDiff line change
@@ -20355,27 +20355,25 @@ namespace ts {
2035520355
}
2035620356

2035720357
// Return true if the given type is deeply nested. We consider this to be the case when structural type comparisons
20358-
// for 5 or more occurrences or instantiations of the type have been recorded on the given stack. It is possible,
20358+
// for maxDepth or more occurrences or instantiations of the type have been recorded on the given stack. It is possible,
2035920359
// though highly unlikely, for this test to be true in a situation where a chain of instantiations is not infinitely
20360-
// expanding. Effectively, we will generate a false positive when two types are structurally equal to at least 5
20360+
// expanding. Effectively, we will generate a false positive when two types are structurally equal to at least maxDepth
2036120361
// levels, but unequal at some level beyond that.
20362-
// In addition, this will also detect when an indexed access has been chained off of 5 or more times (which is essentially
20363-
// the dual of the structural comparison), and likewise mark the type as deeply nested, potentially adding false positives
20364-
// for finite but deeply expanding indexed accesses (eg, for `Q[P1][P2][P3][P4][P5]`).
20365-
// It also detects when a recursive type reference has expanded 5 or more times, eg, if the true branch of
20366-
// `type A<T> = null extends T ? [A<NonNullable<T>>] : [T]`
20367-
// has expanded into `[A<NonNullable<NonNullable<NonNullable<NonNullable<NonNullable<T>>>>>>]`
20368-
// in such cases we need to terminate the expansion, and we do so here.
20369-
function isDeeplyNestedType(type: Type, stack: Type[], depth: number, maxDepth = 5): boolean {
20362+
function isDeeplyNestedType(type: Type, stack: Type[], depth: number, maxDepth = 3): boolean {
2037020363
if (depth >= maxDepth) {
2037120364
const identity = getRecursionIdentity(type);
2037220365
let count = 0;
20366+
let lastTypeId = 0;
2037320367
for (let i = 0; i < depth; i++) {
20374-
if (getRecursionIdentity(stack[i]) === identity) {
20368+
const t = stack[i];
20369+
// We only count occurrences with higher type ids than the previous occurrences, since higher
20370+
// type ids are an indicator of newer instantiations caused by recursion.
20371+
if (getRecursionIdentity(t) === identity && t.id >= lastTypeId) {
2037520372
count++;
2037620373
if (count >= maxDepth) {
2037720374
return true;
2037820375
}
20376+
lastTypeId = t.id;
2037920377
}
2038020378
}
2038120379
}
@@ -20410,13 +20408,6 @@ namespace ts {
2041020408
if (type.flags & TypeFlags.TypeParameter) {
2041120409
return type.symbol;
2041220410
}
20413-
if (type.flags & TypeFlags.IndexedAccess) {
20414-
// Identity is the leftmost object type in a chain of indexed accesses, eg, in A[P][Q] it is A
20415-
do {
20416-
type = (type as IndexedAccessType).objectType;
20417-
} while (type.flags & TypeFlags.IndexedAccess);
20418-
return type;
20419-
}
2042020411
if (type.flags & TypeFlags.Conditional) {
2042120412
// The root object represents the origin of the conditional type
2042220413
return (type as ConditionalType).root;

0 commit comments

Comments
 (0)
Please sign in to comment.