From 93ff28f4d39a66ae5eb97b0b1db4bec1e8f0f13f Mon Sep 17 00:00:00 2001 From: Eric Traut Date: Mon, 19 Aug 2024 11:15:21 -0700 Subject: [PATCH] Fixed bug that results in a false positive error under very specific conditions involving a recursive type alias that is defined in terms of another type alias. This addresses #8784. --- .../src/analyzer/typeUtils.ts | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/packages/pyright-internal/src/analyzer/typeUtils.ts b/packages/pyright-internal/src/analyzer/typeUtils.ts index fe4bd20d71e2..8e49cdbc9721 100644 --- a/packages/pyright-internal/src/analyzer/typeUtils.ts +++ b/packages/pyright-internal/src/analyzer/typeUtils.ts @@ -1026,9 +1026,16 @@ export function isTypeAliasRecursive(typeAliasPlaceholder: TypeVarType, type: Ty ); } -export function transformPossibleRecursiveTypeAlias(type: Type): Type; -export function transformPossibleRecursiveTypeAlias(type: Type | undefined): Type | undefined; -export function transformPossibleRecursiveTypeAlias(type: Type | undefined): Type | undefined { +// Recursively transforms all top-level TypeVars that represent recursive +// type aliases into their actual types. +export function transformPossibleRecursiveTypeAlias(type: Type, recursionCount?: number): Type; +export function transformPossibleRecursiveTypeAlias(type: Type | undefined, recursionCount?: number): Type | undefined; +export function transformPossibleRecursiveTypeAlias(type: Type | undefined, recursionCount = 0): Type | undefined { + if (recursionCount >= maxTypeRecursionCount) { + return type; + } + recursionCount++; + if (type) { const aliasInfo = type.props?.typeAliasInfo; @@ -1038,15 +1045,18 @@ export function transformPossibleRecursiveTypeAlias(type: Type | undefined): Typ : type.shared.boundType; if (!aliasInfo?.typeArgs || !type.shared.recursiveAlias.typeParams) { - return unspecializedType; + return transformPossibleRecursiveTypeAlias(unspecializedType, recursionCount); } const solution = buildSolution(type.shared.recursiveAlias.typeParams, aliasInfo.typeArgs); - return applySolvedTypeVars(unspecializedType, solution); + return transformPossibleRecursiveTypeAlias( + applySolvedTypeVars(unspecializedType, solution), + recursionCount + ); } if (isUnion(type) && type.priv.includesRecursiveTypeAlias) { - let newType = mapSubtypes(type, (subtype) => transformPossibleRecursiveTypeAlias(subtype)); + let newType = mapSubtypes(type, (subtype) => transformPossibleRecursiveTypeAlias(subtype, recursionCount)); if (newType !== type && aliasInfo) { // Copy the type alias information if present.