@@ -115,31 +115,41 @@ def infer_condition_value(expr: Expression, options: Options) -> int:
115115 MYPY_TRUE if true under mypy and false at runtime, MYPY_FALSE if
116116 false under mypy and true at runtime, else TRUTH_VALUE_UNKNOWN.
117117 """
118+ if isinstance (expr , UnaryExpr ) and expr .op == "not" :
119+ positive = infer_condition_value (expr .expr , options )
120+ return inverted_truth_mapping [positive ]
121+
118122 pyversion = options .python_version
119123 name = ""
120- negated = False
121- alias = expr
122- if isinstance (alias , UnaryExpr ):
123- if alias .op == "not" :
124- expr = alias .expr
125- negated = True
124+
126125 result = TRUTH_VALUE_UNKNOWN
127126 if isinstance (expr , NameExpr ):
128127 name = expr .name
129128 elif isinstance (expr , MemberExpr ):
130129 name = expr .name
131130 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.
132137 left = infer_condition_value (expr .left , options )
133- if (left in (ALWAYS_TRUE , MYPY_TRUE ) and expr .op == "and " ) or (
134- left in (ALWAYS_FALSE , MYPY_FALSE ) and expr .op == "or "
138+ if (left in (ALWAYS_TRUE , MYPY_TRUE ) and expr .op == "or " ) or (
139+ left in (ALWAYS_FALSE , MYPY_FALSE ) and expr .op == "and "
135140 ):
136- # Either `True and <other>` or `False or <other>`: the result will
137- # always be the right-hand-side.
138- return infer_condition_value (expr .right , options )
139- else :
140- # The result will always be the left-hand-side (e.g. ALWAYS_* or
141- # TRUTH_VALUE_UNKNOWN).
141+ # Either `True or <other>` or `False and <other>`: `<other>` doesn't matter
142142 return left
143+ 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
143153 else :
144154 result = consider_sys_version_info (expr , pyversion )
145155 if result == TRUTH_VALUE_UNKNOWN :
@@ -155,8 +165,6 @@ def infer_condition_value(expr: Expression, options: Options) -> int:
155165 result = ALWAYS_TRUE
156166 elif name in options .always_false :
157167 result = ALWAYS_FALSE
158- if negated :
159- result = inverted_truth_mapping [result ]
160168 return result
161169
162170
0 commit comments