|
59 | 59 | from mypy.typestate import TypeState, reset_global_state
|
60 | 60 | from mypy.renaming import VariableRenameVisitor
|
61 | 61 | from mypy.config_parser import parse_mypy_comments
|
| 62 | +from mypy.freetree import free_tree |
62 | 63 |
|
63 | 64 |
|
64 | 65 | # Switch to True to produce debug output related to fine-grained incremental
|
@@ -471,6 +472,7 @@ class BuildManager:
|
471 | 472 | missing_modules: Set of modules that could not be imported encountered so far
|
472 | 473 | stale_modules: Set of modules that needed to be rechecked (only used by tests)
|
473 | 474 | fg_deps_meta: Metadata for fine-grained dependencies caches associated with modules
|
| 475 | + fg_deps: A fine-grained dependency map |
474 | 476 | version_id: The current mypy version (based on commit id when possible)
|
475 | 477 | plugin: Active mypy plugin(s)
|
476 | 478 | plugins_snapshot:
|
@@ -523,6 +525,11 @@ def __init__(self, data_dir: str,
|
523 | 525 | self.modules = {} # type: Dict[str, MypyFile]
|
524 | 526 | self.missing_modules = set() # type: Set[str]
|
525 | 527 | self.fg_deps_meta = {} # type: Dict[str, FgDepMeta]
|
| 528 | + # fg_deps holds the dependencies of every module that has been |
| 529 | + # processed. We store this in BuildManager so that we can compute |
| 530 | + # dependencies as we go, which allows us to free ASTs and type information, |
| 531 | + # saving a ton of memory on net. |
| 532 | + self.fg_deps = {} # type: Dict[str, Set[str]] |
526 | 533 | # Always convert the plugin to a ChainedPlugin so that it can be manipulated if needed
|
527 | 534 | if not isinstance(plugin, ChainedPlugin):
|
528 | 535 | plugin = ChainedPlugin(options, [plugin])
|
@@ -894,32 +901,24 @@ def invert_deps(deps: Dict[str, Set[str]],
|
894 | 901 | return rdeps
|
895 | 902 |
|
896 | 903 |
|
897 |
| -def generate_deps_for_cache(proto_deps: Dict[str, Set[str]], |
898 |
| - manager: BuildManager, |
| 904 | +def generate_deps_for_cache(manager: BuildManager, |
899 | 905 | graph: Graph) -> Dict[str, Dict[str, Set[str]]]:
|
900 | 906 | """Generate fine-grained dependencies into a form suitable for serializing.
|
901 | 907 |
|
902 |
| - This does a few things: |
903 |
| - 1. Computes all fine grained deps from modules that were processed |
904 |
| - 2. Splits fine-grained deps based on the module of the trigger |
905 |
| - 3. For each module we generated fine-grained deps for, load any previous |
| 908 | + This does a couple things: |
| 909 | + 1. Splits fine-grained deps based on the module of the trigger |
| 910 | + 2. For each module we generated fine-grained deps for, load any previous |
906 | 911 | deps and merge them in.
|
907 | 912 |
|
908 | 913 | Returns a dictionary from module ids to all dependencies on that
|
909 | 914 | module. Dependencies not associated with a module in the build will be
|
910 | 915 | associated with the nearest parent module that is in the build, or the
|
911 | 916 | fake module FAKE_ROOT_MODULE if none are.
|
912 | 917 | """
|
913 |
| - from mypy.server.update import merge_dependencies # Lazy import to speed up startup |
914 |
| - |
915 |
| - # Compute the full set of dependencies from everything we've processed. |
916 |
| - deps = {} # type: Dict[str, Set[str]] |
917 |
| - things = [st.compute_fine_grained_deps() for st in graph.values() if st.tree] + [proto_deps] |
918 |
| - for st_deps in things: |
919 |
| - merge_dependencies(st_deps, deps) |
| 918 | + from mypy.server.deps import merge_dependencies # Lazy import to speed up startup |
920 | 919 |
|
921 | 920 | # Split the dependencies out into based on the module that is depended on.
|
922 |
| - rdeps = invert_deps(deps, graph) |
| 921 | + rdeps = invert_deps(manager.fg_deps, graph) |
923 | 922 |
|
924 | 923 | # We can't just clobber existing dependency information, so we
|
925 | 924 | # load the deps for every module we've generated new dependencies
|
@@ -2172,6 +2171,16 @@ def finish_passes(self) -> None:
|
2172 | 2171 | typemap=self.type_map())
|
2173 | 2172 | manager.report_file(self.tree, self.type_map(), self.options)
|
2174 | 2173 |
|
| 2174 | + self.update_fine_grained_deps(self.manager.fg_deps) |
| 2175 | + self.free_state() |
| 2176 | + if not manager.options.fine_grained_incremental and not manager.options.preserve_asts: |
| 2177 | + free_tree(self.tree) |
| 2178 | + |
| 2179 | + def free_state(self) -> None: |
| 2180 | + if self._type_checker: |
| 2181 | + self._type_checker.reset() |
| 2182 | + self._type_checker = None |
| 2183 | + |
2175 | 2184 | def _patch_indirect_dependencies(self,
|
2176 | 2185 | module_refs: Set[str],
|
2177 | 2186 | type_map: Dict[Expression, Type]) -> None:
|
@@ -2206,6 +2215,13 @@ def compute_fine_grained_deps(self) -> Dict[str, Set[str]]:
|
2206 | 2215 | python_version=self.options.python_version,
|
2207 | 2216 | options=self.manager.options)
|
2208 | 2217 |
|
| 2218 | + def update_fine_grained_deps(self, deps: Dict[str, Set[str]]) -> None: |
| 2219 | + options = self.manager.options |
| 2220 | + if options.cache_fine_grained or options.fine_grained_incremental: |
| 2221 | + from mypy.server.deps import merge_dependencies # Lazy import to speed up startup |
| 2222 | + merge_dependencies(self.compute_fine_grained_deps(), deps) |
| 2223 | + TypeState.update_protocol_deps(deps) |
| 2224 | + |
2209 | 2225 | def valid_references(self) -> Set[str]:
|
2210 | 2226 | assert self.ancestors is not None
|
2211 | 2227 | valid_refs = set(self.dependencies + self.suppressed + self.ancestors)
|
@@ -2616,10 +2632,9 @@ def dispatch(sources: List[BuildSource],
|
2616 | 2632 | # then we need to collect fine grained protocol dependencies.
|
2617 | 2633 | # Since these are a global property of the program, they are calculated after we
|
2618 | 2634 | # processed the whole graph.
|
2619 |
| - TypeState.update_protocol_deps() |
| 2635 | + TypeState.add_all_protocol_deps(manager.fg_deps) |
2620 | 2636 | if not manager.options.fine_grained_incremental:
|
2621 |
| - proto_deps = TypeState.proto_deps or {} |
2622 |
| - rdeps = generate_deps_for_cache(proto_deps, manager, graph) |
| 2637 | + rdeps = generate_deps_for_cache(manager, graph) |
2623 | 2638 | write_deps_cache(rdeps, manager, graph)
|
2624 | 2639 |
|
2625 | 2640 | if manager.options.dump_deps:
|
@@ -3023,23 +3038,29 @@ def process_stale_scc(graph: Graph, scc: List[str], manager: BuildManager) -> No
|
3023 | 3038 | graph[id].semantic_analysis_pass_three()
|
3024 | 3039 | for id in stale:
|
3025 | 3040 | graph[id].semantic_analysis_apply_patches()
|
| 3041 | + |
| 3042 | + # Track what modules aren't yet done so we can finish them as soon |
| 3043 | + # as possible, saving memory. |
| 3044 | + unfinished_modules = set(stale) |
3026 | 3045 | for id in stale:
|
3027 | 3046 | graph[id].type_check_first_pass()
|
3028 |
| - more = True |
3029 |
| - while more: |
3030 |
| - more = False |
| 3047 | + if not graph[id].type_checker().deferred_nodes: |
| 3048 | + unfinished_modules.discard(id) |
| 3049 | + graph[id].finish_passes() |
| 3050 | + |
| 3051 | + while unfinished_modules: |
3031 | 3052 | for id in stale:
|
3032 |
| - if graph[id].type_check_second_pass(): |
3033 |
| - more = True |
| 3053 | + if id not in unfinished_modules: |
| 3054 | + continue |
| 3055 | + if not graph[id].type_check_second_pass(): |
| 3056 | + unfinished_modules.discard(id) |
| 3057 | + graph[id].finish_passes() |
3034 | 3058 | for id in stale:
|
3035 | 3059 | graph[id].generate_unused_ignore_notes()
|
3036 | 3060 | if any(manager.errors.is_errors_for_file(graph[id].xpath) for id in stale):
|
3037 | 3061 | for id in stale:
|
3038 | 3062 | graph[id].transitive_error = True
|
3039 | 3063 | for id in stale:
|
3040 |
| - graph[id].finish_passes() |
3041 |
| - if manager.options.cache_fine_grained or manager.options.fine_grained_incremental: |
3042 |
| - graph[id].compute_fine_grained_deps() |
3043 | 3064 | manager.flush_errors(manager.errors.file_messages(graph[id].xpath), False)
|
3044 | 3065 | graph[id].write_cache()
|
3045 | 3066 | graph[id].mark_as_rechecked()
|
|
0 commit comments