From de532c79e0f05bda171cbe06dae8cbd4bc0de54e Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Tue, 2 May 2017 21:39:51 +0200 Subject: [PATCH 1/5] Tighten FakeInfo and fix metaclass de-serialization --- mypy/fixup.py | 4 ++++ mypy/nodes.py | 4 +++- mypy/types.py | 6 ++++-- 3 files changed, 11 insertions(+), 3 deletions(-) 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..eba2b1e4c5c6 100644 --- a/mypy/nodes.py +++ b/mypy/nodes.py @@ -2224,7 +2224,9 @@ class FakeInfo(TypeInfo): # pass cleanly. # 2. If NOT_READY value is accidentally used somewhere, it will be obvious where the value # is from, whereas a 'None' value could come from anywhere. - def __getattr__(self, attr: str) -> None: + def __init__(self, *args: Any, **kwargs: Any) -> None: + pass + def __getattribute__(self, attr: str) -> None: raise AssertionError('De-serialization failure: TypeInfo not fixed') diff --git a/mypy/types.py b/mypy/types.py index 8e5383311abc..75178cbcad4d 100644 --- a/mypy/types.py +++ b/mypy/types.py @@ -401,7 +401,7 @@ class Instance(Type): def __init__(self, typ: mypy.nodes.TypeInfo, args: List[Type], line: int = -1, column: int = -1, erased: bool = False) -> None: - assert(typ is None or typ.fullname() not in ["builtins.Any", "typing.Any"]) + assert(typ is NOT_READY or typ.fullname() not in ["builtins.Any", "typing.Any"]) self.type = typ self.args = args self.erased = erased @@ -1796,8 +1796,10 @@ def union_items(typ: Type) -> List[Type]: return [typ] +names = globals().copy() +names.pop('NOT_READY', None) deserialize_map = { key: obj.deserialize # type: ignore - for key, obj in globals().items() + for key, obj in names.items() if isinstance(obj, type) and issubclass(obj, Type) and obj is not Type } From 0bdd3c1eb3d431bf668e6e33cfc5295444bd50c8 Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Tue, 2 May 2017 21:43:58 +0200 Subject: [PATCH 2/5] Fix lint --- mypy/nodes.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mypy/nodes.py b/mypy/nodes.py index eba2b1e4c5c6..f7f66206e9a5 100644 --- a/mypy/nodes.py +++ b/mypy/nodes.py @@ -2226,6 +2226,7 @@ class FakeInfo(TypeInfo): # is from, whereas a 'None' value could come from anywhere. def __init__(self, *args: Any, **kwargs: Any) -> None: pass + def __getattribute__(self, attr: str) -> None: raise AssertionError('De-serialization failure: TypeInfo not fixed') From 1b49e7427ebd188f844c647f6e2e7e9aea444088 Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Wed, 3 May 2017 10:20:38 +0200 Subject: [PATCH 3/5] Always fix TypeInfo in quick mode --- mypy/fixup.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/mypy/fixup.py b/mypy/fixup.py index 5854797dfc0d..f367b861bdbc 100644 --- a/mypy/fixup.py +++ b/mypy/fixup.py @@ -5,7 +5,7 @@ from mypy.nodes import ( MypyFile, SymbolNode, SymbolTable, SymbolTableNode, TypeInfo, FuncDef, OverloadedFuncDef, Decorator, Var, - TypeVarExpr, ClassDef, + TypeVarExpr, ClassDef, Block, LDEF, MDEF, GDEF ) from mypy.types import ( @@ -90,6 +90,9 @@ def visit_symbol_table(self, symtab: SymbolTable) -> None: value.type_override = stnode.type_override elif not self.quick_and_dirty: assert stnode is not None, "Could not find cross-ref %s" % (cross_ref,) + else: + # We have a missing crossref in quick mode, need to put something + value.node = stale_info() else: if isinstance(value.node, TypeInfo): # TypeInfo has no accept(). TODO: Add it? @@ -162,6 +165,10 @@ def visit_instance(self, inst: Instance) -> None: for base in inst.type.bases: if base.type is NOT_READY: base.accept(self) + else: + # Looks like a missing TypeInfo in quick mode, put something there + assert node is None and self.quick_and_dirty + inst.type = stale_info() for a in inst.args: a.accept(self) @@ -267,12 +274,23 @@ def lookup_qualified_stnode(modules: Dict[str, MypyFile], name: str, return None key = rest.pop() if key not in names: + if not quick_and_dirty: + assert key in names, "Cannot find %s for %s" % (key, name) return None - elif not quick_and_dirty: - assert key in names, "Cannot find %s for %s" % (key, name) stnode = names[key] if not rest: return stnode node = stnode.node assert isinstance(node, TypeInfo) names = node.names + + +def stale_info() -> TypeInfo: + suggestion = "" + dummy_def = ClassDef(suggestion, Block([])) + dummy_def.fullname = suggestion + + info = TypeInfo(SymbolTable(), dummy_def, "") + info.mro = [info] + info.bases = [] + return info From a084ab60bad0d40f8f122e75200a3ae0cd171969 Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Wed, 3 May 2017 11:09:30 +0200 Subject: [PATCH 4/5] Also fix type_override just in case --- mypy/fixup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mypy/fixup.py b/mypy/fixup.py index f367b861bdbc..c058bd3fabec 100644 --- a/mypy/fixup.py +++ b/mypy/fixup.py @@ -93,6 +93,8 @@ def visit_symbol_table(self, symtab: SymbolTable) -> None: else: # We have a missing crossref in quick mode, need to put something value.node = stale_info() + if value.type_override is not None: + value.type_override.accept(self.type_fixer) else: if isinstance(value.node, TypeInfo): # TypeInfo has no accept(). TODO: Add it? From 02739af1675f73bd351aa053518ee73386ee35ff Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Wed, 3 May 2017 18:10:08 +0200 Subject: [PATCH 5/5] Relax assert; Var node can also appear there --- mypy/fixup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypy/fixup.py b/mypy/fixup.py index c058bd3fabec..91d8dcdfb783 100644 --- a/mypy/fixup.py +++ b/mypy/fixup.py @@ -169,7 +169,7 @@ def visit_instance(self, inst: Instance) -> None: base.accept(self) else: # Looks like a missing TypeInfo in quick mode, put something there - assert node is None and self.quick_and_dirty + assert self.quick_and_dirty, "Should never get here in normal mode" inst.type = stale_info() for a in inst.args: a.accept(self)