Skip to content

Commit d2638b1

Browse files
ilevkivskyigvanrossum
authored andcommitted
Tighten FakeInfo and fix crashes in --quick mode (#3304)
The idea was proposed by Jukka in #3285 (comment) This could (hopefully) fix #3281 for real. Also fixes #3278
1 parent 784c72d commit d2638b1

File tree

3 files changed

+31
-6
lines changed

3 files changed

+31
-6
lines changed

mypy/fixup.py

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from mypy.nodes import (
66
MypyFile, SymbolNode, SymbolTable, SymbolTableNode,
77
TypeInfo, FuncDef, OverloadedFuncDef, Decorator, Var,
8-
TypeVarExpr, ClassDef,
8+
TypeVarExpr, ClassDef, Block,
99
LDEF, MDEF, GDEF
1010
)
1111
from mypy.types import (
@@ -90,6 +90,11 @@ def visit_symbol_table(self, symtab: SymbolTable) -> None:
9090
value.type_override = stnode.type_override
9191
elif not self.quick_and_dirty:
9292
assert stnode is not None, "Could not find cross-ref %s" % (cross_ref,)
93+
else:
94+
# We have a missing crossref in quick mode, need to put something
95+
value.node = stale_info()
96+
if value.type_override is not None:
97+
value.type_override.accept(self.type_fixer)
9398
else:
9499
if isinstance(value.node, TypeInfo):
95100
# TypeInfo has no accept(). TODO: Add it?
@@ -162,6 +167,10 @@ def visit_instance(self, inst: Instance) -> None:
162167
for base in inst.type.bases:
163168
if base.type is NOT_READY:
164169
base.accept(self)
170+
else:
171+
# Looks like a missing TypeInfo in quick mode, put something there
172+
assert self.quick_and_dirty, "Should never get here in normal mode"
173+
inst.type = stale_info()
165174
for a in inst.args:
166175
a.accept(self)
167176

@@ -267,12 +276,23 @@ def lookup_qualified_stnode(modules: Dict[str, MypyFile], name: str,
267276
return None
268277
key = rest.pop()
269278
if key not in names:
279+
if not quick_and_dirty:
280+
assert key in names, "Cannot find %s for %s" % (key, name)
270281
return None
271-
elif not quick_and_dirty:
272-
assert key in names, "Cannot find %s for %s" % (key, name)
273282
stnode = names[key]
274283
if not rest:
275284
return stnode
276285
node = stnode.node
277286
assert isinstance(node, TypeInfo)
278287
names = node.names
288+
289+
290+
def stale_info() -> TypeInfo:
291+
suggestion = "<stale cache: consider running mypy without --quick>"
292+
dummy_def = ClassDef(suggestion, Block([]))
293+
dummy_def.fullname = suggestion
294+
295+
info = TypeInfo(SymbolTable(), dummy_def, "<stale>")
296+
info.mro = [info]
297+
info.bases = []
298+
return info

mypy/nodes.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2229,7 +2229,10 @@ class FakeInfo(TypeInfo):
22292229
# pass cleanly.
22302230
# 2. If NOT_READY value is accidentally used somewhere, it will be obvious where the value
22312231
# is from, whereas a 'None' value could come from anywhere.
2232-
def __getattr__(self, attr: str) -> None:
2232+
def __init__(self, *args: Any, **kwargs: Any) -> None:
2233+
pass
2234+
2235+
def __getattribute__(self, attr: str) -> None:
22332236
raise AssertionError('De-serialization failure: TypeInfo not fixed')
22342237

22352238

mypy/types.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ class Instance(Type):
401401

402402
def __init__(self, typ: mypy.nodes.TypeInfo, args: List[Type],
403403
line: int = -1, column: int = -1, erased: bool = False) -> None:
404-
assert(typ is None or typ.fullname() not in ["builtins.Any", "typing.Any"])
404+
assert(typ is NOT_READY or typ.fullname() not in ["builtins.Any", "typing.Any"])
405405
self.type = typ
406406
self.args = args
407407
self.erased = erased
@@ -1796,8 +1796,10 @@ def union_items(typ: Type) -> List[Type]:
17961796
return [typ]
17971797

17981798

1799+
names = globals().copy()
1800+
names.pop('NOT_READY', None)
17991801
deserialize_map = {
18001802
key: obj.deserialize # type: ignore
1801-
for key, obj in globals().items()
1803+
for key, obj in names.items()
18021804
if isinstance(obj, type) and issubclass(obj, Type) and obj is not Type
18031805
}

0 commit comments

Comments
 (0)