From 39a41b1f56a18a9588c7eca02e7cd47e1f48acf8 Mon Sep 17 00:00:00 2001 From: David Fisher Date: Thu, 29 Sep 2016 17:03:10 -0700 Subject: [PATCH 1/2] Fix make_simplified_union interaction with Any make_simplified_union had two incorrect interactions with Any that this fixes: 1) Any unions containing Any were simplified to Any, which is incorrect. 2) Any classes that inherited from Any would be removed from the union by the subclass simplification (because subclasses of Any are considered subclasses of all other classes due to subtype/compatible with confusion). Note that `Union`s call make_union and not make_simplified_union, so this doesn't change their behavior directly (unless they interact with something else which causes them to be simplified, like being part of an `Optional`). --- mypy/types.py | 7 +++---- test-data/unit/check-optional.test | 7 +++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/mypy/types.py b/mypy/types.py index b97937526ae4..853aab787804 100644 --- a/mypy/types.py +++ b/mypy/types.py @@ -858,9 +858,6 @@ def make_simplified_union(items: List[Type], line: int = -1, column: int = -1) - all_items.append(typ) items = all_items - if any(isinstance(typ, AnyType) for typ in items): - return AnyType() - from mypy.subtypes import is_subtype removed = set() # type: Set[int] for i, ti in enumerate(items): @@ -868,7 +865,9 @@ def make_simplified_union(items: List[Type], line: int = -1, column: int = -1) - # Keep track of the truishness info for deleted subtypes which can be relevant cbt = cbf = False for j, tj in enumerate(items): - if i != j and is_subtype(tj, ti): + tj_is_anylike = (isinstance(tj, AnyType) or + (isinstance(tj, Instance) and tj.type.fallback_to_any)) + if i != j and is_subtype(tj, ti) and not tj_is_anylike: removed.add(j) cbt = cbt or tj.can_be_true cbf = cbf or tj.can_be_false diff --git a/test-data/unit/check-optional.test b/test-data/unit/check-optional.test index 010ab8f9eef5..4b8f3104256d 100644 --- a/test-data/unit/check-optional.test +++ b/test-data/unit/check-optional.test @@ -428,3 +428,10 @@ x + 1 [out] main:2: note: In module imported here: tmp/a.py:3: error: Unsupported left operand type for + (some union) + +[case testOptionalFallbackToNone] +from typing import Any, Optional +class C(Any): + pass +x = None # type: Optional[C] +x.foo() # E: Some element of union has no attribute "foo" From 786877a744de8cca0cfd6794b958b1fa56faa738 Mon Sep 17 00:00:00 2001 From: David Fisher Date: Mon, 3 Oct 2016 15:38:53 -0700 Subject: [PATCH 2/2] Add clarifying comment --- mypy/types.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mypy/types.py b/mypy/types.py index 853aab787804..1952585d58dd 100644 --- a/mypy/types.py +++ b/mypy/types.py @@ -865,6 +865,8 @@ def make_simplified_union(items: List[Type], line: int = -1, column: int = -1) - # Keep track of the truishness info for deleted subtypes which can be relevant cbt = cbf = False for j, tj in enumerate(items): + # Attempt to only combine true subtypes by avoiding types containing Any. + # TODO: Properly exclude generics and functions. tj_is_anylike = (isinstance(tj, AnyType) or (isinstance(tj, Instance) and tj.type.fallback_to_any)) if i != j and is_subtype(tj, ti) and not tj_is_anylike: