Type check a boolean operation ('and' or 'or').
(self, e: OpExpr)
| 4368 | ) |
| 4369 | |
| 4370 | def check_boolean_op(self, e: OpExpr) -> Type: |
| 4371 | """Type check a boolean operation ('and' or 'or').""" |
| 4372 | |
| 4373 | # A boolean operation can evaluate to either of the operands. |
| 4374 | |
| 4375 | # We use the current type context to guide the type inference of |
| 4376 | # the left operand. We also use the left operand type to guide the type |
| 4377 | # inference of the right operand so that expressions such as |
| 4378 | # '[1] or []' are inferred correctly. |
| 4379 | ctx = self.type_context[-1] |
| 4380 | left_type = self.accept(e.left, ctx) |
| 4381 | expanded_left_type = try_expanding_sum_type_to_union(left_type, "builtins.bool") |
| 4382 | |
| 4383 | assert e.op in ("and", "or") # Checked by visit_op_expr |
| 4384 | |
| 4385 | left_map: mypy.checker.TypeMap |
| 4386 | right_map: mypy.checker.TypeMap |
| 4387 | if e.right_always: |
| 4388 | left_map, right_map = {e.left: UninhabitedType()}, {} |
| 4389 | elif e.right_unreachable: |
| 4390 | left_map, right_map = {}, {e.right: UninhabitedType()} |
| 4391 | elif e.op == "and": |
| 4392 | right_map, left_map = self.chk.find_isinstance_check(e.left) |
| 4393 | elif e.op == "or": |
| 4394 | left_map, right_map = self.chk.find_isinstance_check(e.left) |
| 4395 | |
| 4396 | # If left_map is unreachable then we know mypy considers the left expression |
| 4397 | # to be redundant. |
| 4398 | left_unreachable = mypy.checker.is_unreachable_map(left_map) |
| 4399 | if ( |
| 4400 | codes.REDUNDANT_EXPR in self.chk.options.enabled_error_codes |
| 4401 | and left_unreachable |
| 4402 | # don't report an error if it's intentional |
| 4403 | and not e.right_always |
| 4404 | ): |
| 4405 | self.msg.redundant_left_operand(e.op, e.left) |
| 4406 | |
| 4407 | right_unreachable = mypy.checker.is_unreachable_map(right_map) |
| 4408 | if ( |
| 4409 | self.chk.should_report_unreachable_issues() |
| 4410 | and right_unreachable |
| 4411 | # don't report an error if it's intentional |
| 4412 | and not e.right_unreachable |
| 4413 | ): |
| 4414 | self.msg.unreachable_right_operand(e.op, e.right) |
| 4415 | |
| 4416 | right_type = self.analyze_cond_branch( |
| 4417 | right_map, e.right, self._combined_context(expanded_left_type) |
| 4418 | ) |
| 4419 | |
| 4420 | if left_unreachable and right_unreachable: |
| 4421 | return UninhabitedType() |
| 4422 | |
| 4423 | if right_unreachable: |
| 4424 | # The boolean expression is statically known to be the left value |
| 4425 | return left_type |
| 4426 | if left_unreachable: |
| 4427 | # The boolean expression is statically known to be the right value |
no test coverage detected