diff --git a/mypy/typeops.py b/mypy/typeops.py index 519d3de995f5..97f7ec1aa6ee 100644 --- a/mypy/typeops.py +++ b/mypy/typeops.py @@ -600,10 +600,8 @@ def true_only(t: Type) -> ProperType: else: ret_type = _get_type_special_method_bool_ret_type(t) - if ret_type and ret_type.can_be_false and not ret_type.can_be_true: - new_t = copy_type(t) - new_t.can_be_true = False - return new_t + if ret_type and not ret_type.can_be_true: + return UninhabitedType(line=t.line, column=t.column) new_t = copy_type(t) new_t.can_be_false = False @@ -635,10 +633,8 @@ def false_only(t: Type) -> ProperType: else: ret_type = _get_type_special_method_bool_ret_type(t) - if ret_type and ret_type.can_be_true and not ret_type.can_be_false: - new_t = copy_type(t) - new_t.can_be_false = False - return new_t + if ret_type and not ret_type.can_be_false: + return UninhabitedType(line=t.line) new_t = copy_type(t) new_t.can_be_true = False diff --git a/test-data/unit/check-unreachable-code.test b/test-data/unit/check-unreachable-code.test index b2fd44043435..81da254a4d89 100644 --- a/test-data/unit/check-unreachable-code.test +++ b/test-data/unit/check-unreachable-code.test @@ -1380,6 +1380,38 @@ def f() -> None: x = 1 # E: Statement is unreachable [builtins fixtures/dict.pyi] +[case testUnreachableLiteralFrom__bool__] +# flags: --warn-unreachable +from typing_extensions import Literal + +class Truth: + def __bool__(self) -> Literal[True]: ... + +class Lie: + def __bool__(self) -> Literal[False]: ... + +class Maybe: + def __bool__(self) -> Literal[True | False]: ... + +t = Truth() +if t: + x = 1 +else: + x = 2 # E: Statement is unreachable + +if Lie(): + x = 3 # E: Statement is unreachable + +if Maybe(): + x = 4 + + +def foo() -> bool: ... + +y = Truth() or foo() # E: Right operand of "or" is never evaluated +z = Lie() and foo() # E: Right operand of "and" is never evaluated +[builtins fixtures/dict.pyi] + [case testUnreachableModuleBody1] # flags: --warn-unreachable from typing import NoReturn