@@ -1474,6 +1474,9 @@ class State:
1474
1474
# Whether to ignore all errors
1475
1475
ignore_all = False
1476
1476
1477
+ # Whether the module has an error or any of its dependencies have one.
1478
+ transitive_error = False
1479
+
1477
1480
# Type checker used for checking this file. Use type_checker() for
1478
1481
# access and to construct this on demand.
1479
1482
_type_checker = None # type: Optional[TypeChecker]
@@ -1944,7 +1947,7 @@ def write_cache(self) -> None:
1944
1947
if self .manager .options .quick_and_dirty :
1945
1948
is_errors = self .manager .errors .is_errors_for_file (self .path )
1946
1949
else :
1947
- is_errors = self .manager . errors . is_errors ()
1950
+ is_errors = self .transitive_error
1948
1951
if is_errors :
1949
1952
delete_cache (self .id , self .path , self .manager )
1950
1953
self .meta = None
@@ -2257,6 +2260,12 @@ def process_graph(graph: Graph, manager: BuildManager) -> None:
2257
2260
else :
2258
2261
fresh_msg = "stale due to deps (%s)" % " " .join (sorted (stale_deps ))
2259
2262
2263
+ # Initialize transitive_error for all SCC members from union
2264
+ # of transitive_error of dependencies.
2265
+ if any (graph [dep ].transitive_error for dep in deps if dep in graph ):
2266
+ for id in scc :
2267
+ graph [id ].transitive_error = True
2268
+
2260
2269
scc_str = " " .join (scc )
2261
2270
if fresh :
2262
2271
if not maybe_reuse_in_memory_tree (graph , scc , manager ):
@@ -2272,6 +2281,11 @@ def process_graph(graph: Graph, manager: BuildManager) -> None:
2272
2281
# single fresh SCC. This is intentional -- we don't need those modules
2273
2282
# loaded if there are no more stale SCCs to be rechecked.
2274
2283
#
2284
+ # Also note we shouldn't have to worry about transitive_error here,
2285
+ # since modules with transitive errors aren't written to the cache,
2286
+ # and if any dependencies were changed, this SCC would be stale.
2287
+ # (Also, in quick_and_dirty mode we don't care about transitive errors.)
2288
+ #
2275
2289
# TODO: see if it's possible to determine if we need to process only a
2276
2290
# _subset_ of the past SCCs instead of having to process them all.
2277
2291
for prev_scc in fresh_scc_queue :
@@ -2416,6 +2430,7 @@ def can_reuse_in_memory_tree(graph: Graph, scc: List[str], manager: BuildManager
2416
2430
# Check that all dependencies were loaded from memory.
2417
2431
# If not, some dependency was reparsed but the interface hash
2418
2432
# wasn't changed -- in that case we can't reuse the tree.
2433
+ # TODO: Pass deps in from process_graph(), via maybe_reuse_in_memory_tree()?
2419
2434
deps = set (dep for id in scc for dep in graph [id ].dependencies if dep in graph )
2420
2435
deps -= set (scc ) # Subtract the SCC itself (else nothing will be safe)
2421
2436
if all (graph [dep ].is_from_saved_cache for dep in deps ):
@@ -2464,6 +2479,9 @@ def process_stale_scc(graph: Graph, scc: List[str], manager: BuildManager) -> No
2464
2479
for id in stale :
2465
2480
if graph [id ].type_check_second_pass ():
2466
2481
more = True
2482
+ if any (manager .errors .is_errors_for_file (graph [id ].xpath ) for id in stale ):
2483
+ for id in stale :
2484
+ graph [id ].transitive_error = True
2467
2485
for id in stale :
2468
2486
graph [id ].finish_passes ()
2469
2487
graph [id ].write_cache ()
0 commit comments