Skip to content

Commit 1e598b3

Browse files
committed
Better handling of generics when narrowing
1 parent 94a3cf6 commit 1e598b3

File tree

4 files changed

+9
-40
lines changed

4 files changed

+9
-40
lines changed

mypy/checker.py

Lines changed: 5 additions & 23 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,
@@ -235,7 +235,7 @@
235235
is_literal_type,
236236
is_named_instance,
237237
)
238-
from mypy.types_utils import is_overlapping_none, remove_optional, store_argument_type, strip_type
238+
from mypy.types_utils import store_argument_type, strip_type
239239
from mypy.typetraverser import TypeTraverserVisitor
240240
from mypy.typevars import fill_typevars, fill_typevars_with_any, has_no_typevars
241241
from mypy.util import is_dunder, is_sunder
@@ -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
@@ -6709,6 +6696,8 @@ def narrow_type_by_identity_equality(
67096696
# `x` to `Literal[Foo.A]` iff `Foo` has exactly one member.
67106697
# See testMatchEnumSingleChoice
67116698
target_type = coerce_to_literal(target_type)
6699+
if isinstance(get_proper_type(target_type), Instance):
6700+
target_type = erase_type(target_type)
67126701

67136702
if (
67146703
# See comments in ambiguous_enum_equality_keys
@@ -8589,14 +8578,7 @@ def reduce_conditional_maps(
85898578
return final_if_map, final_else_map
85908579

85918580

8592-
BUILTINS_CUSTOM_EQ_CHECKS: Final = {
8593-
"builtins.bytes",
8594-
"builtins.bytearray",
8595-
"builtins.memoryview",
8596-
"builtins.list",
8597-
"builtins.dict",
8598-
"builtins.set",
8599-
}
8581+
BUILTINS_CUSTOM_EQ_CHECKS: Final = {"builtins.bytes", "builtins.bytearray", "builtins.memoryview"}
86008582

86018583

86028584
def has_custom_eq_checks(t: Type) -> bool:

mypy/meet.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
from collections.abc import Callable
44

55
from mypy import join
6-
from mypy.erasetype import erase_type
76
from mypy.maptype import map_instance_to_supertype
87
from mypy.state import state
98
from mypy.subtypes import (
@@ -657,18 +656,6 @@ def _type_object_overlap(left: Type, right: Type) -> bool:
657656
return False
658657

659658

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-
672659
def are_typed_dicts_overlapping(
673660
left: TypedDictType, right: TypedDictType, is_overlapping: Callable[[Type, Type], bool]
674661
) -> 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)