Skip to content

Commit 9e4fc80

Browse files
committed
Fix getRecursionIdentity, undo changes from #43435 (but keep tests)
1 parent 38da7c6 commit 9e4fc80

File tree

1 file changed

+29
-31
lines changed

1 file changed

+29
-31
lines changed

src/compiler/checker.ts

Lines changed: 29 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -19555,30 +19555,33 @@ namespace ts {
1955519555
function isDeeplyNestedType(type: Type, stack: Type[], depth: number): boolean {
1955619556
if (depth >= 5) {
1955719557
const identity = getRecursionIdentity(type);
19558-
if (identity) {
19559-
let count = 0;
19560-
for (let i = 0; i < depth; i++) {
19561-
if (getRecursionIdentity(stack[i]) === identity) {
19562-
count++;
19563-
if (count >= 5) {
19564-
return true;
19565-
}
19558+
let count = 0;
19559+
for (let i = 0; i < depth; i++) {
19560+
if (getRecursionIdentity(stack[i]) === identity) {
19561+
count++;
19562+
if (count >= 5) {
19563+
return true;
1956619564
}
1956719565
}
1956819566
}
1956919567
}
1957019568
return false;
1957119569
}
1957219570

19573-
// Types with constituents that could circularly reference the type have a recursion identity. The recursion
19574-
// identity is some object that is common to instantiations of the type with the same origin.
19575-
function getRecursionIdentity(type: Type): object | undefined {
19571+
// The recursion identity of a type is an object identity that is shared among multiple instantiations of the type.
19572+
// We track recursion identities in order to identify deeply nested and possibly infinite type instantiations with
19573+
// the same origin. For example, when type parameters are in scope in an object type such as { x: T }, all
19574+
// instantiations of that type have the same recursion identity. The default recursion identity is the object
19575+
// identity of the type, meaning that every type is unique. Generally, types with constituents that could circularly
19576+
// reference the type have a recursion identity that differs from the object identity.
19577+
function getRecursionIdentity(type: Type): object {
19578+
// Object and array literals are known not to contain recursive references and don't need a recursion identity.
1957619579
if (type.flags & TypeFlags.Object && !isObjectOrArrayLiteralType(type)) {
1957719580
if (getObjectFlags(type) && ObjectFlags.Reference && (type as TypeReference).node) {
1957819581
// Deferred type references are tracked through their associated AST node. This gives us finer
1957919582
// granularity than using their associated target because each manifest type reference has a
1958019583
// unique AST node.
19581-
return (type as TypeReference).node;
19584+
return (type as TypeReference).node!;
1958219585
}
1958319586
if (type.symbol && !(getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol.flags & SymbolFlags.Class)) {
1958419587
// We track all object types that have an associated symbol (representing the origin of the type), but
@@ -19590,18 +19593,19 @@ namespace ts {
1959019593
return type.target;
1959119594
}
1959219595
}
19596+
if (type.flags & TypeFlags.TypeParameter) {
19597+
return type.symbol;
19598+
}
1959319599
if (type.flags & TypeFlags.IndexedAccess) {
1959419600
// Identity is the leftmost object type in a chain of indexed accesses, eg, in A[P][Q] it is A
19595-
do {
19596-
type = (type as IndexedAccessType).objectType;
19597-
} while (type.flags & TypeFlags.IndexedAccess);
19601+
do { type = (type as IndexedAccessType).objectType } while (type.flags & TypeFlags.IndexedAccess);
1959819602
return type;
1959919603
}
1960019604
if (type.flags & TypeFlags.Conditional) {
1960119605
// The root object represents the origin of the conditional type
1960219606
return (type as ConditionalType).root;
1960319607
}
19604-
return undefined;
19608+
return type;
1960519609
}
1960619610

1960719611
function isPropertyIdenticalTo(sourceProp: Symbol, targetProp: Symbol): boolean {
@@ -19785,13 +19789,7 @@ namespace ts {
1978519789
function isArrayLikeType(type: Type): boolean {
1978619790
// A type is array-like if it is a reference to the global Array or global ReadonlyArray type,
1978719791
// or if it is not the undefined or null type and if it is assignable to ReadonlyArray<any>
19788-
return isArrayType(type) || hasArrayOrReadonlyArrayBaseType(type) || !(type.flags & TypeFlags.Nullable) && isTypeAssignableTo(type, anyReadonlyArrayType);
19789-
}
19790-
19791-
function hasArrayOrReadonlyArrayBaseType(type: Type): boolean {
19792-
return !!(getObjectFlags(type) & ObjectFlags.Reference)
19793-
&& !!(getObjectFlags((type as TypeReference).target) & ObjectFlags.ClassOrInterface)
19794-
&& some(getBaseTypes((type as TypeReference).target as InterfaceType), isArrayType);
19792+
return isArrayType(type) || !(type.flags & TypeFlags.Nullable) && isTypeAssignableTo(type, anyReadonlyArrayType);
1979519793
}
1979619794

1979719795
function isEmptyArrayLiteralType(type: Type): boolean {
@@ -21024,16 +21022,16 @@ namespace ts {
2102421022
// We stop inferring and report a circularity if we encounter duplicate recursion identities on both
2102521023
// the source side and the target side.
2102621024
const saveExpandingFlags = expandingFlags;
21027-
const sourceIdentity = getRecursionIdentity(source) || source;
21028-
const targetIdentity = getRecursionIdentity(target) || target;
21029-
if (sourceIdentity && contains(sourceStack, sourceIdentity)) expandingFlags |= ExpandingFlags.Source;
21030-
if (targetIdentity && contains(targetStack, targetIdentity)) expandingFlags |= ExpandingFlags.Target;
21025+
const sourceIdentity = getRecursionIdentity(source);
21026+
const targetIdentity = getRecursionIdentity(target);
21027+
if (contains(sourceStack, sourceIdentity)) expandingFlags |= ExpandingFlags.Source;
21028+
if (contains(targetStack, targetIdentity)) expandingFlags |= ExpandingFlags.Target;
2103121029
if (expandingFlags !== ExpandingFlags.Both) {
21032-
if (sourceIdentity) (sourceStack || (sourceStack = [])).push(sourceIdentity);
21033-
if (targetIdentity) (targetStack || (targetStack = [])).push(targetIdentity);
21030+
(sourceStack || (sourceStack = [])).push(sourceIdentity);
21031+
(targetStack || (targetStack = [])).push(targetIdentity);
2103421032
action(source, target);
21035-
if (targetIdentity) targetStack.pop();
21036-
if (sourceIdentity) sourceStack.pop();
21033+
targetStack.pop();
21034+
sourceStack.pop();
2103721035
}
2103821036
else {
2103921037
inferencePriority = InferencePriority.Circularity;

0 commit comments

Comments
 (0)