Fixed a bug that resulted in a false positive when an expression of type type[Self] was used as the base type for a member access expression that was then used to call an instance method on that class. This addresses #5530. (#5532)

Co-authored-by: Eric Traut <erictr@microsoft.com>
This commit is contained in:
Eric Traut 2023-07-18 13:20:17 -07:00 committed by GitHub
parent 5be5852603
commit d7b0a85f1d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 36 additions and 2 deletions

View File

@ -5602,7 +5602,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
type: ClassType.isClassProperty(lookupClass)
? baseTypeClass
: isAccessedThroughObject
? bindToType || ClassType.cloneAsInstance(baseTypeClass)
? bindToType ?? ClassType.cloneAsInstance(baseTypeClass)
: NoneType.createInstance(),
},
},
@ -5801,6 +5801,20 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
// If this function is an instance member (e.g. a lambda that was
// assigned to an instance variable), don't perform any binding.
if (!isAccessedThroughObject || (memberInfo && !memberInfo.isInstanceMember)) {
let effectiveBindToType = bindToType;
if (bindToType && !isInstantiableMetaclass(baseTypeClass)) {
// If bindToType is an instantiable class or TypeVar but we're targeting
// an instance method (in a non-metaclass), we need to convert
// the bindToType to an instance.
const targetMethod = isFunction(concreteSubtype)
? concreteSubtype
: concreteSubtype.overloads[0];
if (FunctionType.isInstanceMethod(targetMethod) && !TypeBase.isInstance(bindToType)) {
effectiveBindToType = convertToInstance(bindToType) as ClassType | TypeVarType;
}
}
return bindFunctionToClassOrObject(
isAccessedThroughObject ? ClassType.cloneAsInstance(baseTypeClass) : baseTypeClass,
concreteSubtype,
@ -5808,7 +5822,7 @@ export function createTypeEvaluator(importLookup: ImportLookup, evaluatorOptions
errorNode,
/* recursionCount */ undefined,
treatConstructorAsClassMember,
bindToType
effectiveBindToType
);
}
}

View File

@ -0,0 +1,15 @@
# This sample tests the case where a `type[T]` or `type[Self]` typevar is
# used as the base for a member access but is then used to call an
# instance method on the resulting class.
from contextlib import contextmanager
class A:
@classmethod
def method1(cls) -> None:
cls.method2
@contextmanager
def method2(self):
yield

View File

@ -525,6 +525,11 @@ test('MemberAccess21', () => {
TestUtils.validateResults(analysisResults, 1);
});
test('MemberAccess22', () => {
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['memberAccess22.py']);
TestUtils.validateResults(analysisResults, 0);
});
test('DataClassNamedTuple1', () => {
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['dataclassNamedTuple1.py']);