diff --git a/packages/pyright-internal/src/analyzer/typeEvaluator.ts b/packages/pyright-internal/src/analyzer/typeEvaluator.ts index 903c77f50..ef42996f6 100644 --- a/packages/pyright-internal/src/analyzer/typeEvaluator.ts +++ b/packages/pyright-internal/src/analyzer/typeEvaluator.ts @@ -5009,7 +5009,7 @@ export function createTypeEvaluator( memberInfo, classType, bindToType, - /* isAccessedThroughObject */ false, + /* isAccessedThroughObject */ !!bindToType, flags, errorNode, memberName, @@ -5217,7 +5217,7 @@ export function createTypeEvaluator( } else if (isFunction(subtype) || isOverloadedFunction(subtype)) { // 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?.isInstanceMember) { + if (!isAccessedThroughObject || (memberInfo && !memberInfo.isInstanceMember)) { return bindFunctionToClassOrObject( isAccessedThroughObject ? ClassType.cloneAsInstance(baseTypeClass) : baseTypeClass, subtype, @@ -11783,7 +11783,7 @@ export function createTypeEvaluator( function createCallableType(typeArgs: TypeResult[] | undefined, errorNode: ParseNode): FunctionType { // Create a new function that is marked as "static" so there is later // no attempt to bind it as though it's an instance or class method. - const functionType = FunctionType.createInstantiable('', '', '', FunctionTypeFlags.StaticMethod); + const functionType = FunctionType.createInstantiable('', '', '', FunctionTypeFlags.None); TypeBase.setNonCallable(functionType); functionType.details.declaredReturnType = UnknownType.create(); @@ -22807,7 +22807,7 @@ export function createTypeEvaluator( '__new__', '', '', - FunctionTypeFlags.StaticMethod | FunctionTypeFlags.ConstructorMethod | FunctionTypeFlags.SynthesizedMethod + FunctionTypeFlags.ConstructorMethod | FunctionTypeFlags.SynthesizedMethod ); constructorFunction.details.declaredReturnType = ClassType.cloneAsInstance(classType); FunctionType.addDefaultParameters(constructorFunction); diff --git a/packages/pyright-internal/src/tests/samples/memberAccess11.py b/packages/pyright-internal/src/tests/samples/memberAccess11.py new file mode 100644 index 000000000..bbaa7cb7f --- /dev/null +++ b/packages/pyright-internal/src/tests/samples/memberAccess11.py @@ -0,0 +1,37 @@ +# This sample tests that methods are bound properly regardless of +# whether they are decorated. + +from typing import Callable + +UnboundMethodThatTakesIntAndReturnsStr = Callable[["MyClass", int], str] + + +def method_decorator( + method: UnboundMethodThatTakesIntAndReturnsStr, +) -> UnboundMethodThatTakesIntAndReturnsStr: + def wrapper(self: "MyClass", a: int) -> str: + return "wrapped " + method(self, a) + + return wrapper + + +class MyClass: + def __init__(self): + self.method4 = lambda x: x + + @method_decorator + def method1(self, a: int) -> str: + return "foo" + + def method2(self, a: int) -> str: + return "foo" + + method3 = method_decorator(method2) + + +mc = MyClass() + +mc.method1(1) +mc.method2(1) +mc.method3(1) +mc.method4(1) diff --git a/packages/pyright-internal/src/tests/samples/memberAccess7.py b/packages/pyright-internal/src/tests/samples/memberAccess7.py index feda52ed3..d09c1b738 100644 --- a/packages/pyright-internal/src/tests/samples/memberAccess7.py +++ b/packages/pyright-internal/src/tests/samples/memberAccess7.py @@ -8,7 +8,7 @@ class ClassA: def __init__(self): return - def __getattr__(self) -> Callable[[str], str]: + def __getattr__(self, key: str) -> Callable[[str], str]: return lambda a: a diff --git a/packages/pyright-internal/src/tests/typeEvaluator4.test.ts b/packages/pyright-internal/src/tests/typeEvaluator4.test.ts index 8348325f8..5fcebf357 100644 --- a/packages/pyright-internal/src/tests/typeEvaluator4.test.ts +++ b/packages/pyright-internal/src/tests/typeEvaluator4.test.ts @@ -375,6 +375,11 @@ test('MemberAccess10', () => { TestUtils.validateResults(analysisResults, 2); }); +test('MemberAccess11', () => { + const analysisResults = TestUtils.typeAnalyzeSampleFiles(['memberAccess11.py']); + TestUtils.validateResults(analysisResults, 0); +}); + test('DataClass1', () => { const analysisResults = TestUtils.typeAnalyzeSampleFiles(['dataclass1.py']);