Skip to content

Commit 8326417

Browse files
committed
Better handling of generics when narrowing
1 parent d17902d commit 8326417

4 files changed

Lines changed: 7 additions & 33 deletions

File tree

mypy/checker.py

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
from mypy.expandtype import expand_type
4646
from mypy.literals import Key, extract_var_from_literal_hash, literal, literal_hash
4747
from mypy.maptype import map_instance_to_supertype
48-
from mypy.meet import is_overlapping_erased_types, is_overlapping_types, meet_types
48+
from mypy.meet import is_overlapping_types, meet_types
4949
from mypy.message_registry import ErrorMessage
5050
from mypy.messages import (
5151
SUGGESTED_TEST_FIXTURES,
@@ -6561,19 +6561,6 @@ def comparison_type_narrowing_helper(self, node: ComparisonExpr) -> tuple[TypeMa
65616561
narrowable_indices={0},
65626562
)
65636563

6564-
# We only try and narrow away 'None' for now
6565-
if (
6566-
if_map is not None
6567-
and is_overlapping_none(item_type)
6568-
and not is_overlapping_none(collection_item_type)
6569-
and not (
6570-
isinstance(collection_item_type, Instance)
6571-
and collection_item_type.type.fullname == "builtins.object"
6572-
)
6573-
and is_overlapping_erased_types(item_type, collection_item_type)
6574-
):
6575-
if_map[operands[left_index]] = remove_optional(item_type)
6576-
65776564
if right_index in narrowable_operand_index_to_hash:
65786565
if_type, else_type = self.conditional_types_for_iterable(
65796566
item_type, iterable_type
@@ -6708,6 +6695,8 @@ def narrow_type_by_identity_equality(
67086695
# `x` to `Literal[Foo.A]` iff `Foo` has exactly one member.
67096696
# See testMatchEnumSingleChoice
67106697
target_type = coerce_to_literal(target_type)
6698+
if isinstance(target_type, Instance):
6699+
target_type = erase_type(target_type)
67116700

67126701
if (
67136702
# See comments in ambiguous_enum_equality_keys
@@ -8612,9 +8601,6 @@ def reduce_and_conditional_type_maps(ms: list[TypeMap], *, use_meet: bool) -> Ty
86128601
"builtins.bytes",
86138602
"builtins.bytearray",
86148603
"builtins.memoryview",
8615-
"builtins.list",
8616-
"builtins.dict",
8617-
"builtins.set",
86188604
}
86198605

86208606

mypy/meet.py

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -657,18 +657,6 @@ def _type_object_overlap(left: Type, right: Type) -> bool:
657657
return False
658658

659659

660-
def is_overlapping_erased_types(
661-
left: Type, right: Type, *, ignore_promotions: bool = False
662-
) -> bool:
663-
"""The same as 'is_overlapping_erased_types', except the types are erased first."""
664-
return is_overlapping_types(
665-
erase_type(left),
666-
erase_type(right),
667-
ignore_promotions=ignore_promotions,
668-
prohibit_none_typevar_overlap=True,
669-
)
670-
671-
672660
def are_typed_dicts_overlapping(
673661
left: TypedDictType, right: TypedDictType, is_overlapping: Callable[[Type, Type], bool]
674662
) -> bool:

test-data/unit/check-isinstance.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2018,7 +2018,7 @@ nested_any: List[List[Any]]
20182018
if lst in nested_any:
20192019
reveal_type(lst) # N: Revealed type is "builtins.list[builtins.int]"
20202020
if x in nested_any:
2021-
reveal_type(x) # N: Revealed type is "builtins.int | None"
2021+
reveal_type(x) # E: Statement is unreachable
20222022
[builtins fixtures/list.pyi]
20232023

20242024
[case testNarrowTypeAfterInTuple]

test-data/unit/check-narrowing.test

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2902,7 +2902,7 @@ def main(key: str):
29022902
[builtins fixtures/tuple.pyi]
29032903

29042904
[case testNarrowingCollections]
2905-
# flags: --warn-unreachable
2905+
# flags: --warn-unreachable --strict-equality
29062906
from typing import cast
29072907

29082908
class X:
@@ -2919,7 +2919,7 @@ class X:
29192919
reveal_type(self.x) # N: Revealed type is "builtins.dict[builtins.str, builtins.str]"
29202920
self.x["asdf"]
29212921

2922-
if self.x == cast(dict[int, int], {}):
2922+
if self.x == cast(dict[int, int], {}): # E: Non-overlapping equality check (left operand type: "dict[str, str]", right operand type: "dict[int, int]")
29232923
reveal_type(self.x) # N: Revealed type is "builtins.dict[builtins.str, builtins.str]"
29242924
self.x["asdf"]
29252925

@@ -2932,7 +2932,7 @@ class X:
29322932
reveal_type(self.y) # N: Revealed type is "builtins.list[builtins.str]"
29332933
self.y[0].does_not_exist # E: "str" has no attribute "does_not_exist"
29342934

2935-
if self.y == cast(list[int], []):
2935+
if self.y == cast(list[int], []): # E: Non-overlapping equality check (left operand type: "list[str]", right operand type: "list[int]")
29362936
reveal_type(self.y) # N: Revealed type is "builtins.list[builtins.str]"
29372937
self.y[0].does_not_exist # E: "str" has no attribute "does_not_exist"
29382938
[builtins fixtures/dict.pyi]

0 commit comments

Comments
 (0)