From 5a08ce14e2f90c5ab5e636c2e4294e6ddf104ebc Mon Sep 17 00:00:00 2001 From: Brian Schubert Date: Wed, 25 Sep 2024 10:08:11 -0400 Subject: [PATCH 1/3] Signal unreachability when narrowing with Type{Guard,Is}[Never] --- mypy/checker.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mypy/checker.py b/mypy/checker.py index 9c4f4ce88690..c8416544e11b 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -5889,9 +5889,13 @@ def find_isinstance_check_helper( # Also note that a care must be taken to unwrap this back at read places # where we use this to narrow down declared type. if node.callee.type_guard is not None: + if isinstance(get_proper_type(node.callee.type_guard), UninhabitedType): + return None, {} return {expr: TypeGuardedType(node.callee.type_guard)}, {} else: assert node.callee.type_is is not None + if isinstance(get_proper_type(node.callee.type_is), UninhabitedType): + return None, {} return conditional_types_to_typemaps( expr, *self.conditional_types_with_intersection( From 29e25c603031ce953597edd920a25856ab00ffea Mon Sep 17 00:00:00 2001 From: Brian Schubert Date: Wed, 25 Sep 2024 11:05:29 -0400 Subject: [PATCH 2/3] Add tests --- test-data/unit/check-unreachable-code.test | 38 ++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/test-data/unit/check-unreachable-code.test b/test-data/unit/check-unreachable-code.test index cbad1bd5449e..794e6c67e3f4 100644 --- a/test-data/unit/check-unreachable-code.test +++ b/test-data/unit/check-unreachable-code.test @@ -1507,3 +1507,41 @@ x = 0 # not unreachable f2: Callable[[], NoReturn] = lambda: foo() x = 0 # not unreachable + +[case testUnreachableTypeGuardNever] +# flags: --warn-unreachable +from typing_extensions import Never, TypeGuard + +def guard(x: object) -> TypeGuard[Never]: + pass + +a: object +assert not guard(a) + +if guard(a): + reveal_type(a) # E: Statement is unreachable +else: + reveal_type(a) # N: Revealed type is "builtins.object" + +assert guard(a) +b = 0 # E: Statement is unreachable +[builtins fixtures/tuple.pyi] + +[case testUnreachableTypeIsNever] +# flags: --warn-unreachable +from typing_extensions import Never, TypeIs + +def guard(x: object) -> TypeIs[Never]: + pass + +a: object +assert not guard(a) + +if guard(a): + reveal_type(a) # E: Statement is unreachable +else: + reveal_type(a) # N: Revealed type is "builtins.object" + +assert guard(a) +b = 0 # E: Statement is unreachable +[builtins fixtures/tuple.pyi] From 9e8008a98e1dad0f2be298eff8c37a96fed3723e Mon Sep 17 00:00:00 2001 From: Brian Schubert Date: Wed, 25 Sep 2024 11:45:33 -0400 Subject: [PATCH 3/3] Black format --- mypy/checker.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mypy/checker.py b/mypy/checker.py index c8416544e11b..db172823b403 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -5889,7 +5889,9 @@ def find_isinstance_check_helper( # Also note that a care must be taken to unwrap this back at read places # where we use this to narrow down declared type. if node.callee.type_guard is not None: - if isinstance(get_proper_type(node.callee.type_guard), UninhabitedType): + if isinstance( + get_proper_type(node.callee.type_guard), UninhabitedType + ): return None, {} return {expr: TypeGuardedType(node.callee.type_guard)}, {} else: