Skip to content

Commit d96243d

Browse files
committed
Pick unreachable branches more aggressively
1 parent ba560f2 commit d96243d

File tree

2 files changed

+20
-8
lines changed

2 files changed

+20
-8
lines changed

mypy/checker.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6507,6 +6507,7 @@ def equality_type_narrowing_helper(
65076507
if operator in {"is", "is not"}:
65086508
is_valid_target: Callable[[Type], bool] = is_singleton_type
65096509
coerce_only_in_literal_context = False
6510+
no_custom_eq = True
65106511
should_narrow_by_identity = True
65116512
else:
65126513

@@ -6522,21 +6523,31 @@ def has_no_custom_eq_checks(t: Type) -> bool:
65226523
coerce_only_in_literal_context = True
65236524

65246525
expr_types = [operand_types[i] for i in expr_indices]
6525-
should_narrow_by_identity = all(
6526-
map(has_no_custom_eq_checks, expr_types)
6527-
) and not is_ambiguous_mix_of_enums(expr_types)
6526+
no_custom_eq = all(map(has_no_custom_eq_checks, expr_types))
6527+
should_narrow_by_identity = not is_ambiguous_mix_of_enums(expr_types)
65286528

65296529
if_map: TypeMap = {}
65306530
else_map: TypeMap = {}
6531-
if should_narrow_by_identity:
6532-
if_map, else_map = self.refine_identity_comparison_expression(
6531+
if no_custom_eq:
6532+
# Try to narrow the types or at least identify unreachable blocks.
6533+
# If there's some mix of enums and values, we do not want to narrow enums
6534+
# to literals, but still want to detect unreachable branches.
6535+
if_map_optimistic, else_map_optimistic = self.refine_identity_comparison_expression(
65336536
operands,
65346537
operand_types,
65356538
expr_indices,
65366539
narrowable_operand_index_to_hash.keys(),
65376540
is_valid_target,
65386541
coerce_only_in_literal_context,
65396542
)
6543+
if should_narrow_by_identity:
6544+
if_map = if_map_optimistic
6545+
else_map = else_map_optimistic
6546+
else:
6547+
if if_map_optimistic is None:
6548+
if_map = None
6549+
if else_map_optimistic is None:
6550+
else_map = None
65406551

65416552
if if_map == {} and else_map == {}:
65426553
if_map, else_map = self.refine_away_none_in_comparison(
@@ -9129,9 +9140,7 @@ def _ambiguous_enum_variants(types: list[Type]) -> set[str]:
91299140
# let's be conservative
91309141
result.add("<other>")
91319142
elif isinstance(t, LiteralType):
9132-
if t.fallback.type.is_enum:
9133-
result.update(_ambiguous_enum_variants([t.fallback]))
9134-
# Other literals (str, int, bool) cannot introduce any surprises
9143+
result.update(_ambiguous_enum_variants([t.fallback]))
91359144
elif isinstance(t, NoneType):
91369145
pass
91379146
else:

test-data/unit/check-enum.test

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2703,6 +2703,9 @@ if A.a == 0: # E: Non-overlapping equality check (left operand type: "Literal[A
27032703

27042704
if A.a == A.a:
27052705
1 + 'a' # E: Unsupported operand types for + ("int" and "str")
2706+
else:
2707+
1 + 'a' # E: Unsupported operand types for + ("int" and "str")
2708+
27062709
if A.a == A.b: # E: Non-overlapping equality check (left operand type: "Literal[A.a]", right operand type: "Literal[A.b]")
27072710
1 + 'a'
27082711

0 commit comments

Comments
 (0)