From d3d50e82bd6bcf3ff2c05e3fc586caa7af7f89b6 Mon Sep 17 00:00:00 2001 From: Ben Kuhn Date: Mon, 6 Mar 2017 19:17:20 -0500 Subject: [PATCH 1/5] Add failing test case --- test-data/unit/check-optional.test | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test-data/unit/check-optional.test b/test-data/unit/check-optional.test index 7b492e7f53ac..6bff206bdf0d 100644 --- a/test-data/unit/check-optional.test +++ b/test-data/unit/check-optional.test @@ -77,6 +77,15 @@ else: reveal_type(x) # E: Revealed type is 'builtins.int' [builtins fixtures/bool.pyi] +[case testAnyCanBeNone] +from typing import Optional, Any +x = None # type: Any +if x is None: + reveal_type(x) # E: Revealed type is 'builtins.None' +else: + reveal_type(x) # E: Revealed type is 'Any' +[builtins fixtures/bool.pyi] + [case testOrCases] from typing import Optional x = None # type: Optional[str] From d4a7e070990cb4ec87a1271f965e6e4384f9bc5b Mon Sep 17 00:00:00 2001 From: Ben Kuhn Date: Mon, 6 Mar 2017 19:24:00 -0500 Subject: [PATCH 2/5] This seems to work?? --- mypy/meet.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mypy/meet.py b/mypy/meet.py index 7aa479c0eefc..af112613cabd 100644 --- a/mypy/meet.py +++ b/mypy/meet.py @@ -69,6 +69,9 @@ class C(A, B): ... TODO: Don't consider callables always overlapping. TODO: Don't consider type variables with values always overlapping. """ + # If either side is Any, there is definitely overlap. + if isinstance(t, AnyType) or isinstance(s, AnyType): + return True # Since we are effectively working with the erased types, we only # need to handle occurrences of TypeVarType at the top level. if isinstance(t, TypeVarType): From 5073e02cb242b67b0c29759bf48a025ad16bec8c Mon Sep 17 00:00:00 2001 From: Ben Kuhn Date: Mon, 6 Mar 2017 21:16:03 -0500 Subject: [PATCH 3/5] Default to a smaller-scoped fix --- mypy/meet.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/mypy/meet.py b/mypy/meet.py index af112613cabd..984a9ba3db84 100644 --- a/mypy/meet.py +++ b/mypy/meet.py @@ -69,9 +69,18 @@ class C(A, B): ... TODO: Don't consider callables always overlapping. TODO: Don't consider type variables with values always overlapping. """ - # If either side is Any, there is definitely overlap. - if isinstance(t, AnyType) or isinstance(s, AnyType): - return True + # TODO(benkuhn): another option for the fix would be to add the following + # lines here: + + # # Any overlaps with everything + # if isinstance(t, AnyType) or isinstance(s, AnyType): + # return True + + # This passes all the tests, and if I understand the mechanics of type + # overlap correctly, this would prevent similar classes of bugs from + # occurring in the future. But I'm guessing that there's a good reason these + # lines aren't already there, so I'm defaulting to a smaller-scoped fix. + # Since we are effectively working with the erased types, we only # need to handle occurrences of TypeVarType at the top level. if isinstance(t, TypeVarType): @@ -109,6 +118,8 @@ class C(A, B): ... else: return False if experiments.STRICT_OPTIONAL: + if isinstance(t, AnyType) or isinstance(s, AnyType): + return True if isinstance(t, NoneTyp) != isinstance(s, NoneTyp): # NoneTyp does not overlap with other non-Union types under strict Optional checking return False From 1756c746620e84a1af469e444fad2e3fd11f58e9 Mon Sep 17 00:00:00 2001 From: Ben Kuhn Date: Mon, 6 Mar 2017 21:32:59 -0500 Subject: [PATCH 4/5] Rewrap to 100 chars --- mypy/meet.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/mypy/meet.py b/mypy/meet.py index 984a9ba3db84..f6e46aa5c2cd 100644 --- a/mypy/meet.py +++ b/mypy/meet.py @@ -69,17 +69,16 @@ class C(A, B): ... TODO: Don't consider callables always overlapping. TODO: Don't consider type variables with values always overlapping. """ - # TODO(benkuhn): another option for the fix would be to add the following - # lines here: + # TODO(benkuhn): another option for the fix would be to add the following lines here: # # Any overlaps with everything # if isinstance(t, AnyType) or isinstance(s, AnyType): # return True - # This passes all the tests, and if I understand the mechanics of type - # overlap correctly, this would prevent similar classes of bugs from - # occurring in the future. But I'm guessing that there's a good reason these - # lines aren't already there, so I'm defaulting to a smaller-scoped fix. + # This passes all the tests locally, and if I understand the mechanics of type overlap + # correctly, this would prevent similar classes of bugs from occurring in the future. But I'm + # guessing that there's a good reason these lines aren't already there, so I'm defaulting to a + # smaller-scoped fix. # Since we are effectively working with the erased types, we only # need to handle occurrences of TypeVarType at the top level. From 7410a21d239a3b20e7ec4b765392314b2a445895 Mon Sep 17 00:00:00 2001 From: Ben Kuhn Date: Wed, 15 Mar 2017 10:50:04 -0500 Subject: [PATCH 5/5] Move AnyType check to toplevel --- mypy/meet.py | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/mypy/meet.py b/mypy/meet.py index f6e46aa5c2cd..03b8d1b58cbc 100644 --- a/mypy/meet.py +++ b/mypy/meet.py @@ -69,16 +69,9 @@ class C(A, B): ... TODO: Don't consider callables always overlapping. TODO: Don't consider type variables with values always overlapping. """ - # TODO(benkuhn): another option for the fix would be to add the following lines here: - - # # Any overlaps with everything - # if isinstance(t, AnyType) or isinstance(s, AnyType): - # return True - - # This passes all the tests locally, and if I understand the mechanics of type overlap - # correctly, this would prevent similar classes of bugs from occurring in the future. But I'm - # guessing that there's a good reason these lines aren't already there, so I'm defaulting to a - # smaller-scoped fix. + # Any overlaps with everything + if isinstance(t, AnyType) or isinstance(s, AnyType): + return True # Since we are effectively working with the erased types, we only # need to handle occurrences of TypeVarType at the top level. @@ -117,8 +110,6 @@ class C(A, B): ... else: return False if experiments.STRICT_OPTIONAL: - if isinstance(t, AnyType) or isinstance(s, AnyType): - return True if isinstance(t, NoneTyp) != isinstance(s, NoneTyp): # NoneTyp does not overlap with other non-Union types under strict Optional checking return False