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
5 changes: 2 additions & 3 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -6866,12 +6866,11 @@ def find_isinstance_check_helper(

# Restrict the type of the variable to True-ish/False-ish in the if and else branches
# respectively
original_vartype = self.lookup_type(node)
vartype = self.lookup_type(node)
if in_boolean_context:
# We don't check `:=` values in expressions like `(a := A())`,
# because they produce two error messages.
self.check_for_truthy_type(original_vartype, node)
vartype = try_expanding_sum_type_to_union(original_vartype, "builtins.bool")
self.check_for_truthy_type(vartype, node)

if_map = {node: true_only(vartype)}
else_map = {node: false_only(vartype)}
Expand Down
12 changes: 5 additions & 7 deletions mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,6 @@
is_literal_type_like,
make_simplified_union,
true_only,
try_expanding_sum_type_to_union,
try_getting_str_literals,
tuple_fallback,
type_object_type,
Expand Down Expand Up @@ -4457,7 +4456,6 @@ def check_boolean_op(self, e: OpExpr) -> Type:
# '[1] or []' are inferred correctly.
ctx = self.type_context[-1]
left_type = self.accept(e.left, ctx)
expanded_left_type = try_expanding_sum_type_to_union(left_type, "builtins.bool")

assert e.op in ("and", "or") # Checked by visit_op_expr

Expand Down Expand Up @@ -4493,7 +4491,7 @@ def check_boolean_op(self, e: OpExpr) -> Type:
self.msg.unreachable_right_operand(e.op, e.right)

right_type = self.analyze_cond_branch(
right_map, e.right, self._combined_context(expanded_left_type)
right_map, e.right, self._combined_context(left_type)
)

if left_unreachable and right_unreachable:
Expand All @@ -4507,11 +4505,11 @@ def check_boolean_op(self, e: OpExpr) -> Type:
return right_type

if e.op == "and":
restricted_left_type = false_only(expanded_left_type)
result_is_left = not expanded_left_type.can_be_true
restricted_left_type = false_only(left_type)
result_is_left = not left_type.can_be_true
elif e.op == "or":
restricted_left_type = true_only(expanded_left_type)
result_is_left = not expanded_left_type.can_be_false
restricted_left_type = true_only(left_type)
result_is_left = not left_type.can_be_false

if isinstance(restricted_left_type, UninhabitedType):
# The left operand can never be the result
Expand Down
2 changes: 2 additions & 0 deletions mypy/test/testtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,7 @@ def test_true_only_of_instance(self) -> None:
assert_type(Instance, to)
# The original class still can be false
assert self.fx.a.can_be_false
assert_equal(true_only(self.fx.bool_type), self.fx.lit_true)

def test_true_only_of_union(self) -> None:
tup_type = self.tuple(AnyType(TypeOfAny.special_form))
Expand Down Expand Up @@ -579,6 +580,7 @@ def test_false_only_of_instance(self) -> None:
assert_type(Instance, fo)
# The original class still can be true
assert self.fx.a.can_be_true
assert_equal(false_only(self.fx.bool_type), self.fx.lit_false)

def test_false_only_of_union(self) -> None:
with state.strict_optional_set(True):
Expand Down
4 changes: 4 additions & 0 deletions mypy/typeops.py
Original file line number Diff line number Diff line change
Expand Up @@ -841,6 +841,8 @@ def true_only(t: Type) -> ProperType:
new_items = [true_only(item) for item in t.items]
can_be_true_items = [item for item in new_items if item.can_be_true]
return make_simplified_union(can_be_true_items, line=t.line, column=t.column)
elif isinstance(t, Instance) and t.type.fullname == "builtins.bool":
return LiteralType(True, fallback=t)
else:
ret_type = _get_type_method_ret_type(t, name="__bool__") or _get_type_method_ret_type(
t, name="__len__"
Expand Down Expand Up @@ -880,6 +882,8 @@ def false_only(t: Type) -> ProperType:
return LiteralType("", fallback=t)
elif isinstance(t, Instance) and t.type.fullname == "builtins.int":
return LiteralType(0, fallback=t)
elif isinstance(t, Instance) and t.type.fullname == "builtins.bool":
return LiteralType(False, fallback=t)
else:
ret_type = _get_type_method_ret_type(t, name="__bool__") or _get_type_method_ret_type(
t, name="__len__"
Expand Down
Loading