mirror of
https://github.com/microsoft/pyright.git
synced 2024-07-14 11:00:25 +03:00
Fixed a bug in the type narrowing for the "x is <class>" type guard pattern when <class>
is a specific class T, as opposed to a variable of type type[T]
. This addresses #8264.
This commit is contained in:
parent
fa0f6b7349
commit
d55be983e5
@ -2463,33 +2463,69 @@ function narrowTypeForClassComparison(
|
||||
isPositiveTest: boolean
|
||||
): Type {
|
||||
return mapSubtypes(referenceType, (subtype) => {
|
||||
const concreteSubtype = evaluator.makeTopLevelTypeVarsConcrete(subtype);
|
||||
let concreteSubtype = evaluator.makeTopLevelTypeVarsConcrete(subtype);
|
||||
|
||||
if (isPositiveTest) {
|
||||
if (isNoneInstance(concreteSubtype)) {
|
||||
return undefined;
|
||||
return isNoneTypeClass(classType) ? classType : undefined;
|
||||
}
|
||||
|
||||
if (isClassInstance(concreteSubtype) && TypeBase.isInstance(subtype)) {
|
||||
if (ClassType.isBuiltIn(concreteSubtype, 'type')) {
|
||||
if (
|
||||
isClassInstance(concreteSubtype) &&
|
||||
TypeBase.isInstance(subtype) &&
|
||||
ClassType.isBuiltIn(concreteSubtype, 'type')
|
||||
) {
|
||||
concreteSubtype =
|
||||
concreteSubtype.typeArguments && concreteSubtype.typeArguments.length > 0
|
||||
? convertToInstantiable(concreteSubtype.typeArguments[0])
|
||||
: UnknownType.create();
|
||||
}
|
||||
|
||||
if (isAnyOrUnknown(concreteSubtype)) {
|
||||
return classType;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
if (isClass(concreteSubtype)) {
|
||||
if (TypeBase.isInstance(concreteSubtype)) {
|
||||
return ClassType.isBuiltIn(concreteSubtype, 'object') ? classType : undefined;
|
||||
}
|
||||
|
||||
if (isInstantiableClass(concreteSubtype) && ClassType.isFinal(concreteSubtype)) {
|
||||
if (
|
||||
!ClassType.isSameGenericClass(concreteSubtype, classType) &&
|
||||
!isIsinstanceFilterSuperclass(
|
||||
const isSuperType = isIsinstanceFilterSuperclass(
|
||||
evaluator,
|
||||
subtype,
|
||||
concreteSubtype,
|
||||
classType,
|
||||
classType,
|
||||
/* isInstanceCheck */ false
|
||||
)
|
||||
) {
|
||||
);
|
||||
|
||||
if (!classType.includeSubclasses) {
|
||||
// Handle the case where the LHS and RHS operands are specific
|
||||
// classes, as opposed to types that represent classes and their
|
||||
// subclasses.
|
||||
if (!concreteSubtype.includeSubclasses) {
|
||||
return ClassType.isSameGenericClass(concreteSubtype, classType) ? classType : undefined;
|
||||
}
|
||||
|
||||
const isSubType = isIsinstanceFilterSubclass(
|
||||
evaluator,
|
||||
concreteSubtype,
|
||||
classType,
|
||||
/* isInstanceCheck */ false
|
||||
);
|
||||
|
||||
if (isSuperType) {
|
||||
return classType;
|
||||
}
|
||||
|
||||
if (isSubType) {
|
||||
return addConditionToType(classType, getTypeCondition(concreteSubtype));
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (ClassType.isFinal(concreteSubtype) && !isSuperType) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
@ -5,17 +5,14 @@ from typing import Any, TypeVar, final
|
||||
|
||||
|
||||
@final
|
||||
class A:
|
||||
...
|
||||
class A: ...
|
||||
|
||||
|
||||
@final
|
||||
class B:
|
||||
...
|
||||
class B: ...
|
||||
|
||||
|
||||
class C:
|
||||
...
|
||||
class C: ...
|
||||
|
||||
|
||||
def func1(x: type[A] | type[B] | None | int):
|
||||
@ -34,7 +31,7 @@ def func2(x: type[A] | type[B] | None | int, y: type[A]):
|
||||
|
||||
def func3(x: type[A] | type[B] | Any):
|
||||
if x is A:
|
||||
reveal_type(x, expected_text="type[A] | Any")
|
||||
reveal_type(x, expected_text="type[A]")
|
||||
else:
|
||||
reveal_type(x, expected_text="type[B] | Any")
|
||||
|
||||
@ -51,7 +48,7 @@ T = TypeVar("T")
|
||||
|
||||
def func5(x: type[A] | type[B] | type[T]) -> type[A] | type[B] | type[T]:
|
||||
if x is A:
|
||||
reveal_type(x, expected_text="type[A] | type[T@func5]")
|
||||
reveal_type(x, expected_text="type[A] | type[A]*")
|
||||
else:
|
||||
reveal_type(x, expected_text="type[B] | type[T@func5]")
|
||||
|
||||
@ -63,3 +60,10 @@ def func6(x: type):
|
||||
reveal_type(x, expected_text="type[str]")
|
||||
else:
|
||||
reveal_type(x, expected_text="type")
|
||||
|
||||
|
||||
def func7(x: type[A | B]):
|
||||
if x is A:
|
||||
reveal_type(x, expected_text="type[A]")
|
||||
else:
|
||||
reveal_type(x, expected_text="type[B]")
|
||||
|
Loading…
Reference in New Issue
Block a user