@@ -1065,6 +1065,84 @@ def f(x: Custom, y: CustomSub):
10651065 reveal_type(y) # N: Revealed type is "__main__.CustomSub"
10661066[builtins fixtures/tuple.pyi]
10671067
1068+ [case testNarrowingCustomEqualityGeneric]
1069+ # flags: --strict-equality --warn-unreachable
1070+ from __future__ import annotations
1071+ from typing import Union
1072+
1073+ class Custom:
1074+ def __eq__(self, other: object) -> bool:
1075+ raise
1076+
1077+ class Default: ...
1078+
1079+ def f(x: list[Custom] | Default, y: list[int]):
1080+ if x == y: # E: Non-overlapping equality check (left operand type: "list[Custom] | Default", right operand type: "list[int]")
1081+ reveal_type(x) # N: Revealed type is "builtins.list[__main__.Custom]"
1082+ reveal_type(y) # N: Revealed type is "builtins.list[builtins.int]"
1083+ else:
1084+ reveal_type(x) # N: Revealed type is "builtins.list[__main__.Custom] | __main__.Default"
1085+ reveal_type(y) # N: Revealed type is "builtins.list[builtins.int]"
1086+
1087+ f([], [])
1088+
1089+ def g(x: list[Custom] | Default, y: list[int] | list[Default]):
1090+ if x == y: # E: Non-overlapping equality check (left operand type: "list[Custom] | Default", right operand type: "list[int] | list[Default]")
1091+ reveal_type(x) # N: Revealed type is "builtins.list[__main__.Custom]"
1092+ reveal_type(y) # N: Revealed type is "builtins.list[builtins.int] | builtins.list[__main__.Default]"
1093+ else:
1094+ reveal_type(x) # N: Revealed type is "builtins.list[__main__.Custom] | __main__.Default"
1095+ reveal_type(y) # N: Revealed type is "builtins.list[builtins.int] | builtins.list[__main__.Default]"
1096+
1097+ listcustom_or_default = Union[list[Custom], Default]
1098+ listint_or_default = Union[list[int], list[Default]]
1099+
1100+ def h(x: listcustom_or_default, y: listint_or_default):
1101+ if x == y: # E: Non-overlapping equality check (left operand type: "list[Custom] | Default", right operand type: "list[int] | list[Default]")
1102+ reveal_type(x) # N: Revealed type is "builtins.list[__main__.Custom]"
1103+ reveal_type(y) # N: Revealed type is "builtins.list[builtins.int] | builtins.list[__main__.Default]"
1104+ else:
1105+ reveal_type(x) # N: Revealed type is "builtins.list[__main__.Custom] | __main__.Default"
1106+ reveal_type(y) # N: Revealed type is "builtins.list[builtins.int] | builtins.list[__main__.Default]"
1107+ [builtins fixtures/list.pyi]
1108+
1109+ [case testNarrowingRecursiveCallable]
1110+ # flags: --strict-equality --warn-unreachable
1111+ from __future__ import annotations
1112+ from typing import Callable
1113+
1114+ class A: ...
1115+ class B: ...
1116+
1117+ T = Callable[[A], "S"]
1118+ S = Callable[[B], "T"]
1119+
1120+ def f(x: S, y: T):
1121+ if x == y: # E: Unsupported left operand type for == ("Callable[[B], T]")
1122+ reveal_type(x) # N: Revealed type is "def (__main__.B) -> def (__main__.A) -> ..."
1123+ reveal_type(y) # N: Revealed type is "def (__main__.A) -> def (__main__.B) -> ..."
1124+ else:
1125+ reveal_type(x) # N: Revealed type is "def (__main__.B) -> def (__main__.A) -> ..."
1126+ reveal_type(y) # N: Revealed type is "def (__main__.A) -> def (__main__.B) -> ..."
1127+ [builtins fixtures/tuple.pyi]
1128+
1129+ [case testNarrowingRecursiveUnion]
1130+ # flags: --strict-equality --warn-unreachable
1131+ from __future__ import annotations
1132+ from typing import Union
1133+
1134+ class A: ...
1135+ class B: ...
1136+
1137+ T = Union[A, "S"]
1138+ S = Union[B, "T"] # E: Invalid recursive alias: a union item of itself
1139+
1140+ def f(x: S, y: T):
1141+ if x == y:
1142+ reveal_type(x) # N: Revealed type is "Any"
1143+ reveal_type(y) # N: Revealed type is "__main__.A | Any"
1144+ [builtins fixtures/tuple.pyi]
1145+
10681146[case testNarrowingUnreachableCases]
10691147# flags: --strict-equality --warn-unreachable
10701148from typing import Literal, Union
0 commit comments