@@ -19610,30 +19610,33 @@ namespace ts {
19610
19610
function isDeeplyNestedType(type: Type, stack: Type[], depth: number): boolean {
19611
19611
if (depth >= 5) {
19612
19612
const identity = getRecursionIdentity(type);
19613
- if (identity) {
19614
- let count = 0;
19615
- for (let i = 0; i < depth; i++) {
19616
- if (getRecursionIdentity(stack[i]) === identity) {
19617
- count++;
19618
- if (count >= 5) {
19619
- return true;
19620
- }
19613
+ let count = 0;
19614
+ for (let i = 0; i < depth; i++) {
19615
+ if (getRecursionIdentity(stack[i]) === identity) {
19616
+ count++;
19617
+ if (count >= 5) {
19618
+ return true;
19621
19619
}
19622
19620
}
19623
19621
}
19624
19622
}
19625
19623
return false;
19626
19624
}
19627
19625
19628
- // Types with constituents that could circularly reference the type have a recursion identity. The recursion
19629
- // identity is some object that is common to instantiations of the type with the same origin.
19630
- function getRecursionIdentity(type: Type): object | undefined {
19626
+ // The recursion identity of a type is an object identity that is shared among multiple instantiations of the type.
19627
+ // We track recursion identities in order to identify deeply nested and possibly infinite type instantiations with
19628
+ // the same origin. For example, when type parameters are in scope in an object type such as { x: T }, all
19629
+ // instantiations of that type have the same recursion identity. The default recursion identity is the object
19630
+ // identity of the type, meaning that every type is unique. Generally, types with constituents that could circularly
19631
+ // reference the type have a recursion identity that differs from the object identity.
19632
+ function getRecursionIdentity(type: Type): object {
19633
+ // Object and array literals are known not to contain recursive references and don't need a recursion identity.
19631
19634
if (type.flags & TypeFlags.Object && !isObjectOrArrayLiteralType(type)) {
19632
19635
if (getObjectFlags(type) && ObjectFlags.Reference && (type as TypeReference).node) {
19633
19636
// Deferred type references are tracked through their associated AST node. This gives us finer
19634
19637
// granularity than using their associated target because each manifest type reference has a
19635
19638
// unique AST node.
19636
- return (type as TypeReference).node;
19639
+ return (type as TypeReference).node! ;
19637
19640
}
19638
19641
if (type.symbol && !(getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol.flags & SymbolFlags.Class)) {
19639
19642
// We track all object types that have an associated symbol (representing the origin of the type), but
@@ -19645,6 +19648,9 @@ namespace ts {
19645
19648
return type.target;
19646
19649
}
19647
19650
}
19651
+ if (type.flags & TypeFlags.TypeParameter) {
19652
+ return type.symbol;
19653
+ }
19648
19654
if (type.flags & TypeFlags.IndexedAccess) {
19649
19655
// Identity is the leftmost object type in a chain of indexed accesses, eg, in A[P][Q] it is A
19650
19656
do {
@@ -19656,7 +19662,7 @@ namespace ts {
19656
19662
// The root object represents the origin of the conditional type
19657
19663
return (type as ConditionalType).root;
19658
19664
}
19659
- return undefined ;
19665
+ return type ;
19660
19666
}
19661
19667
19662
19668
function isPropertyIdenticalTo(sourceProp: Symbol, targetProp: Symbol): boolean {
@@ -19840,13 +19846,7 @@ namespace ts {
19840
19846
function isArrayLikeType(type: Type): boolean {
19841
19847
// A type is array-like if it is a reference to the global Array or global ReadonlyArray type,
19842
19848
// or if it is not the undefined or null type and if it is assignable to ReadonlyArray<any>
19843
- return isArrayType(type) || hasArrayOrReadonlyArrayBaseType(type) || !(type.flags & TypeFlags.Nullable) && isTypeAssignableTo(type, anyReadonlyArrayType);
19844
- }
19845
-
19846
- function hasArrayOrReadonlyArrayBaseType(type: Type): boolean {
19847
- return !!(getObjectFlags(type) & ObjectFlags.Reference)
19848
- && !!(getObjectFlags((type as TypeReference).target) & ObjectFlags.ClassOrInterface)
19849
- && some(getBaseTypes((type as TypeReference).target as InterfaceType), isArrayType);
19849
+ return isArrayType(type) || !(type.flags & TypeFlags.Nullable) && isTypeAssignableTo(type, anyReadonlyArrayType);
19850
19850
}
19851
19851
19852
19852
function isEmptyArrayLiteralType(type: Type): boolean {
@@ -21083,16 +21083,16 @@ namespace ts {
21083
21083
// We stop inferring and report a circularity if we encounter duplicate recursion identities on both
21084
21084
// the source side and the target side.
21085
21085
const saveExpandingFlags = expandingFlags;
21086
- const sourceIdentity = getRecursionIdentity(source) || source ;
21087
- const targetIdentity = getRecursionIdentity(target) || target ;
21088
- if (sourceIdentity && contains(sourceStack, sourceIdentity)) expandingFlags |= ExpandingFlags.Source;
21089
- if (targetIdentity && contains(targetStack, targetIdentity)) expandingFlags |= ExpandingFlags.Target;
21086
+ const sourceIdentity = getRecursionIdentity(source);
21087
+ const targetIdentity = getRecursionIdentity(target);
21088
+ if (contains(sourceStack, sourceIdentity)) expandingFlags |= ExpandingFlags.Source;
21089
+ if (contains(targetStack, targetIdentity)) expandingFlags |= ExpandingFlags.Target;
21090
21090
if (expandingFlags !== ExpandingFlags.Both) {
21091
- if (sourceIdentity) (sourceStack || (sourceStack = [])).push(sourceIdentity);
21092
- if (targetIdentity) (targetStack || (targetStack = [])).push(targetIdentity);
21091
+ (sourceStack || (sourceStack = [])).push(sourceIdentity);
21092
+ (targetStack || (targetStack = [])).push(targetIdentity);
21093
21093
action(source, target);
21094
- if (targetIdentity) targetStack.pop();
21095
- if (sourceIdentity) sourceStack.pop();
21094
+ targetStack.pop();
21095
+ sourceStack.pop();
21096
21096
}
21097
21097
else {
21098
21098
inferencePriority = InferencePriority.Circularity;
0 commit comments