diff --git a/packages/pyright-internal/src/analyzer/typeEvaluator.ts b/packages/pyright-internal/src/analyzer/typeEvaluator.ts index 3cb1cde97..00cb16b50 100644 --- a/packages/pyright-internal/src/analyzer/typeEvaluator.ts +++ b/packages/pyright-internal/src/analyzer/typeEvaluator.ts @@ -183,6 +183,7 @@ import { TypedDictEntry, TypeSourceId, TypeVarScopeId, + TypeVarScopeType, TypeVarType, UnboundType, UnionType, @@ -3479,7 +3480,10 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions type = TypeVarType.cloneForScopeId( type, getScopeIdForNode(enclosingScope), - enclosingScope.name.value + enclosingScope.name.value, + enclosingScope.nodeType === ParseNodeType.Function + ? TypeVarScopeType.Function + : TypeVarScopeType.Class ); } else { fail('AssociateTypeVarsWithCurrentScope flag was set but enclosing scope not found'); @@ -3682,7 +3686,8 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions type: TypeVarType.cloneForScopeId( type, leftType.details.recursiveTypeAliasScopeId, - leftType.details.recursiveTypeAliasName + leftType.details.recursiveTypeAliasName, + TypeVarScopeType.TypeAlias ), foundInterveningClass: false, }; @@ -11832,7 +11837,9 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions const fileInfo = AnalyzerNodeInfo.getFileInfo(name); const typeAliasScopeId = getScopeIdForNode(name); - const boundTypeVars = typeParameters.filter((typeVar) => typeVar.scopeId !== typeAliasScopeId); + const boundTypeVars = typeParameters.filter( + (typeVar) => typeVar.scopeId !== typeAliasScopeId && typeVar.scopeType === TypeVarScopeType.Class + ); if (boundTypeVars.length > 0) { addError( Localizer.Diagnostic.genericTypeAliasBoundTypeVar().format({ @@ -12544,7 +12551,12 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions typeVar.details.isSynthesized = true; typeVar.scopeId = getScopeIdForNode(initDeclNode); typeVar.details.boundType = UnknownType.create(); - return TypeVarType.cloneForScopeId(typeVar, getScopeIdForNode(node), node.name.value); + return TypeVarType.cloneForScopeId( + typeVar, + getScopeIdForNode(node), + node.name.value, + TypeVarScopeType.Class + ); }); } } diff --git a/packages/pyright-internal/src/analyzer/typedDicts.ts b/packages/pyright-internal/src/analyzer/typedDicts.ts index 136ee2ab4..a00c55523 100644 --- a/packages/pyright-internal/src/analyzer/typedDicts.ts +++ b/packages/pyright-internal/src/analyzer/typedDicts.ts @@ -50,6 +50,7 @@ import { OverloadedFunctionType, Type, TypedDictEntry, + TypeVarScopeType, TypeVarType, UnknownType, } from './types'; @@ -300,7 +301,12 @@ export function synthesizeTypedDictClassMethods( const typeVarScopeId = evaluator.getScopeIdForNode(node); let defaultTypeVar = TypeVarType.createInstance(`__${classType.details.name}_default`); defaultTypeVar.details.isSynthesized = true; - defaultTypeVar = TypeVarType.cloneForScopeId(defaultTypeVar, typeVarScopeId, classType.details.name); + defaultTypeVar = TypeVarType.cloneForScopeId( + defaultTypeVar, + typeVarScopeId, + classType.details.name, + TypeVarScopeType.Function + ); const createGetMethod = (keyType: Type, valueType: Type, includeDefault: boolean) => { const getOverload = FunctionType.createInstance( diff --git a/packages/pyright-internal/src/analyzer/types.ts b/packages/pyright-internal/src/analyzer/types.ts index 7ea32f50f..c90b1ee39 100644 --- a/packages/pyright-internal/src/analyzer/types.ts +++ b/packages/pyright-internal/src/analyzer/types.ts @@ -1716,6 +1716,12 @@ export interface TypeVarDetails { export type ParamSpecAccess = 'args' | 'kwargs'; +export const enum TypeVarScopeType { + Class, + Function, + TypeAlias, +} + export interface TypeVarType extends TypeBase { category: TypeCategory.TypeVar; details: TypeVarDetails; @@ -1728,6 +1734,9 @@ export interface TypeVarType extends TypeBase { // so it should be used only for error messages. scopeName?: string | undefined; + // If the TypeVar is bound to a scope, this is the scope type. + scopeType?: TypeVarScopeType; + // String formatted as .. nameWithScope?: string | undefined; @@ -1779,11 +1788,17 @@ export namespace TypeVarType { return newInstance; } - export function cloneForScopeId(type: TypeVarType, scopeId: string, scopeName: string) { + export function cloneForScopeId( + type: TypeVarType, + scopeId: string, + scopeName: string, + scopeType: TypeVarScopeType + ) { const newInstance: TypeVarType = { ...type }; newInstance.nameWithScope = makeNameWithScope(type.details.name, scopeId); newInstance.scopeId = scopeId; newInstance.scopeName = scopeName; + newInstance.scopeType = scopeType; return newInstance; }