Skip to content

Commit

Permalink
Fix narrowing of nested union of TypedDicts
Browse files Browse the repository at this point in the history
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 python#9308.
  • Loading branch information
bluetech committed Sep 27, 2021
1 parent 8e82171 commit f99505c
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 1 deletion.
2 changes: 1 addition & 1 deletion mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -4676,7 +4676,7 @@ def replay_lookup(new_parent_type: ProperType) -> Optional[Type]:
# Take each element in the parent union and replay the original lookup procedure
# to figure out which parents are compatible.
new_parent_types = []
for item in parent_type.items:
for item in union_items(parent_type):
item = get_proper_type(item)
member_type = replay_lookup(item)
if member_type is None:
Expand Down
29 changes: 29 additions & 0 deletions test-data/unit/check-narrowing.test
Original file line number Diff line number Diff line change
Expand Up @@ -1093,3 +1093,32 @@ def f(t: Type[T], a: A, b: B) -> None:
reveal_type(b) # N: Revealed type is "<nothing>"
else:
reveal_type(b) # N: Revealed type is "__main__.B"

[case testNarrowingNestedUnionOfTypedDicts]
from typing import Union
from typing_extensions import Literal, TypedDict

class A(TypedDict):
tag: Literal["A"]
a: int

class B(TypedDict):
tag: Literal["B"]
b: int

class C(TypedDict):
tag: Literal["C"]
c: int

AB = Union[A, B]
ABC = Union[AB, C]
abc: ABC

if abc["tag"] == "A":
reveal_type(abc) # N: Revealed type is "TypedDict('__main__.A', {'tag': Literal['A'], 'a': builtins.int})"
elif abc["tag"] == "C":
reveal_type(abc) # N: Revealed type is "TypedDict('__main__.C', {'tag': Literal['C'], 'c': builtins.int})"
else:
reveal_type(abc) # N: Revealed type is "TypedDict('__main__.B', {'tag': Literal['B'], 'b': builtins.int})"

[builtins fixtures/primitives.pyi]

0 comments on commit f99505c

Please sign in to comment.