Closed
Description
Here is a (relatively) minimal repro:
[case testOidCrash]
import m
[file m.py]
import f
[file m.py.3]
import f
# modify
[file f.py]
import c
def foo(arg: c.Oid) -> None: pass
[file c.py]
from types import Oid
[file types.py]
import pb1
Oid = pb1.Oid
[file types.py.2]
import pb1, pb2
Oid = pb2.Oid
[file pb1.py]
class Oid: ...
[file pb2.py.2]
class Oid: ...
[file pb1.py.2]
[out]
[out2]
[out3]
This crashes with
/home/ivan/src/mypy/mypy/test/testcheck.py:81: in run_case
self.run_case_once(testcase, ops, step)
/home/ivan/src/mypy/mypy/test/testcheck.py:147: in run_case_once
res = build.build(sources=sources, options=options, alt_lib_path=test_temp_dir)
/home/ivan/src/mypy/mypy/build.py:193: in build
result = _build(
/home/ivan/src/mypy/mypy/build.py:276: in _build
graph = dispatch(sources, manager, stdout)
/home/ivan/src/mypy/mypy/build.py:2891: in dispatch
process_graph(graph, manager)
/home/ivan/src/mypy/mypy/build.py:3268: in process_graph
process_fresh_modules(graph, prev_scc, manager)
/home/ivan/src/mypy/mypy/build.py:3349: in process_fresh_modules
graph[id].fix_cross_refs()
/home/ivan/src/mypy/mypy/build.py:2112: in fix_cross_refs
fixup_module(self.tree, self.manager.modules, self.options.use_fine_grained_cache)
/home/ivan/src/mypy/mypy/fixup.py:53: in fixup_module
node_fixer.visit_symbol_table(tree.names, tree.fullname)
/home/ivan/src/mypy/mypy/fixup.py:127: in visit_symbol_table
value.node.accept(self)
/home/ivan/src/mypy/mypy/nodes.py:822: in accept
return visitor.visit_func_def(self)
/home/ivan/src/mypy/mypy/fixup.py:135: in visit_func_def
func.type.accept(self.type_fixer)
/home/ivan/src/mypy/mypy/types.py:1792: in accept
return visitor.visit_callable_type(self)
/home/ivan/src/mypy/mypy/fixup.py:229: in visit_callable_type
argt.accept(self)
/home/ivan/src/mypy/mypy/types.py:1283: in accept
return visitor.visit_instance(self)
/home/ivan/src/mypy/mypy/fixup.py:196: in visit_instance
inst.type = lookup_fully_qualified_typeinfo(
/home/ivan/src/mypy/mypy/fixup.py:331: in lookup_fully_qualified_typeinfo
stnode = lookup_fully_qualified(name, modules, raise_on_missing=not allow_missing)
/home/ivan/src/mypy/mypy/lookup.py:49: in lookup_fully_qualified
assert key in names, f"Cannot find component {key!r} for {name!r}"
AssertionError: Cannot find component 'Oid' for 'pb1.Oid'
The problem is that TypeIndirectionVisitor
uses type_map
for a given module to find indirect dependencies. This is however problematic in various cases, for example types used in a function definition may never appear as a type of some expression (type map of f.py
in this case is just empty). I am not sure what is the best solution (for example fine-grained mode doesn't have this problem as it uses a proper node visitor). Maybe we can just add all types encountered in symbol tables?