@@ -464,57 +464,72 @@ int Compilation::performJobsImpl() {
464
464
const CommandOutput &Output = FinishedCmd->getOutput ();
465
465
StringRef DependenciesFile =
466
466
Output.getAdditionalOutputForType (types::TY_SwiftDeps);
467
- if (!DependenciesFile.empty () &&
468
- (ReturnCode == EXIT_SUCCESS || ReturnCode == EXIT_FAILURE)) {
469
- bool wasCascading = DepGraph.isMarked (FinishedCmd);
470
467
471
- switch (DepGraph.loadFromPath (FinishedCmd, DependenciesFile)) {
472
- case DependencyGraphImpl::LoadResult::HadError:
473
- if (ReturnCode == EXIT_SUCCESS) {
474
- disableIncrementalBuild ();
475
- for (const Job *Cmd : DeferredCommands)
476
- scheduleCommandIfNecessaryAndPossible (Cmd);
477
- DeferredCommands.clear ();
478
- Dependents.clear ();
479
- } // else, let the next build handle it.
480
- break ;
481
- case DependencyGraphImpl::LoadResult::UpToDate:
482
- if (!wasCascading)
483
- break ;
484
- SWIFT_FALLTHROUGH;
485
- case DependencyGraphImpl::LoadResult::AffectsDownstream:
486
- DepGraph.markTransitive (Dependents, FinishedCmd);
487
- break ;
488
- }
468
+ if (DependenciesFile.empty ()) {
469
+ // If this job doesn't track dependencies, it must always be run.
470
+ // Note: In theory CheckDependencies makes sense as well (for a leaf
471
+ // node in the dependency graph), and maybe even NewlyAdded (for very
472
+ // coarse dependencies that always affect downstream nodes), but we're
473
+ // not using either of those right now, and this logic should probably
474
+ // be revisited when we are.
475
+ assert (FinishedCmd->getCondition () == Job::Condition::Always);
489
476
} else {
490
- // If there's a crash, assume the worst.
491
- switch (FinishedCmd->getCondition ()) {
492
- case Job::Condition::NewlyAdded:
493
- // The job won't be treated as newly added next time. Conservatively
494
- // mark it as affecting other jobs, because some of them may have
495
- // completed already.
496
- DepGraph.markTransitive (Dependents, FinishedCmd);
497
- break ;
498
- case Job::Condition::Always:
499
- // This applies to non-incremental tasks as well, but any incremental
500
- // task that shows up here has already been marked.
501
- break ;
502
- case Job::Condition::RunWithoutCascading:
503
- // If this file changed, it might have been a non-cascading change and
504
- // it might not. Unfortunately, the interface hash has been updated or
505
- // compromised, so we don't actually know anymore; we have to
506
- // conservatively assume the changes could affect other files.
507
- DepGraph.markTransitive (Dependents, FinishedCmd);
508
- break ;
509
- case Job::Condition::CheckDependencies:
510
- // If the only reason we're running this is because something else
511
- // changed, then we can trust the dependency graph as to whether it's
512
- // a cascading or non-cascading change. That is, if whatever /caused/
513
- // the error isn't supposed to affect other files, and whatever
514
- // /fixes/ the error isn't supposed to affect other files, then
515
- // there's no need to recompile any other inputs. If either of those
516
- // are false, we /do/ need to recompile other inputs.
517
- break ;
477
+ // If we have a dependency file /and/ the frontend task exited normally,
478
+ // we can be discerning about what downstream files to rebuild.
479
+ if (ReturnCode == EXIT_SUCCESS || ReturnCode == EXIT_FAILURE) {
480
+ bool wasCascading = DepGraph.isMarked (FinishedCmd);
481
+
482
+ switch (DepGraph.loadFromPath (FinishedCmd, DependenciesFile)) {
483
+ case DependencyGraphImpl::LoadResult::HadError:
484
+ if (ReturnCode == EXIT_SUCCESS) {
485
+ disableIncrementalBuild ();
486
+ for (const Job *Cmd : DeferredCommands)
487
+ scheduleCommandIfNecessaryAndPossible (Cmd);
488
+ DeferredCommands.clear ();
489
+ Dependents.clear ();
490
+ } // else, let the next build handle it.
491
+ break ;
492
+ case DependencyGraphImpl::LoadResult::UpToDate:
493
+ if (!wasCascading)
494
+ break ;
495
+ SWIFT_FALLTHROUGH;
496
+ case DependencyGraphImpl::LoadResult::AffectsDownstream:
497
+ DepGraph.markTransitive (Dependents, FinishedCmd);
498
+ break ;
499
+ }
500
+ } else {
501
+ // If there's an abnormal exit (a crash), assume the worst.
502
+ switch (FinishedCmd->getCondition ()) {
503
+ case Job::Condition::NewlyAdded:
504
+ // The job won't be treated as newly added next time. Conservatively
505
+ // mark it as affecting other jobs, because some of them may have
506
+ // completed already.
507
+ DepGraph.markTransitive (Dependents, FinishedCmd);
508
+ break ;
509
+ case Job::Condition::Always:
510
+ // Any incremental task that shows up here has already been marked;
511
+ // we didn't need to wait for it to finish to start downstream
512
+ // tasks.
513
+ assert (DepGraph.isMarked (FinishedCmd));
514
+ break ;
515
+ case Job::Condition::RunWithoutCascading:
516
+ // If this file changed, it might have been a non-cascading change
517
+ // and it might not. Unfortunately, the interface hash has been
518
+ // updated or compromised, so we don't actually know anymore; we
519
+ // have to conservatively assume the changes could affect other
520
+ // files.
521
+ DepGraph.markTransitive (Dependents, FinishedCmd);
522
+ break ;
523
+ case Job::Condition::CheckDependencies:
524
+ // If the only reason we're running this is because something else
525
+ // changed, then we can trust the dependency graph as to whether
526
+ // it's a cascading or non-cascading change. That is, if whatever
527
+ // /caused/ the error isn't supposed to affect other files, and
528
+ // whatever /fixes/ the error isn't supposed to affect other files,
529
+ // then there's no need to recompile any other inputs. If either of
530
+ // those are false, we /do/ need to recompile other inputs.
531
+ break ;
532
+ }
518
533
}
519
534
}
520
535
}
0 commit comments