@@ -1373,13 +1373,13 @@ else:
13731373 reveal_type(val) # N: Revealed type is "None"
13741374
13751375if val in (None,):
1376- reveal_type(val) # N: Revealed type is "__main__.A | None"
1376+ reveal_type(val) # N: Revealed type is "None"
13771377else:
1378- reveal_type(val) # N: Revealed type is "__main__.A | None "
1378+ reveal_type(val) # N: Revealed type is "__main__.A"
13791379if val not in (None,):
1380- reveal_type(val) # N: Revealed type is "__main__.A | None "
1380+ reveal_type(val) # N: Revealed type is "__main__.A"
13811381else:
1382- reveal_type(val) # N: Revealed type is "__main__.A | None"
1382+ reveal_type(val) # N: Revealed type is "None"
13831383
13841384class Hmm:
13851385 def __eq__(self, other) -> bool: ...
@@ -2315,9 +2315,8 @@ def f(x: str | int) -> None:
23152315 y = x
23162316
23172317 if x in ["x"]:
2318- # TODO: we should fix this reveal https://github.com/python/mypy/issues/3229
2319- reveal_type(x) # N: Revealed type is "builtins.str | builtins.int"
2320- y = x # E: Incompatible types in assignment (expression has type "str | int", variable has type "str")
2318+ reveal_type(x) # N: Revealed type is "builtins.str"
2319+ y = x
23212320 z = x
23222321 z = y
23232322[builtins fixtures/primitives.pyi]
@@ -2838,3 +2837,86 @@ class X:
28382837 reveal_type(self.y) # N: Revealed type is "builtins.list[builtins.str]"
28392838 self.y[0].does_not_exist # E: "str" has no attribute "does_not_exist"
28402839[builtins fixtures/dict.pyi]
2840+
2841+
2842+ [case testTypeNarrowingStringInLiteralContainer]
2843+ # flags: --strict-equality --warn-unreachable
2844+ from typing import Literal
2845+
2846+ def narrow_tuple(x: str, t: tuple[Literal['a', 'b']]):
2847+ if x in t:
2848+ reveal_type(x) # N: Revealed type is "Literal['a'] | Literal['b']"
2849+ else:
2850+ reveal_type(x) # N: Revealed type is "builtins.str"
2851+
2852+ if x not in t:
2853+ reveal_type(x) # N: Revealed type is "builtins.str"
2854+ else:
2855+ reveal_type(x) # N: Revealed type is "Literal['a'] | Literal['b']"
2856+
2857+ def narrow_homo_tuple(x: str, t: tuple[Literal['a', 'b'], ...]):
2858+ if x in t:
2859+ reveal_type(x) # N: Revealed type is "Literal['a'] | Literal['b']"
2860+ else:
2861+ reveal_type(x) # N: Revealed type is "builtins.str"
2862+
2863+ def narrow_list(x: str, t: list[Literal['a', 'b']]):
2864+ if x in t:
2865+ reveal_type(x) # N: Revealed type is "Literal['a'] | Literal['b']"
2866+ else:
2867+ reveal_type(x) # N: Revealed type is "builtins.str"
2868+
2869+ def narrow_set(x: str, t: set[Literal['a', 'b']]):
2870+ if x in t:
2871+ reveal_type(x) # N: Revealed type is "Literal['a'] | Literal['b']"
2872+ else:
2873+ reveal_type(x) # N: Revealed type is "builtins.str"
2874+ [builtins fixtures/primitives.pyi]
2875+
2876+
2877+ [case testNarrowingLiteralInLiteralContainer]
2878+ # flags: --strict-equality --warn-unreachable
2879+ from typing import Literal
2880+
2881+ def narrow_tuple(x: Literal['c'], overlap: list[Literal['b', 'c']], no_overlap: list[Literal['a', 'b']]):
2882+ if x in overlap:
2883+ reveal_type(x) # N: Revealed type is "Literal['c']"
2884+ else:
2885+ reveal_type(x) # N: Revealed type is "Literal['c']"
2886+
2887+ if x in no_overlap:
2888+ reveal_type(x) # N: Revealed type is "Literal['c']"
2889+ else:
2890+ reveal_type(x) # N: Revealed type is "Literal['c']"
2891+ [builtins fixtures/tuple.pyi]
2892+
2893+ [case testTypeNarrowingUnionInContainer]
2894+ # flags: --strict-equality --warn-unreachable
2895+ from typing import Union, Literal
2896+
2897+ def f1(x: Union[str, float], t1: list[Literal['a', 'b']], t2: list[str]):
2898+ if x in t1:
2899+ reveal_type(x) # N: Revealed type is "Literal['a'] | Literal['b']"
2900+ else:
2901+ reveal_type(x) # N: Revealed type is "builtins.str | builtins.float"
2902+
2903+ if x in t2:
2904+ reveal_type(x) # N: Revealed type is "builtins.str"
2905+ else:
2906+ reveal_type(x) # N: Revealed type is "builtins.str | builtins.float"
2907+ [builtins fixtures/primitives.pyi]
2908+
2909+ [case testNarrowAnyWithEqualityOrContainment]
2910+ # https://github.com/python/mypy/issues/17841
2911+ from typing import Any
2912+
2913+ def f1(x: Any) -> None:
2914+ if x is not None and x not in ["x"]:
2915+ return
2916+ reveal_type(x) # N: Revealed type is "Any"
2917+
2918+ def f2(x: Any) -> None:
2919+ if x is not None and x != "x":
2920+ return
2921+ reveal_type(x) # N: Revealed type is "Any"
2922+ [builtins fixtures/tuple.pyi]
0 commit comments