diff --git a/mypy/fixup.py b/mypy/fixup.py index c9a45b890b92a..09c190620241a 100644 --- a/mypy/fixup.py +++ b/mypy/fixup.py @@ -57,8 +57,12 @@ def visit_type_info(self, info: TypeInfo) -> None: if info.metaclass_type: info.metaclass_type.accept(self.type_fixer) if info._mro_refs: - info.mro = [lookup_qualified_typeinfo(self.modules, name, self.allow_missing) - for name in info._mro_refs] + # If the class is a "-redefinition", then its + # reference to itself might be busted, so just use the + # info instead of looking up the first element. Ew. + info.mro = [info] + [ + lookup_qualified_typeinfo(self.modules, name, self.allow_missing) + for name in info._mro_refs[1:]] info._mro_refs = None finally: self.current_info = save_info @@ -76,6 +80,7 @@ def visit_symbol_table(self, symtab: SymbolTable) -> None: stnode = lookup_qualified_stnode(self.modules, cross_ref, self.allow_missing) if stnode is not None: + assert stnode.node is not None value.node = stnode.node elif not self.allow_missing: assert stnode is not None, "Could not find cross-ref %s" % (cross_ref,) diff --git a/mypy/nodes.py b/mypy/nodes.py index 236cb92c9a0f4..79343f4ad2123 100644 --- a/mypy/nodes.py +++ b/mypy/nodes.py @@ -2986,8 +2986,10 @@ def serialize(self, prefix: str, name: str) -> JsonDict: assert self.node is not None, '%s:%s' % (prefix, name) if prefix is not None: fullname = self.node.fullname() - if (fullname is not None and '.' in fullname and - fullname != prefix + '.' + name + if (fullname is not None and '.' in fullname + and fullname != prefix + '.' + name + # If it only doesn't match because of -redefinition, that is OK + and fullname != prefix + '.' + name.split('-redefinition')[0] and not (isinstance(self.node, Var) and self.node.from_module_getattr)): data['cross_ref'] = fullname diff --git a/mypy/semanal.py b/mypy/semanal.py index df4126cbf30a1..22da6c3b678df 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -3114,6 +3114,7 @@ def process_module_assignment(self, lvals: List[Lvalue], rval: Expression, # never create module alias except on initial var definition elif lval.is_inferred_def: lnode.kind = self.current_symbol_kind() + assert rnode.node is not None lnode.node = rnode.node def process__all__(self, s: AssignmentStmt) -> None: diff --git a/test-data/unit/fine-grained.test b/test-data/unit/fine-grained.test index 551c752964c7b..b55d765d4bce9 100644 --- a/test-data/unit/fine-grained.test +++ b/test-data/unit/fine-grained.test @@ -9160,3 +9160,27 @@ Data = Tuple[User, File] [typing fixtures/typing-full.pyi] [out] == + +[case testClassRedef] +# An issue involved serializing these caused crashes in the past + +[file a.py] +class A: + pass + +x = 0 + +[file a.py.2] +class A: + a = A() + +x = '0' + +[file b.py] +from a import A, x + +class A: # type: ignore + pass + +[out] +==