From 3b3ff3098c1712fc86234f3d6802721ee3548582 Mon Sep 17 00:00:00 2001 From: elazar Date: Thu, 9 Feb 2017 10:20:01 +0200 Subject: [PATCH 1/3] Patch subtyping for metaclasses --- mypy/subtypes.py | 17 ++++++++++++----- test-data/unit/check-classes.test | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/mypy/subtypes.py b/mypy/subtypes.py index c91250edc1ab..4af105898bf3 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -151,6 +151,11 @@ def visit_instance(self, left: Instance) -> bool: return all(self.check_type_parameter(lefta, righta, tvar.variance) for lefta, righta, tvar in zip(t.args, right.args, right.type.defn.type_vars)) + if isinstance(right, TypeType): + item = right.item + if isinstance(item, TupleType): + item = item.fallback + return isinstance(item, Instance) and is_subtype(left, item.type.metaclass_type) else: return False @@ -269,11 +274,13 @@ 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]; - # treat builtins.object the same as Any. - return True + if isinstance(right, Instance): + if right.type.fullname() in ('builtins.type', 'builtins.object'): + # Treat builtins.type the same as Type[Any]; + # treat builtins.object the same as Any. + return True + item = left.item + return isinstance(item, Instance) and is_subtype(item, right.type.metaclass_type) return False diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index 820b3a42070a..a25c4b696e5c 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -2845,3 +2845,21 @@ class Concrete(metaclass=Meta): reveal_type(Concrete + X()) # E: Revealed type is 'builtins.str' Concrete + "hello" # E: Unsupported operand types for + ("Meta" and "str") + +[case testMetaclassTypeCallable] +class M(type): + x = 5 + +class A(metaclass=M): pass +reveal_type(type(A).x) # E: Revealed type is 'builtins.int' + +[case testMetaclassSelftype] +from typing import TypeVar, Type + +class M(type): pass +T = TypeVar('T', bound='A') + +class M1(M): + def foo(cls: Type[T]) -> T: ... + +class A(metaclass=M1): pass From 94a892bf6dfa40fb8b5698e1ea578a7497b86918 Mon Sep 17 00:00:00 2001 From: elazar Date: Thu, 9 Feb 2017 10:29:39 +0200 Subject: [PATCH 2/3] Oops - that was a test from a different PR --- test-data/unit/check-classes.test | 7 ------- 1 file changed, 7 deletions(-) diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index a25c4b696e5c..a0ce727998ce 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -2846,13 +2846,6 @@ class Concrete(metaclass=Meta): reveal_type(Concrete + X()) # E: Revealed type is 'builtins.str' Concrete + "hello" # E: Unsupported operand types for + ("Meta" and "str") -[case testMetaclassTypeCallable] -class M(type): - x = 5 - -class A(metaclass=M): pass -reveal_type(type(A).x) # E: Revealed type is 'builtins.int' - [case testMetaclassSelftype] from typing import TypeVar, Type From 2b4e148a5fc640f2fe0c89f1a685bf92ed4774ea Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Fri, 10 Feb 2017 15:10:52 -0800 Subject: [PATCH 3/3] Add a test showing that the TypeVar works --- test-data/unit/check-classes.test | 1 + 1 file changed, 1 insertion(+) diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index a0ce727998ce..62b0d16dc060 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -2856,3 +2856,4 @@ class M1(M): def foo(cls: Type[T]) -> T: ... class A(metaclass=M1): pass +reveal_type(A.foo()) # E: Revealed type is '__main__.A*'