Skip to content

Commit

Permalink
Fixed a bug that results in a false positive "recursive type definiti…
Browse files Browse the repository at this point in the history
…on" error under certain circumstances when the number of declarations for a symbol exceeds the internal threshold of 16. This addresses #9721. (#9722)
  • Loading branch information
erictraut authored Jan 17, 2025
1 parent c87dd0b commit 8e70199
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 2 deletions.
14 changes: 12 additions & 2 deletions packages/pyright-internal/src/analyzer/typeEvaluator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -23062,7 +23072,7 @@ export function createTypeEvaluator(
declIndex--;
}

return { type: undefined };
return { type: undefined, exceedsMaxDecls };
}

function inferReturnTypeIfNecessary(type: Type) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,7 @@ export interface PrintTypeOptions {
export interface DeclaredSymbolTypeInfo {
type: Type | undefined;
isTypeAlias?: boolean;
exceedsMaxDecls?: boolean;
}

export interface ResolveAliasOptions {
Expand Down

0 comments on commit 8e70199

Please sign in to comment.