From 60571780fec9b57a4c81885afee47df0d6d0f837 Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Wed, 8 Feb 2017 00:14:35 +0100 Subject: [PATCH 1/7] Treat type equivalent to Type[Any] --- mypy/subtypes.py | 2 ++ test-data/unit/check-classes.test | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/mypy/subtypes.py b/mypy/subtypes.py index c91250edc1ab..4ce680c73375 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -136,6 +136,8 @@ def visit_instance(self, left: Instance) -> bool: right = self.right if isinstance(right, TupleType) and right.fallback.type.is_enum: return is_subtype(left, right.fallback) + if isinstance(right, TypeType): + return left.type.fullname() == 'builtins.type' and isinstance(right.item, AnyType) if isinstance(right, Instance): if left.type._promote and is_subtype( left.type._promote, self.right, self.check_type_parameter, diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index 820b3a42070a..217d23ff5eb5 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -2109,6 +2109,23 @@ def foo(c: Type[C], d: Type[D]) -> None: [out] main:7: error: Revealed type is 'builtins.list[Type[__main__.B]]' +[case testTypeEquivalentTypeAny] +from typing import Type, Any + +a = None # type: Type[Any] +b = a # type: type + +x = None # type: type +y = x # type: Type[Any] + +class C: ... + +p = None # type: type +q = p # type: Type[C] # E: Incompatible types in assignment (expression has type "type", variable has type Type[C]) + +[builtins fixtures/list.pyi] +[out] + [case testTypeMatchesOverloadedFunctions] from typing import Type, overload, Union From b0bd5745b43c6d3eac539b3211d72cf36cd34f90 Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Wed, 8 Feb 2017 12:32:22 +0100 Subject: [PATCH 2/7] Response to comment by @ddfisher --- mypy/subtypes.py | 14 +++++++------- mypy/test/testsubtypes.py | 2 +- test-data/unit/check-classes.test | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/mypy/subtypes.py b/mypy/subtypes.py index 4ce680c73375..5a74c30fafb2 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -52,6 +52,11 @@ def is_subtype(left: Type, right: Type, return any(is_subtype(left, item, type_parameter_checker, ignore_pos_arg_names=ignore_pos_arg_names) for item in right.items) + # Treat builtins.type the same as Type[Any] + elif is_named_instance(left, 'builtins.type'): + return is_subtype(TypeType(AnyType()), right) + elif is_named_instance(right, 'builtins.type'): + return is_subtype(left, TypeType(AnyType())) else: return left.accept(SubtypeVisitor(right, type_parameter_checker, ignore_pos_arg_names=ignore_pos_arg_names)) @@ -136,8 +141,6 @@ def visit_instance(self, left: Instance) -> bool: right = self.right if isinstance(right, TupleType) and right.fallback.type.is_enum: return is_subtype(left, right.fallback) - if isinstance(right, TypeType): - return left.type.fullname() == 'builtins.type' and isinstance(right.item, AnyType) if isinstance(right, Instance): if left.type._promote and is_subtype( left.type._promote, self.right, self.check_type_parameter, @@ -230,8 +233,7 @@ def visit_overloaded(self, left: Overloaded) -> bool: right = self.right if isinstance(right, Instance): return is_subtype(left.fallback, right) - elif isinstance(right, CallableType) or is_named_instance( - right, 'builtins.type'): + elif isinstance(right, CallableType): for item in left.items(): if is_subtype(item, right, self.check_type_parameter, ignore_pos_arg_names=self.ignore_pos_arg_names): @@ -271,9 +273,7 @@ def visit_type_type(self, left: TypeType) -> bool: if isinstance(right, CallableType): # This is unsound, we don't check the __init__ signature. return right.is_type_obj() and is_subtype(left.item, right.ret_type) - if (isinstance(right, Instance) and - right.type.fullname() in ('builtins.type', 'builtins.object')): - # Treat builtins.type the same as Type[Any]; + if is_named_instance(right, 'builtins.object'): # treat builtins.object the same as Any. return True return False diff --git a/mypy/test/testsubtypes.py b/mypy/test/testsubtypes.py index 307cb7abfebb..4121f669ada0 100644 --- a/mypy/test/testsubtypes.py +++ b/mypy/test/testsubtypes.py @@ -168,7 +168,7 @@ def test_var_arg_callable_subtyping_9(self) -> None: self.fx.callable_var_arg(0, self.fx.b, self.fx.d)) def test_type_callable_subtyping(self) -> None: - self.assert_strict_subtype( + self.assert_subtype( self.fx.callable_type(self.fx.d, self.fx.a), self.fx.type_type) self.assert_strict_subtype( diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index 217d23ff5eb5..593e570cc061 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -2121,7 +2121,7 @@ y = x # type: Type[Any] class C: ... p = None # type: type -q = p # type: Type[C] # E: Incompatible types in assignment (expression has type "type", variable has type Type[C]) +q = p # type: Type[C] [builtins fixtures/list.pyi] [out] From 7f76ebfa5f9b81782c006d9c266faa0563d5656d Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Wed, 8 Feb 2017 21:50:06 +0100 Subject: [PATCH 3/7] Add more tests --- test-data/unit/check-classes.test | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index 593e570cc061..325a0f74d010 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -2126,6 +2126,26 @@ q = p # type: Type[C] [builtins fixtures/list.pyi] [out] +[case testTypeEquivalentTypeAny] +from typing import Type, Any, TypeVar, Generic + +class C: ... +x = None # type: type +y = None # type: Type[Any] +z = None # type: Type[C] + +lst = [x, y] +reveal_type(lst) # E: Revealed type is 'builtins.list[builtins.type*]' + +T1 = TypeVar('T1', bound=type) +T2 = TypeVar('T2', bound=Type[Any]) +class C1(Generic[T1]): ... +class C2(Generic[T2]): ... + +C1[Type[Any]], C2[type] # both these sould not fail +[builtins fixtures/list.pyi] +[out] + [case testTypeMatchesOverloadedFunctions] from typing import Type, overload, Union From fbd6fee9bc1375bc14c87de599837139f19acaf9 Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Wed, 8 Feb 2017 21:51:12 +0100 Subject: [PATCH 4/7] Different name for second test --- test-data/unit/check-classes.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index 325a0f74d010..f3198dcfc23c 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -2126,7 +2126,7 @@ q = p # type: Type[C] [builtins fixtures/list.pyi] [out] -[case testTypeEquivalentTypeAny] +[case testTypeEquivalentTypeAny2] from typing import Type, Any, TypeVar, Generic class C: ... From 2dbfa3b66af08f5c883dc90c4a36bfd8ca56222e Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Wed, 8 Feb 2017 21:58:37 +0100 Subject: [PATCH 5/7] Fix a type in tests --- test-data/unit/check-classes.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index f3198dcfc23c..90419a85f2a5 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -2134,7 +2134,7 @@ x = None # type: type y = None # type: Type[Any] z = None # type: Type[C] -lst = [x, y] +lst = [x, y, z] reveal_type(lst) # E: Revealed type is 'builtins.list[builtins.type*]' T1 = TypeVar('T1', bound=type) From 6de91da06cf3caba0c911c1ea6d9775a9b53abde Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Tue, 14 Feb 2017 23:56:42 +0100 Subject: [PATCH 6/7] Fix typo --- mypy/subtypes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypy/subtypes.py b/mypy/subtypes.py index 5a0a287fc094..18034e6e4688 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -277,7 +277,7 @@ def visit_type_type(self, left: TypeType) -> bool: return is_subtype(left.item, right.item) if isinstance(right, CallableType): # This is unsound, we don't check the __init__ signature. - return right.is_type_obj() and is_subtype(left.item, right.ret_type + return right.is_type_obj() and is_subtype(left.item, right.ret_type) if isinstance(right, Instance): if right.type.fullname() == 'builtins.object': # treat builtins.object the same as Any. From 5c1205b3c85072ed50a80f72051045f5f644fad8 Mon Sep 17 00:00:00 2001 From: David Fisher Date: Mon, 13 Mar 2017 17:19:06 -0700 Subject: [PATCH 7/7] Update check-classes.test minor spelling fix in comment --- test-data/unit/check-classes.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index 5ee37fb39c50..d41f90b399fd 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -2159,7 +2159,7 @@ T2 = TypeVar('T2', bound=Type[Any]) class C1(Generic[T1]): ... class C2(Generic[T2]): ... -C1[Type[Any]], C2[type] # both these sould not fail +C1[Type[Any]], C2[type] # both these should not fail [builtins fixtures/list.pyi] [out]