From 9694c5b0e96508c9f6edd0493355b06377b348e5 Mon Sep 17 00:00:00 2001 From: Eric Traut Date: Tue, 10 Dec 2024 18:16:29 -0800 Subject: [PATCH] Fixed bug that leads to a false positive error when `--verifytypes` is used and a subclass overrides an attribute that is generic in the base class. This addresses #9448. --- .../src/analyzer/packageTypeVerifier.ts | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/packages/pyright-internal/src/analyzer/packageTypeVerifier.ts b/packages/pyright-internal/src/analyzer/packageTypeVerifier.ts index 03fd63df7d34..dd521c8ac39a 100644 --- a/packages/pyright-internal/src/analyzer/packageTypeVerifier.ts +++ b/packages/pyright-internal/src/analyzer/packageTypeVerifier.ts @@ -60,6 +60,8 @@ import { isDescriptorInstance, isEllipsisType, isPartlyUnknown, + partiallySpecializeType, + specializeForBaseClass, } from './typeUtils'; type PublicSymbolSet = Set; @@ -510,7 +512,7 @@ export class PackageTypeVerifier { symbolTable: SymbolTable, scopeType: ScopeType, publicSymbols: PublicSymbolSet, - overrideSymbolCallback?: (name: string, symbol: Symbol) => Symbol + overrideSymbolCallback?: (name: string, symbol: Symbol) => Type | undefined ): TypeKnownStatus { if (this._shouldIgnoreType(report, scopeName)) { return TypeKnownStatus.Known; @@ -544,11 +546,10 @@ export class PackageTypeVerifier { let childSymbolType: Type | undefined; if (overrideSymbolCallback) { - const baseTypeSymbol = overrideSymbolCallback(name, symbol); + const baseSymbolType = overrideSymbolCallback(name, symbol); - if (baseTypeSymbol !== symbol) { + if (baseSymbolType) { childSymbolType = symbolType; - baseSymbolType = this._program.getTypeOfSymbol(baseTypeSymbol); // If the inferred type is ambiguous or the declared base class type is // not the same type as the inferred type, mark it as ambiguous because @@ -1164,18 +1165,23 @@ export class PackageTypeVerifier { // If the symbol within this class is lacking a type declaration, // see if we can find a same-named symbol in a parent class with // a type declaration. - if (!symbol.hasTypedDeclarations()) { - for (const mroClass of type.shared.mro.slice(1)) { - if (isClass(mroClass)) { - const overrideSymbol = ClassType.getSymbolTable(mroClass).get(name); - if (overrideSymbol && overrideSymbol.hasTypedDeclarations()) { - return overrideSymbol; - } + if (symbol.hasTypedDeclarations()) { + return undefined; + } + + for (const mroClass of type.shared.mro.slice(1)) { + if (isClass(mroClass)) { + const overrideSymbol = ClassType.getSymbolTable(mroClass).get(name); + if (overrideSymbol && overrideSymbol.hasTypedDeclarations()) { + const baseSymbolType = this._program.getTypeOfSymbol(overrideSymbol); + const baseClassType = specializeForBaseClass(type, mroClass); + + return partiallySpecializeType(baseSymbolType, baseClassType, /* typeClass */ undefined); } } } - return symbol; + return undefined; } );