From 6b6ebbfc7ff230a7654ea0f450bcbef327634b58 Mon Sep 17 00:00:00 2001 From: Peilonrayz Date: Fri, 30 Oct 2020 00:05:41 +0000 Subject: [PATCH 1/3] Fix recursion issue with nested instances and unions --- mypy/sametypes.py | 1 - test-data/unit/check-unions.test | 57 ++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/mypy/sametypes.py b/mypy/sametypes.py index 024333a13ec8..834cadeceadd 100644 --- a/mypy/sametypes.py +++ b/mypy/sametypes.py @@ -25,7 +25,6 @@ def is_same_type(left: Type, right: Type) -> bool: # types can be simplified to non-union types such as Union[int, bool] # -> int. It would be nice if we always had simplified union types but # this is currently not the case, though it often is. - left = simplify_union(left) right = simplify_union(right) return left.accept(SameTypeVisitor(right)) diff --git a/test-data/unit/check-unions.test b/test-data/unit/check-unions.test index a785b28737e6..4f0adb00a156 100644 --- a/test-data/unit/check-unions.test +++ b/test-data/unit/check-unions.test @@ -1059,3 +1059,60 @@ 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] From 616f0f6f06031a72d05e6451f51f7ab0142db283 Mon Sep 17 00:00:00 2001 From: Peilonrayz Date: Wed, 4 Nov 2020 20:00:50 +0000 Subject: [PATCH 2/3] Change to use `==` in `is_protocol_implementation` --- mypy/sametypes.py | 1 + mypy/subtypes.py | 3 +-- test-data/unit/check-unions.test | 42 +++++++++++++++++++++++++++++++- 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/mypy/sametypes.py b/mypy/sametypes.py index 834cadeceadd..024333a13ec8 100644 --- a/mypy/sametypes.py +++ b/mypy/sametypes.py @@ -25,6 +25,7 @@ def is_same_type(left: Type, right: Type) -> bool: # types can be simplified to non-union types such as Union[int, bool] # -> int. It would be nice if we always had simplified union types but # this is currently not the case, though it often is. + left = simplify_union(left) right = simplify_union(right) return left.accept(SameTypeVisitor(right)) diff --git a/mypy/subtypes.py b/mypy/subtypes.py index 81726b1f9884..22e6e9366835 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -524,8 +524,7 @@ def f(self) -> A: ... TypeState.record_protocol_subtype_check(left.type, right.type) 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: diff --git a/test-data/unit/check-unions.test b/test-data/unit/check-unions.test index 4f0adb00a156..ac611ffbcd56 100644 --- a/test-data/unit/check-unions.test +++ b/test-data/unit/check-unions.test @@ -1107,7 +1107,8 @@ 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]: + values: Iter[Iter[Iter[Iter[Iter[int]]]]], +) -> Iterator[int]: for i in values: for j in i: for k in j: @@ -1116,3 +1117,42 @@ def foo( 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] From 99cbcd999ae167ef4b5100f0332258dd74a8a29d Mon Sep 17 00:00:00 2001 From: Peilonrayz Date: Tue, 29 Dec 2020 15:00:31 +0000 Subject: [PATCH 3/3] Add test that verifies Union[a, b] == Union[b, a] --- mypy/test/testtypes.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mypy/test/testtypes.py b/mypy/test/testtypes.py index c65bfc7b9418..0230c0453043 100644 --- a/mypy/test/testtypes.py +++ b/mypy/test/testtypes.py @@ -1010,6 +1010,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 d = self.fx.d @@ -1020,6 +1021,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)