Skip to content

Commit

Permalink
Fix recursion issue with nested instances and unions (#9663)
Browse files Browse the repository at this point in the history
* Fix recursion issue with nested instances and unions

* Change to use `==` in `is_protocol_implementation`

* Add test that verifies Union[a, b] == Union[b, a]

Co-authored-by: Shantanu <[email protected]>
  • Loading branch information
Peilonrayz and hauntsaninja authored Aug 4, 2021
1 parent 082c937 commit 7438158
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 2 deletions.
3 changes: 1 addition & 2 deletions mypy/subtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -547,8 +547,7 @@ def f(self) -> A: ...
return False
assuming = right.type.assuming_proper if proper_subtype else right.type.assuming
for (l, r) in reversed(assuming):
if (mypy.sametypes.is_same_type(l, left)
and mypy.sametypes.is_same_type(r, right)):
if l == left and r == right:
return True
with pop_on_exit(assuming, left, right):
for member in right.type.protocol_members:
Expand Down
2 changes: 2 additions & 0 deletions mypy/test/testtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -1055,6 +1055,7 @@ def setUp(self) -> None:
self.fx = TypeFixture()

def test_literal_type(self) -> None:
a = self.fx.a
b = self.fx.b # Reminder: b is a subclass of a

lit1 = self.fx.lit1
Expand All @@ -1064,6 +1065,7 @@ def test_literal_type(self) -> None:
self.assert_same(lit1, lit1)
self.assert_same(UnionType([lit1, lit2]), UnionType([lit1, lit2]))
self.assert_same(UnionType([lit1, lit2]), UnionType([lit2, lit1]))
self.assert_same(UnionType([a, b]), UnionType([b, a]))
self.assert_not_same(lit1, b)
self.assert_not_same(lit1, lit2)
self.assert_not_same(lit1, lit3)
Expand Down
97 changes: 97 additions & 0 deletions test-data/unit/check-unions.test
Original file line number Diff line number Diff line change
Expand Up @@ -1059,3 +1059,100 @@ x: Union[None, Any]
y: Union[int, None]
reveal_type(f(x, y)) # N: Revealed type is "Union[None, Any, builtins.int]"
reveal_type(f(y, x)) # N: Revealed type is "Union[builtins.int, None, Any]"

[case testNestedProtocolUnions]
from typing import Union, Iterator, Iterable
def foo(
values: Union[
Iterator[Union[
Iterator[Union[Iterator[int], Iterable[int]]],
Iterable[Union[Iterator[int], Iterable[int]]],
]],
Iterable[Union[
Iterator[Union[Iterator[int], Iterable[int]]],
Iterable[Union[Iterator[int], Iterable[int]]],
]],
]
) -> Iterator[int]:
for i in values:
for j in i:
for k in j:
yield k
foo([[[1]]])
[builtins fixtures/list.pyi]

[case testNestedProtocolGenericUnions]
from typing import Union, Iterator, List
def foo(
values: Union[
Iterator[Union[
Iterator[Union[Iterator[int], List[int]]],
List[Union[Iterator[int], List[int]]],
]],
List[Union[
Iterator[Union[Iterator[int], List[int]]],
List[Union[Iterator[int], List[int]]],
]],
]
) -> Iterator[int]:
for i in values:
for j in i:
for k in j:
yield k
foo([[[1]]])
[builtins fixtures/list.pyi]

[case testNestedProtocolGenericUnionsDeep]
from typing import TypeVar, Union, Iterator, List
T = TypeVar("T")
Iter = Union[Iterator[T], List[T]]
def foo(
values: Iter[Iter[Iter[Iter[Iter[int]]]]],
) -> Iterator[int]:
for i in values:
for j in i:
for k in j:
for l in k:
for m in l:
yield m
foo([[[[[1]]]]])
[builtins fixtures/list.pyi]

[case testNestedInstanceUnsimplifiedUnion]
from typing import TypeVar, Union, Iterator, List, Any
T = TypeVar("T")

Iter = Union[Iterator[T], List[T]]
def foo(
values: Iter[Union[Any, Any]],
) -> Iterator[Any]:
for i in values:
yield i
foo([1])
[builtins fixtures/list.pyi]

[case testNestedInstanceTypeAlias]
from typing import TypeVar, Union, Iterator, List, Any
T = TypeVar("T")

Iter = Union[Iterator[T], List[T]]
def foo(
values: Iter["Any"],
) -> Iterator[Any]:
for i in values:
yield i
foo([1])
[builtins fixtures/list.pyi]

[case testNestedInstanceTypeAliasUnsimplifiedUnion]
from typing import TypeVar, Union, Iterator, List, Any
T = TypeVar("T")

Iter = Union[Iterator[T], List[T]]
def foo(
values: Iter["Union[Any, Any]"],
) -> Iterator[Any]:
for i in values:
yield i
foo([1])
[builtins fixtures/list.pyi]

0 comments on commit 7438158

Please sign in to comment.