@@ -8661,6 +8661,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
86618661 }
86628662
86638663 function symbolToTypeNode(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, overrideTypeArguments?: readonly TypeNode[]): TypeNode {
8664+ // Prevent infinite recursion when a function's return type references itself (e.g., ReturnType<typeof clone>)
8665+ if (!context.visitedSymbols) {
8666+ context.visitedSymbols = new Set();
8667+ }
8668+ const symbolKey = `${getSymbolId(symbol)}|${meaning}`;
8669+ if (context.visitedSymbols.has(symbolKey)) {
8670+ // Detected recursive symbol reference, return never type to avoid crash
8671+ return factory.createKeywordTypeNode(SyntaxKind.NeverKeyword);
8672+ }
8673+ context.visitedSymbols.add(symbolKey);
8674+
86648675 const chain = lookupSymbolChain(symbol, context, meaning, !(context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope)); // If we're using aliases outside the current scope, dont bother with the module
86658676
86668677 const isTypeOf = meaning === SymbolFlags.Value;
@@ -8723,33 +8734,39 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
87238734 }
87248735 const lit = factory.createLiteralTypeNode(factory.createStringLiteral(specifier));
87258736 context.approximateLength += specifier.length + 10; // specifier + import("")
8737+ let result: TypeNode;
87268738 if (!nonRootParts || isEntityName(nonRootParts)) {
87278739 if (nonRootParts) {
87288740 const lastId = isIdentifier(nonRootParts) ? nonRootParts : nonRootParts.right;
87298741 setIdentifierTypeArguments(lastId, /*typeArguments*/ undefined);
87308742 }
8731- return factory.createImportTypeNode(lit, attributes, nonRootParts as EntityName, typeParameterNodes as readonly TypeNode[], isTypeOf);
8743+ result = factory.createImportTypeNode(lit, attributes, nonRootParts as EntityName, typeParameterNodes as readonly TypeNode[], isTypeOf);
87328744 }
87338745 else {
87348746 const splitNode = getTopmostIndexedAccessType(nonRootParts);
87358747 const qualifier = (splitNode.objectType as TypeReferenceNode).typeName;
8736- return factory.createIndexedAccessTypeNode(factory.createImportTypeNode(lit, attributes, qualifier, typeParameterNodes as readonly TypeNode[], isTypeOf), splitNode.indexType);
8748+ result = factory.createIndexedAccessTypeNode(factory.createImportTypeNode(lit, attributes, qualifier, typeParameterNodes as readonly TypeNode[], isTypeOf), splitNode.indexType);
87378749 }
8750+ context.visitedSymbols.delete(symbolKey);
8751+ return result;
87388752 }
87398753
87408754 const entityName = createAccessFromSymbolChain(chain, chain.length - 1, 0);
8755+ let result: TypeNode;
87418756 if (isIndexedAccessTypeNode(entityName)) {
8742- return entityName; // Indexed accesses can never be `typeof`
8757+ result = entityName; // Indexed accesses can never be `typeof`
87438758 }
8744- if (isTypeOf) {
8745- return factory.createTypeQueryNode(entityName);
8759+ else if (isTypeOf) {
8760+ result = factory.createTypeQueryNode(entityName);
87468761 }
87478762 else {
87488763 const lastId = isIdentifier(entityName) ? entityName : entityName.right;
87498764 const lastTypeArgs = getIdentifierTypeArguments(lastId);
87508765 setIdentifierTypeArguments(lastId, /*typeArguments*/ undefined);
8751- return factory.createTypeReferenceNode(entityName, lastTypeArgs as NodeArray<TypeNode>);
8766+ result = factory.createTypeReferenceNode(entityName, lastTypeArgs as NodeArray<TypeNode>);
87528767 }
8768+ context.visitedSymbols.delete(symbolKey);
8769+ return result;
87538770
87548771 function createAccessFromSymbolChain(chain: Symbol[], index: number, stopper: number): EntityName | IndexedAccessTypeNode {
87558772 const typeParameterNodes = index === (chain.length - 1) ? overrideTypeArguments : lookupTypeParameterNodes(chain, index, context);
@@ -54300,6 +54317,7 @@ interface NodeBuilderContext extends SyntacticTypeNodeBuilderContext {
5430054317 reportedDiagnostic: boolean;
5430154318 trackedSymbols: TrackedSymbol[] | undefined;
5430254319 visitedTypes: Set<number> | undefined;
54320+ visitedSymbols: Set<string> | undefined;
5430354321 symbolDepth: Map<string, number> | undefined;
5430454322 inferTypeParameters: TypeParameter[] | undefined;
5430554323 approximateLength: number;
0 commit comments