Skip to content

Commit e80da8c

Browse files
authored
Fix narrowing of nested union of TypedDicts (#11204)
The code in refine_parent_types() bailed out when it encountered something other than a TypedDict in the union, including a nested union of TypedDicts. This caused the narrowing to fail. Fix it by making it iterate over the flattened union items. Fixes #9308.
1 parent 02b9694 commit e80da8c

File tree

2 files changed

+30
-2
lines changed

2 files changed

+30
-2
lines changed

mypy/checker.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4676,8 +4676,7 @@ def replay_lookup(new_parent_type: ProperType) -> Optional[Type]:
46764676
# Take each element in the parent union and replay the original lookup procedure
46774677
# to figure out which parents are compatible.
46784678
new_parent_types = []
4679-
for item in parent_type.items:
4680-
item = get_proper_type(item)
4679+
for item in union_items(parent_type):
46814680
member_type = replay_lookup(item)
46824681
if member_type is None:
46834682
# We were unable to obtain the member type. So, we give up on refining this

test-data/unit/check-narrowing.test

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,3 +1114,32 @@ def f(t: Type[T], a: A, b: B) -> None:
11141114
reveal_type(b) # N: Revealed type is "<nothing>"
11151115
else:
11161116
reveal_type(b) # N: Revealed type is "__main__.B"
1117+
1118+
[case testNarrowingNestedUnionOfTypedDicts]
1119+
from typing import Union
1120+
from typing_extensions import Literal, TypedDict
1121+
1122+
class A(TypedDict):
1123+
tag: Literal["A"]
1124+
a: int
1125+
1126+
class B(TypedDict):
1127+
tag: Literal["B"]
1128+
b: int
1129+
1130+
class C(TypedDict):
1131+
tag: Literal["C"]
1132+
c: int
1133+
1134+
AB = Union[A, B]
1135+
ABC = Union[AB, C]
1136+
abc: ABC
1137+
1138+
if abc["tag"] == "A":
1139+
reveal_type(abc) # N: Revealed type is "TypedDict('__main__.A', {'tag': Literal['A'], 'a': builtins.int})"
1140+
elif abc["tag"] == "C":
1141+
reveal_type(abc) # N: Revealed type is "TypedDict('__main__.C', {'tag': Literal['C'], 'c': builtins.int})"
1142+
else:
1143+
reveal_type(abc) # N: Revealed type is "TypedDict('__main__.B', {'tag': Literal['B'], 'b': builtins.int})"
1144+
1145+
[builtins fixtures/primitives.pyi]

0 commit comments

Comments
 (0)