@@ -1364,13 +1364,13 @@ class A: ...
13641364val: Optional[A]
13651365
13661366if val == None:
1367- reveal_type(val) # N: Revealed type is "__main__.A | None"
1367+ reveal_type(val) # N: Revealed type is "None"
13681368else:
13691369 reveal_type(val) # N: Revealed type is "__main__.A"
13701370if val != None:
13711371 reveal_type(val) # N: Revealed type is "__main__.A"
13721372else:
1373- reveal_type(val) # N: Revealed type is "__main__.A | None"
1373+ reveal_type(val) # N: Revealed type is "None"
13741374
13751375if val in (None,):
13761376 reveal_type(val) # N: Revealed type is "__main__.A | None"
@@ -1380,6 +1380,19 @@ if val not in (None,):
13801380 reveal_type(val) # N: Revealed type is "__main__.A | None"
13811381else:
13821382 reveal_type(val) # N: Revealed type is "__main__.A | None"
1383+
1384+ class Hmm:
1385+ def __eq__(self, other) -> bool: ...
1386+
1387+ hmm: Optional[Hmm]
1388+ if hmm == None:
1389+ reveal_type(hmm) # N: Revealed type is "__main__.Hmm | None"
1390+ else:
1391+ reveal_type(hmm) # N: Revealed type is "__main__.Hmm"
1392+ if hmm != None:
1393+ reveal_type(hmm) # N: Revealed type is "__main__.Hmm"
1394+ else:
1395+ reveal_type(hmm) # N: Revealed type is "__main__.Hmm | None"
13831396[builtins fixtures/primitives.pyi]
13841397
13851398[case testNarrowingWithTupleOfTypes]
@@ -2277,13 +2290,13 @@ def f4(x: SE) -> None:
22772290# https://github.com/python/mypy/issues/17864
22782291def f(x: str | int) -> None:
22792292 if x == "x":
2280- reveal_type(x) # N: Revealed type is "builtins.str | builtins.int "
2293+ reveal_type(x) # N: Revealed type is "builtins.str"
22812294 y = x
22822295
22832296 if x in ["x"]:
22842297 # TODO: we should fix this reveal https://github.com/python/mypy/issues/3229
22852298 reveal_type(x) # N: Revealed type is "builtins.str | builtins.int"
2286- y = x
2299+ y = x # E: Incompatible types in assignment (expression has type "str | int", variable has type "str")
22872300 z = x
22882301 z = y
22892302[builtins fixtures/primitives.pyi]
@@ -2699,3 +2712,97 @@ reveal_type(t.foo) # N: Revealed type is "__main__.D"
26992712t.foo = C1()
27002713reveal_type(t.foo) # N: Revealed type is "__main__.C"
27012714[builtins fixtures/property.pyi]
2715+
2716+ [case testNarrowingNotImplemented]
2717+ from __future__ import annotations
2718+ from typing_extensions import Self
2719+
2720+ class X:
2721+ def __divmod__(self, other: Self | int) -> tuple[Self, Self]: ...
2722+
2723+ def __floordiv__(self, other: Self | int) -> Self:
2724+ qr = self.__divmod__(other)
2725+ if qr is NotImplemented:
2726+ return NotImplemented
2727+ return qr[0]
2728+ [builtins fixtures/notimplemented.pyi]
2729+
2730+
2731+ [case testNarrowingBooleans]
2732+ # flags: --warn-return-any
2733+ from typing import Any
2734+
2735+ def foo(x: dict[str, Any]) -> bool:
2736+ if x.get("event") is False:
2737+ return False
2738+ if x.get("event") is True:
2739+ return True
2740+ raise
2741+ [builtins fixtures/dict.pyi]
2742+
2743+
2744+ [case testNarrowingTypeObjects]
2745+ from __future__ import annotations
2746+ from typing import Callable, Any, TypeVar, Generic, Protocol
2747+ _T_co = TypeVar('_T_co', covariant=True)
2748+
2749+ class Boxxy(Protocol[_T_co]):
2750+ def get_box(self) -> _T_co: ...
2751+
2752+ class TupleLike(Generic[_T_co]):
2753+ def __init__(self, iterable: Boxxy[_T_co], /) -> None:
2754+ raise
2755+
2756+ class Box1(Generic[_T_co]):
2757+ def __init__(self, content: _T_co, /) -> None: ...
2758+ def get_box(self) -> _T_co: raise
2759+
2760+ class Box2(Generic[_T_co]):
2761+ def __init__(self, content: _T_co, /) -> None: ...
2762+ def get_box(self) -> _T_co: raise
2763+
2764+ def get_type(setting_name: str) -> Callable[[Box1], Any] | type[Any]:
2765+ raise
2766+
2767+ def main(key: str):
2768+ existing_value_type = get_type(key)
2769+ if existing_value_type is TupleLike:
2770+ reveal_type(TupleLike) # N: Revealed type is "def [_T_co] (__main__.Boxxy[_T_co`1]) -> __main__.TupleLike[_T_co`1]"
2771+ TupleLike(Box2("str"))
2772+ [builtins fixtures/tuple.pyi]
2773+
2774+ [case testNarrowingCollections]
2775+ # flags: --warn-unreachable
2776+ from typing import cast
2777+
2778+ class X:
2779+ def __init__(self) -> None:
2780+ self.x: dict[str, str] = {}
2781+ self.y: list[str] = []
2782+
2783+ def xxx(self) -> None:
2784+ if self.x == {}:
2785+ reveal_type(self.x) # N: Revealed type is "builtins.dict[builtins.str, builtins.str]"
2786+ self.x["asdf"]
2787+
2788+ if self.x == dict():
2789+ reveal_type(self.x) # N: Revealed type is "builtins.dict[builtins.str, builtins.str]"
2790+ self.x["asdf"]
2791+
2792+ if self.x == cast(dict[int, int], {}):
2793+ reveal_type(self.x) # N: Revealed type is "builtins.dict[builtins.str, builtins.str]"
2794+ self.x["asdf"]
2795+
2796+ def yyy(self) -> None:
2797+ if self.y == []:
2798+ reveal_type(self.y) # N: Revealed type is "builtins.list[builtins.str]"
2799+ self.y[0].does_not_exist # E: "str" has no attribute "does_not_exist"
2800+
2801+ if self.y == list():
2802+ reveal_type(self.y) # N: Revealed type is "builtins.list[builtins.str]"
2803+ self.y[0].does_not_exist # E: "str" has no attribute "does_not_exist"
2804+
2805+ if self.y == cast(list[int], []):
2806+ reveal_type(self.y) # N: Revealed type is "builtins.list[builtins.str]"
2807+ self.y[0].does_not_exist # E: "str" has no attribute "does_not_exist"
2808+ [builtins fixtures/dict.pyi]
0 commit comments