From abd9476d08af0efb9dd01b6cc48aa7f2d44542c5 Mon Sep 17 00:00:00 2001 From: "Michael J. Sullivan" Date: Wed, 11 Sep 2019 14:34:30 -0700 Subject: [PATCH] Don't serialize redefined symbol nodes Redefined nodes sometimes have busted internal references (like a self argument that has the class as its type even though it won't be able to look it up) which can cause crashes. Since they can't have references from outside themselves, we don't lose anything by not serializing them. Fixes a crash I observed at Dropbox. This partially reverts #7413, which introduced this crash (while fixing another), but leaves the test case it added. --- mypy/fixup.py | 8 ++------ mypy/nodes.py | 2 -- mypy/semanal.py | 5 +++++ test-data/unit/check-incremental.test | 13 +++++++++++++ 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/mypy/fixup.py b/mypy/fixup.py index 0a89bae0757c..8f3e29c9750d 100644 --- a/mypy/fixup.py +++ b/mypy/fixup.py @@ -57,12 +57,8 @@ def visit_type_info(self, info: TypeInfo) -> None: if info.metaclass_type: info.metaclass_type.accept(self.type_fixer) if 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 = [lookup_qualified_typeinfo(self.modules, name, self.allow_missing) + for name in info._mro_refs] info._mro_refs = None finally: self.current_info = save_info diff --git a/mypy/nodes.py b/mypy/nodes.py index 500069f082c0..28699021d49a 100644 --- a/mypy/nodes.py +++ b/mypy/nodes.py @@ -2996,8 +2996,6 @@ def serialize(self, prefix: str, name: str) -> JsonDict: fullname = self.node.fullname() 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 50e3d8cc6c68..63077f14e849 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -4245,6 +4245,11 @@ def add_redefinition(self, redefinitions (such as e.g. variable redefined as a class). """ i = 1 + # Don't serialize redefined nodes. They are likely to have + # busted internal references which can cause problems with + # serialization and they can't have any external references to + # them. + symbol.no_serialize = True while True: if i == 1: new_name = '{}-redefinition'.format(name) diff --git a/test-data/unit/check-incremental.test b/test-data/unit/check-incremental.test index 79e0a34a00a0..7e20008b63fa 100644 --- a/test-data/unit/check-incremental.test +++ b/test-data/unit/check-incremental.test @@ -5094,3 +5094,16 @@ tmp/a.py:4: error: Cannot determine type of 'foo' [out2] tmp/a.py:3: error: Cannot determine type of 'foo' tmp/a.py:4: error: Cannot determine type of 'foo' + +[case testRedefinitionClass] +import b +[file a.py] +from whatever import Foo # type: ignore + +class Foo: # type: ignore + def f(self) -> None: + pass +[file b.py] +import a +[file b.py.2] +import a # a change