From 8e70199ad4d29f8de4d79a6c10c8908828215f42 Mon Sep 17 00:00:00 2001 From: Eric Traut Date: Fri, 17 Jan 2025 11:06:22 -0800 Subject: [PATCH] Fixed a bug that results in a false positive "recursive type definition" error under certain circumstances when the number of declarations for a symbol exceeds the internal threshold of 16. This addresses #9721. (#9722) --- .../pyright-internal/src/analyzer/typeEvaluator.ts | 14 ++++++++++++-- .../src/analyzer/typeEvaluatorTypes.ts | 1 + 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/pyright-internal/src/analyzer/typeEvaluator.ts b/packages/pyright-internal/src/analyzer/typeEvaluator.ts index 594f9b3883f6..dd7efe510886 100644 --- a/packages/pyright-internal/src/analyzer/typeEvaluator.ts +++ b/packages/pyright-internal/src/analyzer/typeEvaluator.ts @@ -22675,13 +22675,21 @@ export function createTypeEvaluator( if (declaredType || !declaredTypeInfo.isTypeAlias) { const typedDecls = symbol.getTypedDeclarations(); + // If we received an undefined declared type, this can be caused by + // exceeding the max number of type declarations, speculative + // evaluation, or a recursive definition. + const isRecursiveDefinition = + !declaredType && + !declaredTypeInfo.exceedsMaxDecls && + !speculativeTypeTracker.isSpeculative(/* node */ undefined); + const result: EffectiveTypeResult = { type: declaredType ?? UnknownType.create(), isIncomplete, includesVariableDecl: includesVariableTypeDecl(typedDecls), includesIllegalTypeAliasDecl: !typedDecls.every((decl) => isPossibleTypeAliasDeclaration(decl)), includesSpeculativeResult: false, - isRecursiveDefinition: !declaredType && !speculativeTypeTracker.isSpeculative(/* node */ undefined), + isRecursiveDefinition, }; return result; @@ -22991,12 +22999,14 @@ export function createTypeEvaluator( // reachable from the usage node (if specified). This can happen in // cases where a property symbol is redefined to add a setter, deleter, // etc. + let exceedsMaxDecls = false; if (usageNode && typedDecls.length > 1) { if (typedDecls.length > maxTypedDeclsPerSymbol) { // If there are too many typed decls, don't bother filtering them // because this can be very expensive. Simply use the last one // in this case. typedDecls = [typedDecls[typedDecls.length - 1]]; + exceedsMaxDecls = true; } else { const filteredTypedDecls = typedDecls.filter((decl) => { if (decl.type !== DeclarationType.Alias) { @@ -23062,7 +23072,7 @@ export function createTypeEvaluator( declIndex--; } - return { type: undefined }; + return { type: undefined, exceedsMaxDecls }; } function inferReturnTypeIfNecessary(type: Type) { diff --git a/packages/pyright-internal/src/analyzer/typeEvaluatorTypes.ts b/packages/pyright-internal/src/analyzer/typeEvaluatorTypes.ts index ba6f4b2d6c04..3bbbab30cfa9 100644 --- a/packages/pyright-internal/src/analyzer/typeEvaluatorTypes.ts +++ b/packages/pyright-internal/src/analyzer/typeEvaluatorTypes.ts @@ -511,6 +511,7 @@ export interface PrintTypeOptions { export interface DeclaredSymbolTypeInfo { type: Type | undefined; isTypeAlias?: boolean; + exceedsMaxDecls?: boolean; } export interface ResolveAliasOptions {