Skip to content

Commit 116d8e5

Browse files
committed
Refactor fine-grained graph processing and optimize deletes in initial load
1 parent b328f74 commit 116d8e5

File tree

5 files changed

+53
-15
lines changed

5 files changed

+53
-15
lines changed

mypy/build.py

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1795,13 +1795,15 @@ def load_tree(self) -> None:
17951795

17961796
def fix_cross_refs(self) -> None:
17971797
assert self.tree is not None, "Internal error: method must be called on parsed file only"
1798+
# We need to set quick_and_dirty when doing a fine grained
1799+
# cache load because we need to gracefully handle missing modules.
17981800
fixup_module_pass_one(self.tree, self.manager.modules,
1799-
self.manager.options.quick_and_dirty)
1801+
self.manager.options.quick_and_dirty or
1802+
self.manager.only_load_from_cache)
18001803

18011804
def calculate_mros(self) -> None:
18021805
assert self.tree is not None, "Internal error: method must be called on parsed file only"
1803-
fixup_module_pass_two(self.tree, self.manager.modules,
1804-
self.manager.options.quick_and_dirty)
1806+
fixup_module_pass_two(self.tree, self.manager.modules)
18051807

18061808
def patch_dependency_parents(self) -> None:
18071809
"""
@@ -2128,7 +2130,10 @@ def dispatch(sources: List[BuildSource], manager: BuildManager) -> Graph:
21282130
if manager.options.dump_graph:
21292131
dump_graph(graph)
21302132
return graph
2131-
process_graph(graph, manager)
2133+
if manager.only_load_from_cache:
2134+
halfass_process_graph(graph, manager)
2135+
else:
2136+
process_graph(graph, manager)
21322137
updated = preserve_cache(graph)
21332138
set_updated = set(updated)
21342139
manager.saved_cache.clear()
@@ -2437,14 +2442,6 @@ def process_graph(graph: Graph, manager: BuildManager) -> None:
24372442
manager.log("Processing SCC of size %d (%s) as %s" % (size, scc_str, fresh_msg))
24382443
process_stale_scc(graph, scc, manager)
24392444

2440-
# If we are running in fine-grained incremental mode with caching,
2441-
# we always process fresh SCCs so that we have all of the symbol
2442-
# tables and fine-grained dependencies available.
2443-
if manager.options.use_fine_grained_cache:
2444-
for prev_scc in fresh_scc_queue:
2445-
process_fresh_scc(graph, prev_scc, manager)
2446-
fresh_scc_queue = []
2447-
24482445
sccs_left = len(fresh_scc_queue)
24492446
nodes_left = sum(len(scc) for scc in fresh_scc_queue)
24502447
manager.add_stats(sccs_left=sccs_left, nodes_left=nodes_left)
@@ -2456,6 +2453,25 @@ def process_graph(graph: Graph, manager: BuildManager) -> None:
24562453
manager.log("No fresh SCCs left in queue")
24572454

24582455

2456+
def halfass_process_graph(graph: Graph, manager: BuildManager) -> None:
2457+
"""Finish loading everything for use in the fine-grained incremental cache"""
2458+
2459+
# If we are running in fine-grained incremental mode with caching,
2460+
# we process all SCCs as fresh SCCs so that we have all of the symbol
2461+
# tables and fine-grained dependencies available.
2462+
# We fail the loading of any SCC that we can't load a meta for, so we
2463+
# don't have anything *but* fresh SCCs.
2464+
sccs = sorted_components(graph)
2465+
manager.log("Found %d SCCs; largest has %d nodes" %
2466+
(len(sccs), max(len(scc) for scc in sccs)))
2467+
2468+
for ascc in sccs:
2469+
# Order the SCC's nodes using a heuristic.
2470+
# Note that ascc is a set, and scc is a list.
2471+
scc = order_ascc(graph, ascc)
2472+
process_fresh_scc(graph, scc, manager)
2473+
2474+
24592475
def order_ascc(graph: Graph, ascc: AbstractSet[str], pri_max: int = PRI_ALL) -> List[str]:
24602476
"""Come up with the ideal processing order within an SCC.
24612477

mypy/dmypy_server.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,11 @@ def initialize_fine_grained(self, sources: List[mypy.build.BuildSource]) -> Dict
310310

311311
# Run an update
312312
changed = self.find_changed(sources)
313+
for state in self.fine_grained_manager.graph.values():
314+
if not state.is_fresh():
315+
assert state.path is not None
316+
changed.append((state.id, state.path))
317+
313318
if changed:
314319
messages = self.fine_grained_manager.update(changed)
315320
self.fscache.flush()

mypy/fixup.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ def fixup_module_pass_one(tree: MypyFile, modules: Dict[str, MypyFile],
2222
node_fixer.visit_symbol_table(tree.names)
2323

2424

25-
def fixup_module_pass_two(tree: MypyFile, modules: Dict[str, MypyFile],
26-
quick_and_dirty: bool) -> None:
25+
def fixup_module_pass_two(tree: MypyFile, modules: Dict[str, MypyFile]) -> None:
2726
compute_all_mros(tree.names, modules)
2827

2928

mypy/server/astdiff.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,9 @@ def snapshot_symbol_table(name_prefix: str, table: SymbolTable) -> Dict[str, Sna
254254
common = (fullname, symbol.kind, symbol.module_public)
255255
if symbol.kind == MODULE_REF:
256256
# This is a cross-reference to another module.
257-
assert isinstance(node, MypyFile)
257+
# If the reference is busted because the other module is missing,
258+
# the node will be a "stale_info" TypeInfo produced by fixup,
259+
# but that doesn't really matter to us here.
258260
result[name] = ('Moduleref', common)
259261
elif symbol.kind == TVAR:
260262
assert isinstance(node, TypeVarExpr)

test-data/unit/fine-grained-modules.test

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,22 @@ c.f(1)
624624
==
625625
a.py:2: error: Too many arguments for "f"
626626

627+
[case testRenameAndDeleteModule]
628+
import a
629+
[file a.py]
630+
from b1 import f
631+
f()
632+
[file b1.py]
633+
def f() -> None: pass
634+
[file b2.py.2]
635+
def f() -> None: pass
636+
[delete b1.py.2]
637+
[file a.py.2]
638+
from b2 import f
639+
f()
640+
[out]
641+
==
642+
627643
[case testDeleteFileWithinPackage]
628644
import a
629645
[file a.py]

0 commit comments

Comments
 (0)