diff --git a/mypy/checker.py b/mypy/checker.py index 33705c98e10c..4c643bb4317b 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -6591,12 +6591,19 @@ def find_isinstance_check_helper( if len(node.args) != 2: # the error will be reported elsewhere return {}, {} if literal(expr) == LITERAL_TYPE: - return conditional_types_to_typemaps( - expr, - *self.conditional_types_with_intersection( - self.lookup_type(expr), self.get_isinstance_type(node.args[1]), expr - ), + original_type = self.lookup_type(expr) + current_type = self.expr_checker.narrow_type_from_binder(expr, original_type) + yes_type, no_type = self.conditional_types_with_intersection( + current_type, self.get_isinstance_type(node.args[1]), expr ) + if ( + self.binder.get(expr) is not None + and yes_type is not None + and not isinstance(get_proper_type(current_type), AnyType) + and is_subtype(current_type, yes_type, ignore_promotions=True) + ): + yes_type = current_type + return conditional_types_to_typemaps(expr, yes_type, no_type) elif refers_to_fullname(node.callee, "builtins.issubclass"): if len(node.args) != 2: # the error will be reported elsewhere return {}, {} diff --git a/test-data/unit/check-isinstance.test b/test-data/unit/check-isinstance.test index acd81839fcdc..b63b5f6c8a6f 100644 --- a/test-data/unit/check-isinstance.test +++ b/test-data/unit/check-isinstance.test @@ -3248,6 +3248,15 @@ def foo(x: object, t: type[Any]): reveal_type(x) # N: Revealed type is "Any" [builtins fixtures/isinstance.pyi] +[case testAssertIsinstanceAny] +from typing import Any + +def f(x: Any) -> str: + assert isinstance(x, str) + reveal_type(x) # N: Revealed type is "builtins.str" + return x +[builtins fixtures/isinstance.pyi] + [case testIsInstanceObject] # flags: --strict-equality --warn-unreachable from typing import Any diff --git a/test-data/unit/check-typeis.test b/test-data/unit/check-typeis.test index 65ee837452f5..6b63f9aa080c 100644 --- a/test-data/unit/check-typeis.test +++ b/test-data/unit/check-typeis.test @@ -26,6 +26,25 @@ def main(a: Union[Point, Line, int]) -> None: [builtins fixtures/tuple.pyi] +[case testTypeIsAndIsinstanceWithGenericAlias] +from typing import Any, Generic, TypeVar +from typing_extensions import TypeAlias, TypeIs + +T = TypeVar("T") +class Slice(Generic[T]): pass + +SliceInt: TypeAlias = Slice[int | None] +SliceStr: TypeAlias = Slice[str | None] + +def is_slice_int(obj: Any) -> TypeIs[SliceInt]: pass + +def main(obj: SliceInt | SliceStr) -> None: + if is_slice_int(obj): + pass + elif isinstance(obj, Slice): + reveal_type(obj) # N: Revealed type is "__main__.Slice[builtins.str | None]" +[builtins fixtures/isinstance.pyi] + [case testTypeIsTypeArgsNone] from typing_extensions import TypeIs def foo(a: object) -> TypeIs: # E: TypeIs must have exactly one type argument