Skip to content

Commit

Permalink
Support __bool__ with Literal in --warn-unreachable (#15645)
Browse files Browse the repository at this point in the history
This adds support for `Literal` as return type of `__bool__` in the
reachability analysis.

Fixes #7008
  • Loading branch information
kreathon authored Aug 12, 2023
1 parent 0e4521a commit 742b5c6
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 8 deletions.
12 changes: 4 additions & 8 deletions mypy/typeops.py
Original file line number Diff line number Diff line change
Expand Up @@ -602,10 +602,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
Expand Down Expand Up @@ -637,10 +635,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
Expand Down
32 changes: 32 additions & 0 deletions test-data/unit/check-unreachable-code.test
Original file line number Diff line number Diff line change
Expand Up @@ -1379,6 +1379,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
Expand Down

0 comments on commit 742b5c6

Please sign in to comment.