Added accessor method for class symbol table. This is in preparation for a bug fix for #7516.

This commit is contained in:
Eric Traut 2024-04-05 21:52:53 -07:00
parent 6d1a5fd9f7
commit 39dfca8acd
17 changed files with 72 additions and 60 deletions

View File

@ -4805,7 +4805,7 @@ export class Checker extends ParseTreeWalker {
// Validates that any overridden member variables are not marked
// as Final in parent classes.
private _validateFinalMemberOverrides(classType: ClassType) {
classType.details.fields.forEach((localSymbol, name) => {
ClassType.getSymbolTable(classType).forEach((localSymbol, name) => {
const parentSymbol = lookUpClassMember(classType, name, MemberAccessFlags.SkipOriginalClass);
if (parentSymbol && isInstantiableClass(parentSymbol.classType) && !SymbolNameUtils.isPrivateName(name)) {
// Did the parent class explicitly declare the variable as final?
@ -4884,7 +4884,7 @@ export class Checker extends ParseTreeWalker {
}
}
classType.details.fields.forEach((symbol, name) => {
ClassType.getSymbolTable(classType).forEach((symbol, name) => {
// Enum members don't have type annotations.
if (symbol.getTypedDeclarations().length > 0) {
return;
@ -4996,7 +4996,7 @@ export class Checker extends ParseTreeWalker {
const initOnlySymbolMap = new Map<string, Symbol>();
ClassType.getReverseMro(classType).forEach((mroClass) => {
if (isClass(mroClass) && ClassType.isDataClass(mroClass)) {
mroClass.details.fields.forEach((symbol, name) => {
ClassType.getSymbolTable(mroClass).forEach((symbol, name) => {
if (symbol.isInitVar()) {
initOnlySymbolMap.set(name, symbol);
}
@ -5158,7 +5158,7 @@ export class Checker extends ParseTreeWalker {
getProtocolSymbolsRecursive(classType, abstractSymbols, ClassTypeFlags.SupportsAbstractMethods);
}
classType.details.fields.forEach((localSymbol, name) => {
ClassType.getSymbolTable(classType).forEach((localSymbol, name) => {
abstractSymbols.delete(name);
// This applies only to instance members.
@ -5377,7 +5377,7 @@ export class Checker extends ParseTreeWalker {
return;
}
classType.details.fields.forEach((symbol, name) => {
ClassType.getSymbolTable(classType).forEach((symbol, name) => {
const decls = symbol.getDeclarations();
const isDefinedBySlots = decls.some(
(decl) => decl.type === DeclarationType.Variable && decl.isDefinedBySlots
@ -5759,7 +5759,7 @@ export class Checker extends ParseTreeWalker {
let overrideType = this._evaluator.getEffectiveTypeOfSymbol(overrideSymbol);
overrideType = partiallySpecializeType(overrideType, overrideClassAndSymbol.classType);
const childOverrideSymbol = childClassType.details.fields.get(memberName);
const childOverrideSymbol = ClassType.getSymbolTable(childClassType).get(memberName);
const childOverrideType = childOverrideSymbol
? this._evaluator.getEffectiveTypeOfSymbol(childOverrideSymbol)
: undefined;
@ -5943,7 +5943,7 @@ export class Checker extends ParseTreeWalker {
// are decorated. For example, if the first overload is not marked @final
// but subsequent ones are, an error should be reported.
private _validateOverloadDecoratorConsistency(classType: ClassType) {
classType.details.fields.forEach((symbol, name) => {
ClassType.getSymbolTable(classType).forEach((symbol, name) => {
const primaryDecl = getLastTypedDeclaredForSymbol(symbol);
if (!primaryDecl || primaryDecl.type !== DeclarationType.Function) {
@ -6122,7 +6122,7 @@ export class Checker extends ParseTreeWalker {
// types as the original method. Also marks the class as abstract if one
// or more abstract methods are not overridden.
private _validateBaseClassOverrides(classType: ClassType) {
classType.details.fields.forEach((symbol, name) => {
ClassType.getSymbolTable(classType).forEach((symbol, name) => {
// Private symbols do not need to match in type since their
// names are mangled, and subclasses can't access the value in
// the parent class.

View File

@ -131,7 +131,7 @@ function applyPartialTransform(
// Create a new copy of the functools.partial class that overrides the __call__ method.
const newPartialClass = ClassType.cloneForSymbolTableUpdate(result.returnType);
newPartialClass.details.fields.set(
ClassType.getSymbolTable(newPartialClass).set(
'__call__',
Symbol.createWithType(SymbolFlags.ClassMember, transformResult.returnType)
);
@ -196,7 +196,7 @@ function applyPartialTransform(
);
}
newPartialClass.details.fields.set(
ClassType.getSymbolTable(newPartialClass).set(
'__call__',
Symbol.createWithType(SymbolFlags.ClassMember, synthesizedCallType)
);

View File

@ -129,7 +129,7 @@ export function synthesizeDataClassMethods(
const localEntryTypeEvaluator: { entry: DataClassEntry; evaluator: EntryTypeEvaluator }[] = [];
let sawKeywordOnlySeparator = false;
classType.details.fields.forEach((symbol, name) => {
ClassType.getSymbolTable(classType).forEach((symbol, name) => {
if (symbol.isIgnoredForProtocolMatch()) {
return;
}
@ -322,7 +322,7 @@ export function synthesizeDataClassMethods(
// Don't include class vars. PEP 557 indicates that they shouldn't
// be considered data class entries.
const variableSymbol = classType.details.fields.get(variableName);
const variableSymbol = ClassType.getSymbolTable(classType).get(variableName);
if (variableSymbol?.isClassVar() && !variableSymbol?.isFinalVarInClassBody()) {
// If an ancestor class declared an instance variable but this dataclass
@ -462,7 +462,7 @@ export function synthesizeDataClassMethods(
entryEvaluator.entry.type = entryEvaluator.evaluator();
});
const symbolTable = classType.details.fields;
const symbolTable = ClassType.getSymbolTable(classType);
const keywordOnlyParams: FunctionParameter[] = [];
if (!skipSynthesizeInit && !hasExistingInitMethod) {
@ -868,7 +868,7 @@ function getDescriptorForConverterField(
descriptorClass.details.baseClasses.push(evaluator.getBuiltInType(dataclassNode, 'object'));
computeMroLinearization(descriptorClass);
const fields = descriptorClass.details.fields;
const fields = ClassType.getSymbolTable(descriptorClass);
const selfType = synthesizeTypeVarForSelfCls(descriptorClass, /* isClsParam */ false);
const setFunction = FunctionType.createSynthesizedInstance('__set__');

View File

@ -57,7 +57,7 @@ export function isEnumClassWithMembers(evaluator: TypeEvaluator, classType: Clas
// Determine whether the enum class defines a member.
let definesValue = false;
classType.details.fields.forEach((symbol) => {
ClassType.getSymbolTable(classType).forEach((symbol) => {
const symbolType = evaluator.getEffectiveTypeOfSymbol(symbol);
if (isClassInstance(symbolType) && ClassType.isSameGenericClass(symbolType, classType)) {
definesValue = true;
@ -105,7 +105,7 @@ export function createEnumType(
classType.details.baseClasses.push(enumClass);
computeMroLinearization(classType);
const classFields = classType.details.fields;
const classFields = ClassType.getSymbolTable(classType);
classFields.set(
'__class__',
Symbol.createWithType(SymbolFlags.ClassMember | SymbolFlags.IgnoredForProtocolMatch, classType)
@ -362,7 +362,7 @@ export function transformTypeForPossibleEnumClass(
}
// The spec excludes descriptors.
if (isClassInstance(valueType) && valueType.details.fields.get('__get__')) {
if (isClassInstance(valueType) && ClassType.getSymbolTable(valueType).get('__get__')) {
return undefined;
}

View File

@ -128,7 +128,10 @@ function applyTotalOrderingTransform(
FunctionType.addParameter(methodToAdd, objParam);
methodToAdd.details.declaredReturnType = boolType;
classType.details.fields.set(methodName, Symbol.createWithType(SymbolFlags.ClassMember, methodToAdd));
ClassType.getSymbolTable(classType).set(
methodName,
Symbol.createWithType(SymbolFlags.ClassMember, methodToAdd)
);
});
return result;

View File

@ -129,7 +129,7 @@ export function createNamedTupleType(
classType.details.baseClasses.push(namedTupleType);
classType.details.typeVarScopeId = ParseTreeUtils.getScopeIdForNode(errorNode);
const classFields = classType.details.fields;
const classFields = ClassType.getSymbolTable(classType);
classFields.set(
'__class__',
Symbol.createWithType(SymbolFlags.ClassMember | SymbolFlags.IgnoredForProtocolMatch, classType)

View File

@ -331,7 +331,7 @@ export class PackageTypeVerifier {
alternateSymbolNames,
module,
fullName,
symbolType.details.fields,
ClassType.getSymbolTable(symbolType),
ScopeType.Class
);
}
@ -1149,7 +1149,7 @@ export class PackageTypeVerifier {
const symbolTableTypeKnownStatus = this._getTypeKnownStatusForSymbolTable(
report,
type.details.fullName,
type.details.fields,
ClassType.getSymbolTable(type),
ScopeType.Class,
publicSymbols,
(name: string, symbol: Symbol) => {
@ -1159,7 +1159,7 @@ export class PackageTypeVerifier {
if (!symbol.hasTypedDeclarations()) {
for (const mroClass of type.details.mro.slice(1)) {
if (isClass(mroClass)) {
const overrideSymbol = mroClass.details.fields.get(name);
const overrideSymbol = ClassType.getSymbolTable(mroClass).get(name);
if (overrideSymbol && overrideSymbol.hasTypedDeclarations()) {
return overrideSymbol;
}

View File

@ -78,8 +78,8 @@ export function createProperty(
computeMroLinearization(propertyClass);
// Clone the symbol table of the old class type.
const fields = propertyClass.details.fields;
decoratorType.details.fields.forEach((symbol, name) => {
const fields = ClassType.getSymbolTable(propertyClass);
ClassType.getSymbolTable(decoratorType).forEach((symbol, name) => {
const ignoredMethods = ['__get__', '__set__', '__delete__'];
if (!symbol.isIgnoredForProtocolMatch()) {
@ -184,8 +184,8 @@ export function clonePropertyWithSetter(
const propertyObject = ClassType.cloneAsInstance(propertyClass);
// Clone the symbol table of the old class type.
const fields = propertyClass.details.fields;
classType.details.fields.forEach((symbol, name) => {
const fields = ClassType.getSymbolTable(propertyClass);
ClassType.getSymbolTable(classType).forEach((symbol, name) => {
if (!symbol.isIgnoredForProtocolMatch()) {
fields.set(name, symbol);
}
@ -243,8 +243,8 @@ export function clonePropertyWithDeleter(
propertyClass.isAsymmetricDescriptor = classType.isAsymmetricDescriptor ?? false;
// Clone the symbol table of the old class type.
const fields = propertyClass.details.fields;
classType.details.fields.forEach((symbol, name) => {
const fields = ClassType.getSymbolTable(propertyClass);
ClassType.getSymbolTable(classType).forEach((symbol, name) => {
if (!symbol.isIgnoredForProtocolMatch()) {
fields.set(name, symbol);
}
@ -269,7 +269,7 @@ export function clonePropertyWithDeleter(
}
function addGetMethodToPropertySymbolTable(evaluator: TypeEvaluator, propertyObject: ClassType, fget: FunctionType) {
const fields = propertyObject.details.fields;
const fields = ClassType.getSymbolTable(propertyObject);
// The first overload is for accesses through a class object (where
// the instance argument is None).
@ -348,7 +348,7 @@ function addGetMethodToPropertySymbolTable(evaluator: TypeEvaluator, propertyObj
}
function addSetMethodToPropertySymbolTable(evaluator: TypeEvaluator, propertyObject: ClassType, fset: FunctionType) {
const fields = propertyObject.details.fields;
const fields = ClassType.getSymbolTable(propertyObject);
const setFunction = FunctionType.createSynthesizedInstance('__set__');
FunctionType.addParameter(setFunction, {
@ -397,7 +397,7 @@ function addSetMethodToPropertySymbolTable(evaluator: TypeEvaluator, propertyObj
}
function addDelMethodToPropertySymbolTable(evaluator: TypeEvaluator, propertyObject: ClassType, fdel: FunctionType) {
const fields = propertyObject.details.fields;
const fields = ClassType.getSymbolTable(propertyObject);
const delFunction = FunctionType.createSynthesizedInstance('__delete__');
FunctionType.addParameter(delFunction, {
@ -447,7 +447,7 @@ function updateGetSetDelMethodForClonedProperty(evaluator: TypeEvaluator, proper
}
function addDecoratorMethodsToPropertySymbolTable(propertyObject: ClassType) {
const fields = propertyObject.details.fields;
const fields = ClassType.getSymbolTable(propertyObject);
// Fill in the getter, setter and deleter methods.
['getter', 'setter', 'deleter'].forEach((accessorName) => {

View File

@ -180,7 +180,7 @@ export function isMethodOnlyProtocol(classType: ClassType): boolean {
}
}
for (const [, symbol] of classType.details.fields) {
for (const [, symbol] of ClassType.getSymbolTable(classType)) {
if (symbol.isIgnoredForProtocolMatch()) {
continue;
}
@ -209,7 +209,7 @@ export function isProtocolUnsafeOverlap(evaluator: TypeEvaluator, protocol: Clas
return;
}
mroClass.details.fields.forEach((destSymbol, name) => {
ClassType.getSymbolTable(mroClass).forEach((destSymbol, name) => {
if (!isUnsafeOverlap || !destSymbol.isClassMember() || destSymbol.isIgnoredForProtocolMatch()) {
return;
}
@ -354,7 +354,7 @@ function assignClassToProtocolInternal(
return;
}
mroClass.details.fields.forEach((destSymbol, name) => {
ClassType.getSymbolTable(mroClass).forEach((destSymbol, name) => {
// If we've already determined that the types are not consistent and the caller
// hasn't requested detailed diagnostic output, we can shortcut the remainder.
if (!typesAreConsistent && !diag) {

View File

@ -328,7 +328,7 @@ function _getPropertyDocStringInherited(
continue;
}
const symbol = mroClass.details.fields.get(fieldName);
const symbol = ClassType.getSymbolTable(mroClass).get(fieldName);
// Get both the setter and getter declarations
const decls = symbol?.getDeclarations();
if (decls) {

View File

@ -3417,7 +3417,9 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
// Assignments to instance or class variables through "self" or "cls" is not
// allowed for protocol classes unless it is also declared within the class.
if (ClassType.isProtocolClass(classTypeResults.classType)) {
const memberSymbol = classTypeResults.classType.details.fields.get(target.memberName.value);
const memberSymbol = ClassType.getSymbolTable(classTypeResults.classType).get(
target.memberName.value
);
if (memberSymbol) {
const classLevelDecls = memberSymbol.getDeclarations().filter((decl) => {
return !ParseTreeUtils.getEnclosingFunction(decl.node);
@ -3479,7 +3481,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
isInstanceMember ? MemberAccessFlags.Default : MemberAccessFlags.SkipInstanceMembers
);
const memberFields = classTypeInfo.classType.details.fields;
const memberFields = ClassType.getSymbolTable(classTypeInfo.classType);
if (memberInfo) {
// Are we accessing an existing member on this class, or is
// it a member on a parent class?
@ -9457,7 +9459,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
function getAbstractSymbolInfo(classType: ClassType, symbolName: string): AbstractSymbol | undefined {
const isProtocolClass = ClassType.isProtocolClass(classType);
const symbol = classType.details.fields.get(symbolName);
const symbol = ClassType.getSymbolTable(classType).get(symbolName);
if (!symbol) {
return undefined;
}
@ -12857,7 +12859,10 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
hasDeclaredType: true,
});
initType.details.declaredReturnType = getNoneType();
classType.details.fields.set('__init__', Symbol.createWithType(SymbolFlags.ClassMember, initType));
ClassType.getSymbolTable(classType).set(
'__init__',
Symbol.createWithType(SymbolFlags.ClassMember, initType)
);
// Synthesize a trivial __new__ method.
const newType = FunctionType.createSynthesizedInstance('__new__', FunctionTypeFlags.ConstructorMethod);
@ -12870,7 +12875,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
FunctionType.addDefaultParameters(newType);
newType.details.declaredReturnType = ClassType.cloneAsInstance(classType);
newType.details.constructorTypeVarScopeId = classType.details.typeVarScopeId;
classType.details.fields.set('__new__', Symbol.createWithType(SymbolFlags.ClassMember, newType));
ClassType.getSymbolTable(classType).set('__new__', Symbol.createWithType(SymbolFlags.ClassMember, newType));
}
return classType;
@ -22298,7 +22303,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
// as though all TypeParameters are invariant.
assignClassToSelfStack.push({ class: destType, assumedVariance });
destType.details.fields.forEach((symbol, name) => {
ClassType.getSymbolTable(destType).forEach((symbol, name) => {
if (!isAssignable || symbol.isIgnoredForProtocolMatch()) {
return;
}
@ -24543,12 +24548,12 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
// a normal function wouldn't be compatible with.
for (const mroClass of objType.details.mro) {
if (isClass(mroClass) && ClassType.isProtocolClass(mroClass)) {
for (const field of mroClass.details.fields) {
for (const field of ClassType.getSymbolTable(mroClass)) {
if (field[0] !== '__call__' && !field[1].isIgnoredForProtocolMatch()) {
let fieldIsPartOfFunction = false;
if (functionObj && isClass(functionObj)) {
if (functionObj.details.fields.has(field[0])) {
if (ClassType.getSymbolTable(functionObj).has(field[0])) {
fieldIsPartOfFunction = true;
}
}
@ -26343,7 +26348,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
// See if this class is introducing a new abstract symbol that has not been
// introduced previously or if it is overriding an abstract symbol with
// a non-abstract one.
mroClass.details.fields.forEach((symbol, symbolName) => {
ClassType.getSymbolTable(mroClass).forEach((symbol, symbolName) => {
const abstractSymbolInfo = getAbstractSymbolInfo(mroClass, symbolName);
if (abstractSymbolInfo) {

View File

@ -2509,7 +2509,7 @@ export function enumerateLiteralsForType(evaluator: TypeEvaluator, type: ClassTy
// Enumerate all of the values in this enumeration.
const enumList: ClassType[] = [];
const fields = type.details.fields;
const fields = ClassType.getSymbolTable(type);
fields.forEach((symbol) => {
if (!symbol.isIgnoredForProtocolMatch()) {
const symbolType = evaluator.getEffectiveTypeOfSymbol(symbol);
@ -2601,7 +2601,7 @@ function narrowTypeForCallable(
FunctionType.addParameter(callMethod, selfParam);
FunctionType.addDefaultParameters(callMethod);
callMethod.details.declaredReturnType = UnknownType.create();
newClassType.details.fields.set(
ClassType.getSymbolTable(newClassType).set(
'__call__',
Symbol.createWithType(SymbolFlags.ClassMember, callMethod)
);

View File

@ -1330,11 +1330,11 @@ export function isMaybeDescriptorInstance(type: Type, requireSetter = false): bo
return false;
}
if (!type.details.fields.has('__get__')) {
if (!ClassType.getSymbolTable(type).has('__get__')) {
return false;
}
if (requireSetter && !type.details.fields.has('__set__')) {
if (requireSetter && !ClassType.getSymbolTable(type).has('__set__')) {
return false;
}
@ -1638,7 +1638,7 @@ export function getProtocolSymbolsRecursive(
}
});
classType.details.fields.forEach((symbol, name) => {
ClassType.getSymbolTable(classType).forEach((symbol, name) => {
if (!symbol.isIgnoredForProtocolMatch()) {
symbolMap.set(name, {
symbol,
@ -1795,7 +1795,7 @@ export function* getClassMemberIterator(
continue;
}
const memberFields = specializedMroClass.details.fields;
const memberFields = ClassType.getSymbolTable(specializedMroClass);
// Look at instance members first if requested.
if ((flags & MemberAccessFlags.SkipInstanceMembers) === 0) {
@ -1935,7 +1935,7 @@ export function getClassFieldsRecursive(classType: ClassType): Map<string, Class
const specializedMroClass = partiallySpecializeType(mroClass, classType);
if (isClass(specializedMroClass)) {
specializedMroClass.details.fields.forEach((symbol, name) => {
ClassType.getSymbolTable(specializedMroClass).forEach((symbol, name) => {
if (!symbol.isIgnoredForProtocolMatch() && symbol.hasTypedDeclarations()) {
memberMap.set(name, {
classType: specializedMroClass,
@ -2598,7 +2598,7 @@ export function getMembersForClass(classType: ClassType, symbolTable: SymbolTabl
if (isInstantiableClass(mroClass)) {
// Add any new member variables from this class.
const isClassTypedDict = ClassType.isTypedDictClass(mroClass);
mroClass.details.fields.forEach((symbol, name) => {
ClassType.getSymbolTable(mroClass).forEach((symbol, name) => {
if (symbol.isClassMember() || (includeInstanceVars && symbol.isInstanceMember())) {
if (!isClassTypedDict || !isTypedDictMemberAccessedThroughIndex(symbol)) {
if (!symbol.isInitVar()) {
@ -2624,7 +2624,7 @@ export function getMembersForClass(classType: ClassType, symbolTable: SymbolTabl
if (metaclass && isInstantiableClass(metaclass)) {
for (const mroClass of metaclass.details.mro) {
if (isInstantiableClass(mroClass)) {
mroClass.details.fields.forEach((symbol, name) => {
ClassType.getSymbolTable(mroClass).forEach((symbol, name) => {
const existingSymbol = symbolTable.get(name);
if (!existingSymbol) {

View File

@ -113,7 +113,7 @@ export function createTypedDictType(
classType.details.baseClasses.push(typedDictClass);
computeMroLinearization(classType);
const classFields = classType.details.fields;
const classFields = ClassType.getSymbolTable(classType);
classFields.set(
'__class__',
Symbol.createWithType(SymbolFlags.ClassMember | SymbolFlags.IgnoredForProtocolMatch, classType)
@ -256,7 +256,7 @@ export function createTypedDictTypeInlined(
classType.details.baseClasses.push(typedDictClass);
computeMroLinearization(classType);
getTypedDictFieldsFromDictSyntax(evaluator, dictNode, classType.details.fields, /* isInline */ true);
getTypedDictFieldsFromDictSyntax(evaluator, dictNode, ClassType.getSymbolTable(classType), /* isInline */ true);
synthesizeTypedDictClassMethods(evaluator, dictNode, classType);
return classType;
@ -361,7 +361,7 @@ export function synthesizeTypedDictClassMethods(
});
}
const symbolTable = classType.details.fields;
const symbolTable = ClassType.getSymbolTable(classType);
const initType = OverloadedFunctionType.create([initOverride1, initOverride2]);
symbolTable.set('__init__', Symbol.createWithType(SymbolFlags.ClassMember, initType));
symbolTable.set('__new__', Symbol.createWithType(SymbolFlags.ClassMember, newType));
@ -993,7 +993,7 @@ function getTypedDictMembersForClassRecursive(
const typeVarContext = buildTypeVarContextFromSpecializedClass(classType);
// Add any new typed dict entries from this class.
classType.details.fields.forEach((symbol, name) => {
ClassType.getSymbolTable(classType).forEach((symbol, name) => {
if (!symbol.isIgnoredForProtocolMatch()) {
// Only variables (not functions, classes, etc.) are considered.
const lastDecl = getLastTypedDeclaredForSymbol(symbol);

View File

@ -1171,6 +1171,10 @@ export namespace ClassType {
return classType.details.mro.some((baseClass) => isAnyOrUnknown(baseClass));
}
export function getSymbolTable(classType: ClassType) {
return classType.details.fields;
}
// Similar to isPartiallyEvaluated except that it also looks at all of the
// classes in the MRO list for this class to see if any of them are still
// partially evaluated.

View File

@ -2908,7 +2908,7 @@ export class CompletionProvider {
classType.classType.details.mro.forEach((baseClass, index) => {
if (isInstantiableClass(baseClass)) {
this._addSymbolsForSymbolTable(
baseClass.details.fields,
ClassType.getSymbolTable(baseClass),
(symbol) => {
if (!symbol.isClassMember()) {
return false;

View File

@ -431,7 +431,7 @@ export class HoverProvider {
const text = '(key) ' + node.value + ': ' + this._evaluator.printType(entry.valueType);
this._addResultsPart(parts, text, /* python */ true);
const declarations = subtype.details.fields.get(node.value)?.getDeclarations();
const declarations = ClassType.getSymbolTable(subtype).get(node.value)?.getDeclarations();
if (declarations !== undefined && declarations?.length !== 0) {
// As we are just interested in the docString we don't have to worry about
// anything other than the first declaration. There also shouldn't be more