@@ -14549,6 +14549,9 @@ namespace ts {
1454914549 // though highly unlikely, for this test to be true in a situation where a chain of instantiations is not infinitely
1455014550 // expanding. Effectively, we will generate a false positive when two types are structurally equal to at least 5
1455114551 // levels, but unequal at some level beyond that.
14552+ // In addition, this will also detect when an indexed access has been chained off of 5 or more times (which is essentially
14553+ // the dual of the structural comparison), and likewise mark the type as deeply nested, potentially adding false positives
14554+ // for finite but deeply expanding indexed accesses (eg, for `Q[P1][P2][P3][P4][P5]`).
1455214555 function isDeeplyNestedType(type: Type, stack: Type[], depth: number): boolean {
1455314556 // We track all object types that have an associated symbol (representing the origin of the type)
1455414557 if (depth >= 5 && type.flags & TypeFlags.Object) {
@@ -14564,9 +14567,31 @@ namespace ts {
1456414567 }
1456514568 }
1456614569 }
14570+ if (depth >= 5 && type.flags & TypeFlags.IndexedAccess) {
14571+ const root = getRootObjectTypeFromIndexedAccessChain(type);
14572+ let count = 0;
14573+ for (let i = 0; i < depth; i++) {
14574+ const t = stack[i];
14575+ if (getRootObjectTypeFromIndexedAccessChain(t) === root) {
14576+ count++;
14577+ if (count >= 5) return true;
14578+ }
14579+ }
14580+ }
1456714581 return false;
1456814582 }
1456914583
14584+ /**
14585+ * Gets the leftmost object type in a chain of indexed accesses, eg, in A[P][Q], returns A
14586+ */
14587+ function getRootObjectTypeFromIndexedAccessChain(type: Type) {
14588+ let t = type;
14589+ while (t.flags & TypeFlags.IndexedAccess) {
14590+ t = (t as IndexedAccessType).objectType;
14591+ }
14592+ return t;
14593+ }
14594+
1457014595 function isPropertyIdenticalTo(sourceProp: Symbol, targetProp: Symbol): boolean {
1457114596 return compareProperties(sourceProp, targetProp, compareTypesIdentical) !== Ternary.False;
1457214597 }
0 commit comments