Skip to content

Commit 648bd84

Browse files
committed
Remove short-circuiting logic here, it is safe to check truthiness of any stmt - there are no error reports. Make MYPY_* vs ALWAYS_* consistent.
1 parent a500826 commit 648bd84

File tree

2 files changed

+49
-20
lines changed

2 files changed

+49
-20
lines changed

mypy/reachability.py

+23-20
Original file line numberDiff line numberDiff line change
@@ -128,28 +128,31 @@ def infer_condition_value(expr: Expression, options: Options) -> int:
128128
elif isinstance(expr, MemberExpr):
129129
name = expr.name
130130
elif isinstance(expr, OpExpr) and expr.op in ("and", "or"):
131-
# This is a bit frivolous with MYPY_* vs ALWAYS_* returns: for example, here
132-
# `MYPY_TRUE or ALWAYS_TRUE` will be `MYPY_TRUE`, while
133-
# `ALWAYS_TRUE or MYPY_TRUE` will be `ALWAYS_TRUE`. This literally never
134-
# makes any difference in consuming code, so short-circuiting here is probably
135-
# good enough as it allows referencing platform-dependent variables in
136-
# statement parts that will not be executed.
131+
if expr.op not in ("or", "and"):
132+
return TRUTH_VALUE_UNKNOWN
133+
137134
left = infer_condition_value(expr.left, options)
138-
if (left in (ALWAYS_TRUE, MYPY_TRUE) and expr.op == "or") or (
139-
left in (ALWAYS_FALSE, MYPY_FALSE) and expr.op == "and"
140-
):
141-
# Either `True or <other>` or `False and <other>`: `<other>` doesn't matter
142-
return left
143135
right = infer_condition_value(expr.right, options)
144-
if (right in (ALWAYS_TRUE, MYPY_TRUE) and expr.op == "or") or (
145-
right in (ALWAYS_FALSE, MYPY_FALSE) and expr.op == "and"
146-
):
147-
# Either `<other> or True` or `<other> and False`: `<other>` doesn't matter
148-
return right
149-
# Now we have `True and True`, `False or False` or smth indeterminate.
150-
if TRUTH_VALUE_UNKNOWN in (left, right) or expr.op not in ("or", "and"):
151-
return TRUTH_VALUE_UNKNOWN
152-
return left
136+
results = {left, right}
137+
if expr.op == "or":
138+
if ALWAYS_TRUE in results:
139+
return ALWAYS_TRUE
140+
elif MYPY_TRUE in results:
141+
return MYPY_TRUE
142+
elif left == right == MYPY_FALSE:
143+
return MYPY_FALSE
144+
elif results <= {ALWAYS_FALSE, MYPY_FALSE}:
145+
return ALWAYS_FALSE
146+
elif expr.op == "and":
147+
if ALWAYS_FALSE in results:
148+
return ALWAYS_FALSE
149+
elif MYPY_FALSE in results:
150+
return MYPY_FALSE
151+
elif left == right == ALWAYS_TRUE:
152+
return ALWAYS_TRUE
153+
elif results <= {ALWAYS_TRUE, MYPY_TRUE}:
154+
return MYPY_TRUE
155+
return TRUTH_VALUE_UNKNOWN
153156
else:
154157
result = consider_sys_version_info(expr, pyversion)
155158
if result == TRUTH_VALUE_UNKNOWN:

test-data/unit/check-unreachable-code.test

+26
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,32 @@ reveal_type(unary_minus) # N: Revealed type is "Union[Literal[0], builtins.str]"
550550
reveal_type(binary_minus) # N: Revealed type is "Union[Literal[0], builtins.str]"
551551
[builtins fixtures/ops.pyi]
552552

553+
[case testMypyFalseValuesInBinaryOps_no_empty]
554+
# flags: --platform linux
555+
import sys
556+
from typing import TYPE_CHECKING
557+
558+
MYPY = 0
559+
560+
if TYPE_CHECKING and sys.platform == 'linux':
561+
def foo1() -> int: ...
562+
if sys.platform == 'linux' and TYPE_CHECKING:
563+
def foo2() -> int: ...
564+
if MYPY and sys.platform == 'linux':
565+
def foo3() -> int: ...
566+
if sys.platform == 'linux' and MYPY:
567+
def foo4() -> int: ...
568+
569+
if TYPE_CHECKING or sys.platform == 'linux':
570+
def bar1() -> int: ... # E: Missing return statement
571+
if sys.platform == 'linux' or TYPE_CHECKING:
572+
def bar2() -> int: ... # E: Missing return statement
573+
if MYPY or sys.platform == 'linux':
574+
def bar3() -> int: ... # E: Missing return statement
575+
if sys.platform == 'linux' or MYPY:
576+
def bar4() -> int: ... # E: Missing return statement
577+
[builtins fixtures/ops.pyi]
578+
553579
[case testShortCircuitAndWithConditionalAssignment]
554580
# flags: --platform linux
555581
import sys

0 commit comments

Comments
 (0)