Skip to content

Commit

Permalink
Modified the isinstance type narrowing logic to retain a TypeVar wh…
Browse files Browse the repository at this point in the history
…en narrowing in the positive case and the value is not a constrained TypeVar. This addresses #6434. (#6439)
  • Loading branch information
erictraut authored Nov 14, 2023
1 parent 6edcade commit f0aad20
Show file tree
Hide file tree
Showing 5 changed files with 12 additions and 7 deletions.
7 changes: 6 additions & 1 deletion packages/pyright-internal/src/analyzer/typeGuards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1394,7 +1394,12 @@ function narrowTypeForIsInstance(
if (filterIsSuperclass) {
// If the variable type is a subclass of the isinstance filter,
// we haven't learned anything new about the variable type.
filteredTypes.push(addConditionToType(concreteVarType, conditions));

// If the varType is a constrained TypeVar, narrow to the specific
// constraint. Otherwise retain the varType.
const unnarrowedType =
isTypeVar(varType) && varType.details.constraints.length > 0 ? concreteVarType : varType;
filteredTypes.push(addConditionToType(unnarrowedType, conditions));
} else if (filterIsSubclass) {
if (
evaluator.assignType(
Expand Down
2 changes: 1 addition & 1 deletion packages/pyright-internal/src/tests/samples/isinstance4.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def get_type_of_object(object: Union[Callable[..., Any], CustomClass]):

def func1(cls: Type[_T1], val: _T1):
if issubclass(cls, CustomClass):
reveal_type(cls, expected_text="type[CustomClass]*")
reveal_type(cls, expected_text="type[_T1@func1]")
else:
reveal_type(cls, expected_text="Never")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def func1(cls: type[T], obj: Any) -> T:

def func2(klass: type[T], obj: T | int) -> T:
assert isinstance(obj, klass)
reveal_type(obj, expected_text="object*")
reveal_type(obj, expected_text="T@func2")
return obj


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ def baz(self, other: object):
reveal_type(other, expected_text="Self@ClassA")

if isinstance(other, (int, type(self))):
reveal_type(other, expected_text="ClassA | int | Self@ClassA")
reveal_type(other, expected_text="Self@ClassA | int")
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class ClassC:
@classmethod
def test(cls: type[TC], id: int | TC):
if isinstance(id, cls):
reveal_type(id, expected_text="object*")
reveal_type(id, expected_text="TC@test")
else:
reveal_type(id, expected_text="int")

Expand All @@ -36,7 +36,7 @@ class ClassD:
@classmethod
def test(cls: type[TD], id: int | TD):
if isinstance(id, cls):
reveal_type(id, expected_text="ClassD*")
reveal_type(id, expected_text="TD@test")
else:
reveal_type(id, expected_text="int")

Expand All @@ -45,6 +45,6 @@ class ClassE:
@classmethod
def test(cls: type[Self], id: int | Self):
if isinstance(id, cls):
reveal_type(id, expected_text="ClassE")
reveal_type(id, expected_text="Self@ClassE")
else:
reveal_type(id, expected_text="int")

0 comments on commit f0aad20

Please sign in to comment.