Skip to content

Commit 811c201

Browse files
authored
Fix serialization of redefined nodes (#7413)
Currently they will get incorrectly serialized as xrefs because the symbol table name doesn't match the fullname. Fix this. (Though I don't love the way I've fixed it, if somebody has a suggestion for something nicer.) This could cause nondeterministc crashes under python 3.5 when it led to crossrefs to crossrefs, since random dict iteration order meant that the referenced crossref might not be resolved. Add some asserts to catch these things earlier.
1 parent 8954045 commit 811c201

File tree

4 files changed

+36
-4
lines changed

4 files changed

+36
-4
lines changed

mypy/fixup.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,12 @@ def visit_type_info(self, info: TypeInfo) -> None:
5757
if info.metaclass_type:
5858
info.metaclass_type.accept(self.type_fixer)
5959
if info._mro_refs:
60-
info.mro = [lookup_qualified_typeinfo(self.modules, name, self.allow_missing)
61-
for name in info._mro_refs]
60+
# If the class is a "-redefinition", then its
61+
# reference to itself might be busted, so just use the
62+
# info instead of looking up the first element. Ew.
63+
info.mro = [info] + [
64+
lookup_qualified_typeinfo(self.modules, name, self.allow_missing)
65+
for name in info._mro_refs[1:]]
6266
info._mro_refs = None
6367
finally:
6468
self.current_info = save_info
@@ -76,6 +80,7 @@ def visit_symbol_table(self, symtab: SymbolTable) -> None:
7680
stnode = lookup_qualified_stnode(self.modules, cross_ref,
7781
self.allow_missing)
7882
if stnode is not None:
83+
assert stnode.node is not None
7984
value.node = stnode.node
8085
elif not self.allow_missing:
8186
assert stnode is not None, "Could not find cross-ref %s" % (cross_ref,)

mypy/nodes.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2986,8 +2986,10 @@ def serialize(self, prefix: str, name: str) -> JsonDict:
29862986
assert self.node is not None, '%s:%s' % (prefix, name)
29872987
if prefix is not None:
29882988
fullname = self.node.fullname()
2989-
if (fullname is not None and '.' in fullname and
2990-
fullname != prefix + '.' + name
2989+
if (fullname is not None and '.' in fullname
2990+
and fullname != prefix + '.' + name
2991+
# If it only doesn't match because of -redefinition, that is OK
2992+
and fullname != prefix + '.' + name.split('-redefinition')[0]
29912993
and not (isinstance(self.node, Var)
29922994
and self.node.from_module_getattr)):
29932995
data['cross_ref'] = fullname

mypy/semanal.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3118,6 +3118,7 @@ def process_module_assignment(self, lvals: List[Lvalue], rval: Expression,
31183118
# never create module alias except on initial var definition
31193119
elif lval.is_inferred_def:
31203120
lnode.kind = self.current_symbol_kind()
3121+
assert rnode.node is not None
31213122
lnode.node = rnode.node
31223123

31233124
def process__all__(self, s: AssignmentStmt) -> None:

test-data/unit/fine-grained.test

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9160,3 +9160,27 @@ Data = Tuple[User, File]
91609160
[typing fixtures/typing-full.pyi]
91619161
[out]
91629162
==
9163+
9164+
[case testClassRedef]
9165+
# An issue involved serializing these caused crashes in the past
9166+
9167+
[file a.py]
9168+
class A:
9169+
pass
9170+
9171+
x = 0
9172+
9173+
[file a.py.2]
9174+
class A:
9175+
a = A()
9176+
9177+
x = '0'
9178+
9179+
[file b.py]
9180+
from a import A, x
9181+
9182+
class A: # type: ignore
9183+
pass
9184+
9185+
[out]
9186+
==

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy