From 5f37d89c881dcbe3234f47b34cdd124fa779a912 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 30 Oct 2021 18:04:39 -0700 Subject: [PATCH] Keep indexed access recursion depth check --- src/compiler/checker.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index daade99214e..e6a4c2d8c7c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -20359,6 +20359,13 @@ namespace ts { // though highly unlikely, for this test to be true in a situation where a chain of instantiations is not infinitely // expanding. Effectively, we will generate a false positive when two types are structurally equal to at least maxDepth // levels, but unequal at some level beyond that. + // In addition, this will also detect when an indexed access has been chained off of maxDepth more times (which is + // essentially the dual of the structural comparison), and likewise mark the type as deeply nested, potentially adding + // false positives for finite but deeply expanding indexed accesses (eg, for `Q[P1][P2][P3][P4][P5]`). + // It also detects when a recursive type reference has expanded maxDepth or more times, e.g. if the true branch of + // `type A = null extends T ? [A>] : [T]` + // has expanded into `[A>>>>>]`. In such cases we need + // to terminate the expansion, and we do so here. function isDeeplyNestedType(type: Type, stack: Type[], depth: number, maxDepth = 3): boolean { if (depth >= maxDepth) { const identity = getRecursionIdentity(type); @@ -20410,6 +20417,13 @@ namespace ts { if (type.flags & TypeFlags.TypeParameter) { return type.symbol; } + if (type.flags & TypeFlags.IndexedAccess) { + // Identity is the leftmost object type in a chain of indexed accesses, eg, in A[P][Q] it is A + do { + type = (type as IndexedAccessType).objectType; + } while (type.flags & TypeFlags.IndexedAccess); + return type; + } if (type.flags & TypeFlags.Conditional) { // The root object represents the origin of the conditional type return (type as ConditionalType).root;