@@ -3540,7 +3540,6 @@ namespace ts {
35403540 }
35413541
35423542 function createNodeBuilder() {
3543- let depth = 0;
35443543 return {
35453544 typeToTypeNode: (type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker) =>
35463545 withContext(enclosingDeclaration, flags, tracker, context => typeToTypeNodeHelper(type, context)),
@@ -3712,7 +3711,7 @@ namespace ts {
37123711
37133712 if (objectFlags & ObjectFlags.Reference) {
37143713 Debug.assert(!!(type.flags & TypeFlags.Object));
3715- return typeReferenceToTypeNode(<TypeReference>type);
3714+ return (<TypeReference>type).node ? visitAndTransformType(type, typeReferenceToTypeNode) : typeReferenceToTypeNode(<TypeReference>type);
37163715 }
37173716 if (type.flags & TypeFlags.TypeParameter || objectFlags & ObjectFlags.ClassOrInterface) {
37183717 if (type.flags & TypeFlags.TypeParameter && contains(context.inferTypeParameters, type)) {
@@ -3804,10 +3803,7 @@ namespace ts {
38043803 function createAnonymousTypeNode(type: ObjectType): TypeNode {
38053804 const typeId = "" + type.id;
38063805 const symbol = type.symbol;
3807- let id: string;
38083806 if (symbol) {
3809- const isConstructorObject = getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & SymbolFlags.Class;
3810- id = (isConstructorObject ? "+" : "") + getSymbolId(symbol);
38113807 if (isJSConstructor(symbol.valueDeclaration)) {
38123808 // Instance and static types share the same symbol; only add 'typeof' for the static side.
38133809 const isInstanceType = type === getInferredClassType(symbol) ? SymbolFlags.Type : SymbolFlags.Value;
@@ -3831,25 +3827,7 @@ namespace ts {
38313827 }
38323828 }
38333829 else {
3834- // Since instantiations of the same anonymous type have the same symbol, tracking symbols instead
3835- // of types allows us to catch circular references to instantiations of the same anonymous type
3836- if (!context.visitedTypes) {
3837- context.visitedTypes = createMap<true>();
3838- }
3839- if (!context.symbolDepth) {
3840- context.symbolDepth = createMap<number>();
3841- }
3842-
3843- const depth = context.symbolDepth.get(id) || 0;
3844- if (depth > 10) {
3845- return createElidedInformationPlaceholder(context);
3846- }
3847- context.symbolDepth.set(id, depth + 1);
3848- context.visitedTypes.set(typeId, true);
3849- const result = createTypeNodeFromObjectType(type);
3850- context.visitedTypes.delete(typeId);
3851- context.symbolDepth.set(id, depth);
3852- return result;
3830+ return visitAndTransformType(type, createTypeNodeFromObjectType);
38533831 }
38543832 }
38553833 else {
@@ -3871,6 +3849,37 @@ namespace ts {
38713849 }
38723850 }
38733851
3852+ function visitAndTransformType<T>(type: Type, transform: (type: Type) => T) {
3853+ const typeId = "" + type.id;
3854+ const isConstructorObject = getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & SymbolFlags.Class;
3855+ const id = getObjectFlags(type) & ObjectFlags.Reference ? "N" + getNodeId((<DeferredTypeReference>type).node) :
3856+ (isConstructorObject ? "+" : "") + getSymbolId(type.symbol);
3857+ // Since instantiations of the same anonymous type have the same symbol, tracking symbols instead
3858+ // of types allows us to catch circular references to instantiations of the same anonymous type
3859+ if (!context.visitedTypes) {
3860+ context.visitedTypes = createMap<true>();
3861+ }
3862+ if (id && !context.symbolDepth) {
3863+ context.symbolDepth = createMap<number>();
3864+ }
3865+
3866+ let depth: number | undefined;
3867+ if (id) {
3868+ depth = context.symbolDepth!.get(id) || 0;
3869+ if (depth > 10) {
3870+ return createElidedInformationPlaceholder(context);
3871+ }
3872+ context.symbolDepth!.set(id, depth + 1);
3873+ }
3874+ context.visitedTypes.set(typeId, true);
3875+ const result = transform(type);
3876+ context.visitedTypes.delete(typeId);
3877+ if (id) {
3878+ context.symbolDepth!.set(id, depth!);
3879+ }
3880+ return result;
3881+ }
3882+
38743883 function createTypeNodeFromObjectType(type: ObjectType): TypeNode {
38753884 if (isGenericMappedType(type)) {
38763885 return createMappedTypeNodeFromType(type);
@@ -3910,15 +3919,10 @@ namespace ts {
39103919 const typeArguments: ReadonlyArray<Type> = getTypeArguments(type);
39113920 if (type.target === globalArrayType || type.target === globalReadonlyArrayType) {
39123921 if (context.flags & NodeBuilderFlags.WriteArrayAsGenericType) {
3913- depth++;
3914- const typeArgumentNode = typeToTypeNodeHelper(depth >= 5 ? anyType : typeArguments[0], context);
3915- depth--;
3916- createTypeReferenceNode(type.target === globalArrayType ? "Array" : "ReadonlyArray", [typeArgumentNode]);
3922+ const typeArgumentNode = typeToTypeNodeHelper(typeArguments[0], context);
3923+ return createTypeReferenceNode(type.target === globalArrayType ? "Array" : "ReadonlyArray", [typeArgumentNode]);
39173924 }
3918-
3919- depth++;
3920- const elementType = typeToTypeNodeHelper(depth >= 5 ? anyType : typeArguments[0], context);
3921- depth--;
3925+ const elementType = typeToTypeNodeHelper(typeArguments[0], context);
39223926 const arrayType = createArrayTypeNode(elementType);
39233927 return type.target === globalArrayType ? arrayType : createTypeOperatorNode(SyntaxKind.ReadonlyKeyword, arrayType);
39243928 }
0 commit comments