Ahejlsberg
I have a fix for this. We solved a similar problem in isDeeplyNestedType
by tracking whether type IDs are increasing as we move up the recursion tracking stack. Increasing type IDs indicate newly generated types, and those we want to count, whereas decreasing type IDs indicate manually written instantiations that we don't want to count. However, the circularity checking in invokeOnce
doesn't use isDeeplyNestedType
, so it doesn't benefit from this. But with this change it can:
function invokeOnce<Source extends Type, Target extends Type>(source: Source, target: Target, action: (source: Source, target: Target) => void) {
const key = source.id + "," + target.id;
const status = visited && visited.get(key);
if (status !== undefined) {
inferencePriority = Math.min(inferencePriority, status);
return;
}
(visited || (visited = new Map<string, number>())).set(key, InferencePriority.Circularity);
const saveInferencePriority = inferencePriority;
inferencePriority = InferencePriority.MaxValue;
// We stop inferring and report a circularity if we encounter duplicate recursion identities on both
// the source side and the target side.
const saveExpandingFlags = expandingFlags;
(sourceStack ??= []).push(source);
(targetStack ??= []).push(target);
if (isDeeplyNestedType(source, sourceStack, sourceStack.length, 2)) expandingFlags |= ExpandingFlags.Source;
if (isDeeplyNestedType(target, targetStack, targetStack.length, 2)) expandingFlags |= ExpandingFlags.Target;
if (expandingFlags !== ExpandingFlags.Both) {
action(source, target);
}
else {
inferencePriority = InferencePriority.Circularity;
}
targetStack.pop();
sourceStack.pop();
expandingFlags = saveExpandingFlags;
visited.set(key, inferencePriority);
inferencePriority = Math.min(inferencePriority, saveInferencePriority);
}
Plus change the declarations of sourceStack
and targetStack
to have type Type[]
.
Best I can tell this takes care of the problem.
Commented On 20 Mar 2023 at 07:35:48