diff --git a/mypy/fixup.py b/mypy/fixup.py index 993a0949b2f2..5854797dfc0d 100644 --- a/mypy/fixup.py +++ b/mypy/fixup.py @@ -66,6 +66,10 @@ def visit_type_info(self, info: TypeInfo) -> None: info.tuple_type.accept(self.type_fixer) if info.typeddict_type: info.typeddict_type.accept(self.type_fixer) + if info.declared_metaclass: + info.declared_metaclass.accept(self.type_fixer) + if info.metaclass_type: + info.metaclass_type.accept(self.type_fixer) finally: self.current_info = save_info diff --git a/mypy/nodes.py b/mypy/nodes.py index 76c94f820750..0088808c8c58 100644 --- a/mypy/nodes.py +++ b/mypy/nodes.py @@ -2180,6 +2180,8 @@ def serialize(self) -> JsonDict: '_promote': None if self._promote is None else self._promote.serialize(), 'declared_metaclass': (None if self.declared_metaclass is None else self.declared_metaclass.serialize()), + 'metaclass_type': + None if self.metaclass_type is None else self.metaclass_type.serialize(), 'tuple_type': None if self.tuple_type is None else self.tuple_type.serialize(), 'typeddict_type': None if self.typeddict_type is None else self.typeddict_type.serialize(), @@ -2202,7 +2204,9 @@ def deserialize(cls, data: JsonDict) -> 'TypeInfo': else mypy.types.deserialize_type(data['_promote'])) ti.declared_metaclass = (None if data['declared_metaclass'] is None else mypy.types.Instance.deserialize(data['declared_metaclass'])) - # NOTE: ti.metaclass_type and ti.mro will be set in the fixup phase. + ti.metaclass_type = (None if data['metaclass_type'] is None + else mypy.types.Instance.deserialize(data['metaclass_type'])) + # NOTE: ti.mro will be set in the fixup phase. ti.tuple_type = (None if data['tuple_type'] is None else mypy.types.TupleType.deserialize(data['tuple_type'])) ti.typeddict_type = (None if data['typeddict_type'] is None diff --git a/test-data/unit/check-incremental.test b/test-data/unit/check-incremental.test index c38b5b6bc7b5..20bbbbbd8b60 100644 --- a/test-data/unit/check-incremental.test +++ b/test-data/unit/check-incremental.test @@ -1943,6 +1943,49 @@ main:4: error: Revealed type is 'TypedDict(x=builtins.int, y=builtins.str, _fall main:2: error: Revealed type is 'TypedDict(x=builtins.int, y=builtins.str, _fallback=b.A)' main:4: error: Revealed type is 'TypedDict(x=builtins.int, y=builtins.str, _fallback=b.A)' +[case testSerializeMetaclass] +import b +reveal_type(b.A.f()) +m: b.M = b.A +reveal_type(b.a.f()) +[file b.py] +from typing import Type + +class M(type): + def f(cls) -> int: return 0 +class A(metaclass=M): pass +a: Type[A] +[out] +main:2: error: Revealed type is 'builtins.int' +main:4: error: Revealed type is 'builtins.int' +[out2] +main:2: error: Revealed type is 'builtins.int' +main:4: error: Revealed type is 'builtins.int' + +[case testSerializeMetaclassInImportCycle1] +import b +import c +reveal_type(b.A.f()) +m: c.M = b.A +reveal_type(b.a.f()) +[file b.py] +from typing import Type +from c import M +class A(metaclass=M): pass +a: Type[A] +[file c.py] +class M(type): + def f(cls) -> int: return 0 +[out] +main:3: error: Revealed type is 'builtins.int' +main:5: error: Revealed type is 'builtins.int' +[out2] +main:3: error: Revealed type is 'builtins.int' +main:5: error: Revealed type is 'builtins.int' + +-- TODO: Add another test for metaclass in import cycle (reversed from the above test). +-- This currently doesn't work. + [case testQuickAndDirty1] # flags: --quick-and-dirty import b, c