Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions mypy/reachability.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ def infer_condition_value(expr: Expression, options: Options) -> int:
name = expr.name
elif isinstance(expr, OpExpr) and expr.op in ('and', 'or'):
left = infer_condition_value(expr.left, options)
if ((left == ALWAYS_TRUE and expr.op == 'and') or
(left == ALWAYS_FALSE and expr.op == 'or')):
if ((left in (ALWAYS_TRUE, MYPY_TRUE) and expr.op == 'and') or
(left in (ALWAYS_FALSE, MYPY_FALSE) and expr.op == 'or')):
# Either `True and <other>` or `False or <other>`: the result will
# always be the right-hand-side.
return infer_condition_value(expr.right, options)
Expand All @@ -105,9 +105,9 @@ def infer_condition_value(expr: Expression, options: Options) -> int:
elif name == 'MYPY' or name == 'TYPE_CHECKING':
result = MYPY_TRUE
elif name in options.always_true:
result = MYPY_TRUE
result = ALWAYS_TRUE
elif name in options.always_false:
result = MYPY_FALSE
result = ALWAYS_FALSE
if negated:
result = inverted_truth_mapping[result]
return result
Expand Down
11 changes: 6 additions & 5 deletions mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@
from mypy.semanal_enum import EnumCallAnalyzer
from mypy.semanal_newtype import NewTypeAnalyzer
from mypy.reachability import (
infer_reachability_of_if_statement, infer_condition_value, ALWAYS_FALSE, ALWAYS_TRUE
infer_reachability_of_if_statement, infer_condition_value, ALWAYS_FALSE, ALWAYS_TRUE,
MYPY_TRUE, MYPY_FALSE
)
from mypy.typestate import TypeState

Expand Down Expand Up @@ -3102,12 +3103,12 @@ def visit_op_expr(self, expr: OpExpr) -> None:

if expr.op in ('and', 'or'):
inferred = infer_condition_value(expr.left, self.options)
if ((inferred == ALWAYS_FALSE and expr.op == 'and') or
(inferred == ALWAYS_TRUE and expr.op == 'or')):
if ((inferred in (ALWAYS_FALSE, MYPY_FALSE) and expr.op == 'and') or
(inferred in (ALWAYS_TRUE, MYPY_TRUE) and expr.op == 'or')):
expr.right_unreachable = True
return
elif ((inferred == ALWAYS_TRUE and expr.op == 'and') or
(inferred == ALWAYS_FALSE and expr.op == 'or')):
elif ((inferred in (ALWAYS_TRUE, MYPY_TRUE) and expr.op == 'and') or
(inferred in (ALWAYS_FALSE, MYPY_FALSE) and expr.op == 'or')):
expr.right_always = True

expr.right.accept(self)
Expand Down
36 changes: 36 additions & 0 deletions test-data/unit/check-unreachable-code.test
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,42 @@ else:
reveal_type(y) # E: Revealed type is 'builtins.str'
[builtins fixtures/ops.pyi]

[case testShortCircuitNoEvaluation]
# flags: --platform linux --always-false COMPILE_TIME_FALSE
import sys

if sys.platform == 'darwin':
mac_only = 'junk'

# `mac_only` should not be evaluated
if sys.platform == 'darwin' and mac_only:
pass
if sys.platform == 'linux' or mac_only:
pass

COMPILE_TIME_FALSE = 'junk'

if COMPILE_TIME_FALSE:
compile_time_false_only = 'junk'

# `compile_time_false_only` should not be evaluated
if COMPILE_TIME_FALSE and compile_time_false_only:
pass
if not COMPILE_TIME_FALSE or compile_time_false_only:
pass

MYPY = False

if not MYPY:
mypy_only = 'junk'

# `mypy_only` should not be evaluated
if not MYPY and mypy_only:
pass
if MYPY or mypy_only:
pass
[builtins fixtures/ops.pyi]

[case testConditionalAssertWithoutElse]
import typing

Expand Down