mirror of
https://github.com/microsoft/pyright.git
synced 2024-10-26 10:55:06 +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 {
|
): CallResult | undefined {
|
||||||
const metaclassCallMethodInfo = getBoundCallMethod(evaluator, errorNode, type);
|
const metaclassCallMethodInfo = getBoundCallMethod(evaluator, errorNode, type);
|
||||||
|
|
||||||
if (metaclassCallMethodInfo) {
|
if (!metaclassCallMethodInfo) {
|
||||||
const callResult = evaluator.validateCallArguments(
|
return undefined;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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(
|
function applyExpectedSubtypeForConstructor(
|
||||||
|
@ -5,6 +5,9 @@
|
|||||||
# pyright: reportIncompatibleMethodOverride=false
|
# pyright: reportIncompatibleMethodOverride=false
|
||||||
|
|
||||||
|
|
||||||
|
from typing import Any, Self
|
||||||
|
|
||||||
|
|
||||||
class MetaClass1(type):
|
class MetaClass1(type):
|
||||||
def __call__(cls, **kwargs):
|
def __call__(cls, **kwargs):
|
||||||
return object.__new__(**kwargs)
|
return object.__new__(**kwargs)
|
||||||
@ -33,7 +36,7 @@ reveal_type(v2, expected_text="NoReturn")
|
|||||||
|
|
||||||
|
|
||||||
class MetaClass3(type):
|
class MetaClass3(type):
|
||||||
def __call__(cls, *args, **kwargs):
|
def __call__(cls, *args, **kwargs) -> Any:
|
||||||
return super().__call__(*args, **kwargs)
|
return super().__call__(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
@ -44,3 +47,17 @@ class Class3(metaclass=MetaClass3):
|
|||||||
|
|
||||||
v3 = Class3()
|
v3 = Class3()
|
||||||
reveal_type(v3, expected_text="Any")
|
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