mirror of
https://github.com/microsoft/pyright.git
synced 2024-09-17 11:17:17 +03:00
Fixed false positive error caused by inappropriate method binding for instance methods.
This commit is contained in:
parent
fbb0d521ee
commit
bf8b5511d3
@ -5009,7 +5009,7 @@ export function createTypeEvaluator(
|
|||||||
memberInfo,
|
memberInfo,
|
||||||
classType,
|
classType,
|
||||||
bindToType,
|
bindToType,
|
||||||
/* isAccessedThroughObject */ false,
|
/* isAccessedThroughObject */ !!bindToType,
|
||||||
flags,
|
flags,
|
||||||
errorNode,
|
errorNode,
|
||||||
memberName,
|
memberName,
|
||||||
@ -5217,7 +5217,7 @@ export function createTypeEvaluator(
|
|||||||
} else if (isFunction(subtype) || isOverloadedFunction(subtype)) {
|
} else if (isFunction(subtype) || isOverloadedFunction(subtype)) {
|
||||||
// If this function is an instance member (e.g. a lambda that was
|
// If this function is an instance member (e.g. a lambda that was
|
||||||
// assigned to an instance variable), don't perform any binding.
|
// assigned to an instance variable), don't perform any binding.
|
||||||
if (!isAccessedThroughObject || !memberInfo?.isInstanceMember) {
|
if (!isAccessedThroughObject || (memberInfo && !memberInfo.isInstanceMember)) {
|
||||||
return bindFunctionToClassOrObject(
|
return bindFunctionToClassOrObject(
|
||||||
isAccessedThroughObject ? ClassType.cloneAsInstance(baseTypeClass) : baseTypeClass,
|
isAccessedThroughObject ? ClassType.cloneAsInstance(baseTypeClass) : baseTypeClass,
|
||||||
subtype,
|
subtype,
|
||||||
@ -11783,7 +11783,7 @@ export function createTypeEvaluator(
|
|||||||
function createCallableType(typeArgs: TypeResult[] | undefined, errorNode: ParseNode): FunctionType {
|
function createCallableType(typeArgs: TypeResult[] | undefined, errorNode: ParseNode): FunctionType {
|
||||||
// Create a new function that is marked as "static" so there is later
|
// 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.
|
// 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);
|
TypeBase.setNonCallable(functionType);
|
||||||
functionType.details.declaredReturnType = UnknownType.create();
|
functionType.details.declaredReturnType = UnknownType.create();
|
||||||
|
|
||||||
@ -22807,7 +22807,7 @@ export function createTypeEvaluator(
|
|||||||
'__new__',
|
'__new__',
|
||||||
'',
|
'',
|
||||||
'',
|
'',
|
||||||
FunctionTypeFlags.StaticMethod | FunctionTypeFlags.ConstructorMethod | FunctionTypeFlags.SynthesizedMethod
|
FunctionTypeFlags.ConstructorMethod | FunctionTypeFlags.SynthesizedMethod
|
||||||
);
|
);
|
||||||
constructorFunction.details.declaredReturnType = ClassType.cloneAsInstance(classType);
|
constructorFunction.details.declaredReturnType = ClassType.cloneAsInstance(classType);
|
||||||
FunctionType.addDefaultParameters(constructorFunction);
|
FunctionType.addDefaultParameters(constructorFunction);
|
||||||
|
@ -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)
|
@ -8,7 +8,7 @@ class ClassA:
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
return
|
return
|
||||||
|
|
||||||
def __getattr__(self) -> Callable[[str], str]:
|
def __getattr__(self, key: str) -> Callable[[str], str]:
|
||||||
return lambda a: a
|
return lambda a: a
|
||||||
|
|
||||||
|
|
||||||
|
@ -375,6 +375,11 @@ test('MemberAccess10', () => {
|
|||||||
TestUtils.validateResults(analysisResults, 2);
|
TestUtils.validateResults(analysisResults, 2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('MemberAccess11', () => {
|
||||||
|
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['memberAccess11.py']);
|
||||||
|
TestUtils.validateResults(analysisResults, 0);
|
||||||
|
});
|
||||||
|
|
||||||
test('DataClass1', () => {
|
test('DataClass1', () => {
|
||||||
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['dataclass1.py']);
|
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['dataclass1.py']);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user