diff --git a/packages/pyright-internal/src/analyzer/typeGuards.ts b/packages/pyright-internal/src/analyzer/typeGuards.ts index acf04b825f25..1b6bfd250246 100644 --- a/packages/pyright-internal/src/analyzer/typeGuards.ts +++ b/packages/pyright-internal/src/analyzer/typeGuards.ts @@ -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( diff --git a/packages/pyright-internal/src/tests/samples/isinstance4.py b/packages/pyright-internal/src/tests/samples/isinstance4.py index 126fbe553eea..57f05d20d6d5 100644 --- a/packages/pyright-internal/src/tests/samples/isinstance4.py +++ b/packages/pyright-internal/src/tests/samples/isinstance4.py @@ -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") diff --git a/packages/pyright-internal/src/tests/samples/typeNarrowingIsinstance14.py b/packages/pyright-internal/src/tests/samples/typeNarrowingIsinstance14.py index 4e8613f0ed7b..467d35be059e 100644 --- a/packages/pyright-internal/src/tests/samples/typeNarrowingIsinstance14.py +++ b/packages/pyright-internal/src/tests/samples/typeNarrowingIsinstance14.py @@ -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 diff --git a/packages/pyright-internal/src/tests/samples/typeNarrowingIsinstance16.py b/packages/pyright-internal/src/tests/samples/typeNarrowingIsinstance16.py index 1477455cd8cb..a7b7281b7e54 100644 --- a/packages/pyright-internal/src/tests/samples/typeNarrowingIsinstance16.py +++ b/packages/pyright-internal/src/tests/samples/typeNarrowingIsinstance16.py @@ -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") diff --git a/packages/pyright-internal/src/tests/samples/typeNarrowingIsinstance2.py b/packages/pyright-internal/src/tests/samples/typeNarrowingIsinstance2.py index af624238dab6..b4c439a3194d 100644 --- a/packages/pyright-internal/src/tests/samples/typeNarrowingIsinstance2.py +++ b/packages/pyright-internal/src/tests/samples/typeNarrowingIsinstance2.py @@ -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") @@ -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") @@ -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")