diff --git a/mypy/checkmember.py b/mypy/checkmember.py index e3ad6ac35328..7390bb7baf93 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -134,7 +134,7 @@ def analyze_member_access(name: str, if not is_operator: # When Python sees an operator (eg `3 == 4`), it automatically translates that # into something like `int.__eq__(3, 4)` instead of `(3).__eq__(4)` as an - # optimation. + # optimization. # # While it normally it doesn't matter which of the two versions are used, it # does cause inconsistencies when working with classes. For example, translating diff --git a/mypy/nodes.py b/mypy/nodes.py index 8d0d15af4c6a..4e871209b70a 100644 --- a/mypy/nodes.py +++ b/mypy/nodes.py @@ -2017,6 +2017,8 @@ def calculate_metaclass_type(self) -> 'Optional[mypy.types.Instance]': return mypy.types.Instance(self, []) candidates = [s.declared_metaclass for s in self.mro if s.declared_metaclass is not None] for c in candidates: + if c.type.mro is None: + continue if all(other.type in c.type.mro for other in candidates): return c return None diff --git a/mypy/semanal.py b/mypy/semanal.py index 66553325ece2..9cc58c08bba8 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -914,10 +914,11 @@ def analyze_metaclass(self, defn: ClassDef) -> None: inst = fill_typevars(sym.node) assert isinstance(inst, Instance) defn.info.declared_metaclass = inst - defn.info.metaclass_type = defn.info.calculate_metaclass_type() - if defn.info.metaclass_type is None: - # Inconsistency may happen due to multiple baseclasses even in classes that - # do not declare explicit metaclass, but it's harder to catch at this stage + defn.info.metaclass_type = defn.info.calculate_metaclass_type() + if defn.info.metaclass_type is None: + # Inconsistency may happen due to multiple baseclasses even in classes that + # do not declare explicit metaclass, but it's harder to catch at this stage + if defn.metaclass: self.fail("Inconsistent metaclass structure for '%s'" % defn.name, defn) def object_type(self) -> Instance: diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index af69bf7c4c30..b8a7e19c5f0c 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -2785,6 +2785,18 @@ def f(TA: Type[A]): reveal_type(TA) # E: Revealed type is 'Type[__main__.A]' reveal_type(TA.x) # E: Revealed type is 'builtins.int' +[case testMetaclassSubclass] +from typing import Type +class M(type): + x = 0 # type: int + +class A(metaclass=M): pass +class B(A): pass + +def f(TB: Type[B]): + reveal_type(TB) # E: Revealed type is 'Type[__main__.B]' + reveal_type(TB.x) # E: Revealed type is 'builtins.int' + [case testMetaclassIterable] from typing import Iterable, Iterator