mirror of
https://github.com/microsoft/pyright.git
synced 2024-07-14 19:10:39 +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
|
isPositiveTest: boolean
|
||||||
): Type {
|
): Type {
|
||||||
return mapSubtypes(referenceType, (subtype) => {
|
return mapSubtypes(referenceType, (subtype) => {
|
||||||
const concreteSubtype = evaluator.makeTopLevelTypeVarsConcrete(subtype);
|
let concreteSubtype = evaluator.makeTopLevelTypeVarsConcrete(subtype);
|
||||||
|
|
||||||
if (isPositiveTest) {
|
if (isPositiveTest) {
|
||||||
if (isNoneInstance(concreteSubtype)) {
|
if (isNoneInstance(concreteSubtype)) {
|
||||||
return undefined;
|
return isNoneTypeClass(classType) ? classType : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isClassInstance(concreteSubtype) && TypeBase.isInstance(subtype)) {
|
if (
|
||||||
if (ClassType.isBuiltIn(concreteSubtype, 'type')) {
|
isClassInstance(concreteSubtype) &&
|
||||||
return classType;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isClass(concreteSubtype)) {
|
||||||
|
if (TypeBase.isInstance(concreteSubtype)) {
|
||||||
|
return ClassType.isBuiltIn(concreteSubtype, 'object') ? classType : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
const isSuperType = isIsinstanceFilterSuperclass(
|
||||||
}
|
evaluator,
|
||||||
|
subtype,
|
||||||
|
concreteSubtype,
|
||||||
|
classType,
|
||||||
|
classType,
|
||||||
|
/* isInstanceCheck */ false
|
||||||
|
);
|
||||||
|
|
||||||
if (isInstantiableClass(concreteSubtype) && ClassType.isFinal(concreteSubtype)) {
|
if (!classType.includeSubclasses) {
|
||||||
if (
|
// Handle the case where the LHS and RHS operands are specific
|
||||||
!ClassType.isSameGenericClass(concreteSubtype, classType) &&
|
// classes, as opposed to types that represent classes and their
|
||||||
!isIsinstanceFilterSuperclass(
|
// subclasses.
|
||||||
|
if (!concreteSubtype.includeSubclasses) {
|
||||||
|
return ClassType.isSameGenericClass(concreteSubtype, classType) ? classType : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isSubType = isIsinstanceFilterSubclass(
|
||||||
evaluator,
|
evaluator,
|
||||||
subtype,
|
|
||||||
concreteSubtype,
|
concreteSubtype,
|
||||||
classType,
|
classType,
|
||||||
classType,
|
|
||||||
/* isInstanceCheck */ false
|
/* isInstanceCheck */ false
|
||||||
)
|
);
|
||||||
) {
|
|
||||||
|
if (isSuperType) {
|
||||||
|
return classType;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSubType) {
|
||||||
|
return addConditionToType(classType, getTypeCondition(concreteSubtype));
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ClassType.isFinal(concreteSubtype) && !isSuperType) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,17 +5,14 @@ from typing import Any, TypeVar, final
|
|||||||
|
|
||||||
|
|
||||||
@final
|
@final
|
||||||
class A:
|
class A: ...
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
@final
|
@final
|
||||||
class B:
|
class B: ...
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
class C:
|
class C: ...
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
def func1(x: type[A] | type[B] | None | int):
|
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):
|
def func3(x: type[A] | type[B] | Any):
|
||||||
if x is A:
|
if x is A:
|
||||||
reveal_type(x, expected_text="type[A] | Any")
|
reveal_type(x, expected_text="type[A]")
|
||||||
else:
|
else:
|
||||||
reveal_type(x, expected_text="type[B] | Any")
|
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]:
|
def func5(x: type[A] | type[B] | type[T]) -> type[A] | type[B] | type[T]:
|
||||||
if x is A:
|
if x is A:
|
||||||
reveal_type(x, expected_text="type[A] | type[T@func5]")
|
reveal_type(x, expected_text="type[A] | type[A]*")
|
||||||
else:
|
else:
|
||||||
reveal_type(x, expected_text="type[B] | type[T@func5]")
|
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]")
|
reveal_type(x, expected_text="type[str]")
|
||||||
else:
|
else:
|
||||||
reveal_type(x, expected_text="type")
|
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