mirror of
https://github.com/microsoft/pyright.git
synced 2024-10-26 02:38:31 +03:00
Fixed recent regression that affected unannotated __call__
methods in a metaclass. This change aligns pyright's behavior to the typing spec. It addresses #7717. (#7746)
This commit is contained in:
parent
9ca7cbd48c
commit
419a8f41c1
@ -674,28 +674,31 @@ function validateMetaclassCall(
|
||||
): CallResult | undefined {
|
||||
const metaclassCallMethodInfo = getBoundCallMethod(evaluator, errorNode, type);
|
||||
|
||||
if (metaclassCallMethodInfo) {
|
||||
const callResult = evaluator.validateCallArguments(
|
||||
errorNode,
|
||||
argList,
|
||||
metaclassCallMethodInfo,
|
||||
/* typeVarContext */ undefined,
|
||||
skipUnknownArgCheck,
|
||||
inferenceContext
|
||||
);
|
||||
|
||||
if (!callResult.returnType || isUnknown(callResult.returnType)) {
|
||||
// The return result isn't known. We'll assume in this case that
|
||||
// the metaclass __call__ method allocated a new instance of the
|
||||
// requested class.
|
||||
const typeVarContext = new TypeVarContext(getTypeVarScopeId(type));
|
||||
callResult.returnType = applyExpectedTypeForConstructor(evaluator, type, inferenceContext, typeVarContext);
|
||||
}
|
||||
|
||||
return callResult;
|
||||
if (!metaclassCallMethodInfo) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
const callResult = evaluator.validateCallArguments(
|
||||
errorNode,
|
||||
argList,
|
||||
metaclassCallMethodInfo,
|
||||
/* typeVarContext */ undefined,
|
||||
skipUnknownArgCheck,
|
||||
inferenceContext
|
||||
);
|
||||
|
||||
// If the return type is unannotated, don't use the inferred return type.
|
||||
const callType = metaclassCallMethodInfo.type;
|
||||
if (isFunction(callType) && !callType.details.declaredReturnType) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// If the return type is unknown, ignore it.
|
||||
if (callResult.returnType && isUnknown(callResult.returnType)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return callResult;
|
||||
}
|
||||
|
||||
function applyExpectedSubtypeForConstructor(
|
||||
|
@ -5,6 +5,9 @@
|
||||
# pyright: reportIncompatibleMethodOverride=false
|
||||
|
||||
|
||||
from typing import Any, Self
|
||||
|
||||
|
||||
class MetaClass1(type):
|
||||
def __call__(cls, **kwargs):
|
||||
return object.__new__(**kwargs)
|
||||
@ -33,7 +36,7 @@ reveal_type(v2, expected_text="NoReturn")
|
||||
|
||||
|
||||
class MetaClass3(type):
|
||||
def __call__(cls, *args, **kwargs):
|
||||
def __call__(cls, *args, **kwargs) -> Any:
|
||||
return super().__call__(*args, **kwargs)
|
||||
|
||||
|
||||
@ -44,3 +47,17 @@ class Class3(metaclass=MetaClass3):
|
||||
|
||||
v3 = Class3()
|
||||
reveal_type(v3, expected_text="Any")
|
||||
|
||||
|
||||
class MetaClass4(type):
|
||||
def __call__(cls, *args, **kwargs):
|
||||
return super().__call__(*args, **kwargs)
|
||||
|
||||
|
||||
class Class4(metaclass=MetaClass4):
|
||||
def __new__(cls, *args, **kwargs) -> Self:
|
||||
return super().__new__(cls, *args, **kwargs)
|
||||
|
||||
|
||||
v4 = Class4()
|
||||
reveal_type(v4, expected_text="Class4")
|
||||
|
Loading…
Reference in New Issue
Block a user