Skip to content

Commit 418b607

Browse files
author
David Ungar
committed
Add info about externals when -driver-show-incremental is present.
1 parent 391204e commit 418b607

File tree

4 files changed

+93
-26
lines changed

4 files changed

+93
-26
lines changed

Sources/SwiftDriver/IncrementalCompilation/DependencyKey.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,3 +367,23 @@ extension DependencyKey: Comparable {
367367

368368
extension DependencyKey.Designator: Comparable {
369369
}
370+
371+
// MARK: - InvalidationReason
372+
extension ExternalDependency {
373+
public enum InvalidationReason: String {
374+
case added, changed, testing
375+
init?(_ graph: ModuleDependencyGraph,
376+
isNewToTheGraph: Bool ,
377+
_ externalDependency: ExternalDependency) {
378+
if isNewToTheGraph {
379+
self = .added
380+
return
381+
}
382+
if graph.hasFileChanged(of: externalDependency) {
383+
self = .changed
384+
return
385+
}
386+
return nil
387+
}
388+
}
389+
}

Sources/SwiftDriver/IncrementalCompilation/IncrementalCompilationState.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,19 @@ extension IncrementalCompilationState {
428428
func reportIncrementalCompilationHasBeenDisabled(_ why: String) {
429429
report("Incremental compilation has been disabled, \(why)")
430430
}
431+
432+
func reportInvalidated<Nodes: Sequence>(
433+
_ nodes: Nodes,
434+
by externalDependency: ExternalDependency,
435+
_ why: ExternalDependency.InvalidationReason
436+
)
437+
where Nodes.Element == ModuleDependencyGraph.Node
438+
{
439+
let depString = externalDependency.shortDescription
440+
for node in nodes {
441+
report("\(why): \(depString) -> \(node)")
442+
}
443+
}
431444
}
432445
}
433446

Sources/SwiftDriver/IncrementalCompilation/ModuleDependencyGraph.swift

Lines changed: 59 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,32 @@ extension ModuleDependencyGraph {
9999
}
100100
}
101101

102+
var shouldNewExternalDependenciesTriggerInvalidation: Bool {
103+
switch self {
104+
case .buildingWithoutAPrior:
105+
// Reading graph from a swiftdeps file,
106+
// so every incremental external dependency found will be new to the
107+
// graph. Don't invalidate just 'cause it's new.
108+
return false
109+
110+
case .buildingAfterEachCompilation:
111+
// Will be compiling every file, so no need to invalidate based on
112+
// found external dependencies.
113+
return false
114+
115+
// Reading a swiftdeps file after a compilation.
116+
// A new external dependency represents an addition.
117+
// So must invalidate based on it.
118+
case .updatingAfterCompilation:
119+
return true
120+
121+
case .updatingFromAPrior:
122+
// If the graph was read from priors,
123+
// then any new external dependency must also be an addition.
124+
return true
125+
}
126+
}
127+
102128
var isCompilingAllInputsNoMatterWhat: Bool {
103129
switch self {
104130
case .buildingAfterEachCompilation:
@@ -239,6 +265,7 @@ extension ModuleDependencyGraph {
239265
/// As an optimization, only return the nodes that have not been already traced, because the traced nodes
240266
/// will have already been used to schedule jobs to run.
241267
/*@_spi(Testing)*/ public func collectUntracedNodesUsing(
268+
_ why: ExternalDependency.InvalidationReason,
242269
_ fingerprintedExternalDependency: FingerprintedExternalDependency
243270
) -> DirectlyInvalidatedNodeSet {
244271
// These nodes will depend on the *interface* of the external Decl.
@@ -251,10 +278,12 @@ extension ModuleDependencyGraph {
251278
let node = Node(key: key,
252279
fingerprint: fingerprintedExternalDependency.fingerprint,
253280
dependencySource: nil)
254-
return DirectlyInvalidatedNodeSet(
281+
let untracedUses = DirectlyInvalidatedNodeSet(
255282
nodeFinder
256283
.uses(of: node)
257284
.filter({ use in use.isUntraced }))
285+
info.reporter?.reportInvalidated(untracedUses, by: fingerprintedExternalDependency.externalDependency, why)
286+
return untracedUses
258287
}
259288

260289
/// Find all the inputs known to need recompilation as a consequence of reading a swiftdeps or swiftmodule
@@ -309,36 +338,38 @@ extension ModuleDependencyGraph {
309338

310339
let isNewToTheGraph = isPresentInTheGraph != true && fingerprintedExternalDependencies.insert(fed).inserted
311340

312-
// If the graph already includes prior externals, then any new externals are changes
313-
// Short-circuit conjunction may avoid the modTime query
314-
let shouldTryToProcess = info.isCrossModuleIncrementalBuildEnabled &&
315-
(isNewToTheGraph || hasFileChanged(of: fed.externalDependency))
341+
// Even if invalidation won't be reported to the caller, a new or added
342+
// incremental external dependency may require integration in order to
343+
// transitively close them, (e.g. if an imported module imports a module).
344+
let whyIntegrateForClosure = info.isCrossModuleIncrementalBuildEnabled
345+
? ExternalDependency.InvalidationReason(self,
346+
isNewToTheGraph: isNewToTheGraph,
347+
fed.externalDependency)
348+
: nil
316349

317-
// Do this no matter what in order to integrate any incremental external dependencies.
318-
let invalidatedNodesFromIncrementalExternal = shouldTryToProcess
319-
? collectNodesInvalidatedByAttemptingToProcess(fed, info)
320-
: nil
350+
let invalidatedNodesFromIncrementalExternal = whyIntegrateForClosure.flatMap { why in
351+
collectNodesInvalidatedByAttemptingToProcess(why, fed)
352+
}
321353

322354
if phase.isCompilingAllInputsNoMatterWhat {
323355
// going to compile every input anyway, less work for callers
324356
return DirectlyInvalidatedNodeSet()
325357
}
326358

327-
/// When building a graph from scratch, an unchanged but new-to-the-graph external dependendcy should be ignored.
328-
/// Otherwise, it represents an added Import
329-
let callerWantsTheseChanges = (phase.isUpdating && isNewToTheGraph) ||
330-
hasFileChanged(of: fed.externalDependency)
331-
332-
guard callerWantsTheseChanges else {
359+
guard let whyInvalidate = ExternalDependency.InvalidationReason(
360+
self,
361+
isNewToTheGraph: phase.shouldNewExternalDependenciesTriggerInvalidation && isNewToTheGraph,
362+
fed.externalDependency)
363+
else {
333364
return DirectlyInvalidatedNodeSet()
334365
}
335366

336367
// If there was an error integrating the external dependency, or if it was not an incremental one,
337368
// return anything that uses that dependency.
338-
return invalidatedNodesFromIncrementalExternal ?? collectUntracedNodesUsing(fed)
369+
return invalidatedNodesFromIncrementalExternal ?? collectUntracedNodesUsing(whyInvalidate, fed)
339370
}
340371

341-
private func hasFileChanged(of externalDependency: ExternalDependency
372+
func hasFileChanged(of externalDependency: ExternalDependency
342373
) -> Bool {
343374
if let hasChanged = externalDependencyModTimeCache[externalDependency] {
344375
return hasChanged
@@ -355,14 +386,17 @@ extension ModuleDependencyGraph {
355386
/// Try to read and integrate an external dependency.
356387
/// Return nil if it's not incremental, or if an error occurs.
357388
private func collectNodesInvalidatedByAttemptingToProcess(
358-
_ fed: FingerprintedExternalDependency,
359-
_ info: IncrementalCompilationState.IncrementalDependencyAndInputSetup) -> DirectlyInvalidatedNodeSet? {
360-
fed.incrementalDependencySource?
361-
.read(in: info.fileSystem, reporter: info.reporter)
362-
.map { unserializedDepGraph in
363-
info.reporter?.report("Integrating changes from: \(fed.externalDependency)")
364-
return Integrator.integrate(from: unserializedDepGraph, into: self)
365-
}
389+
_ why: ExternalDependency.InvalidationReason,
390+
_ fed: FingerprintedExternalDependency
391+
) -> DirectlyInvalidatedNodeSet? {
392+
guard let source = fed.incrementalDependencySource,
393+
let unserializedDepGraph = source.read(in: info.fileSystem, reporter: info.reporter)
394+
else {
395+
return nil
396+
}
397+
let invalidatedNodes = Integrator.integrate(from: unserializedDepGraph, into: self)
398+
info.reporter?.reportInvalidated(invalidatedNodes, by: fed.externalDependency, why)
399+
return invalidatedNodes
366400
}
367401
}
368402

Tests/SwiftDriverTests/ModuleDependencyGraphTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1014,7 +1014,7 @@ extension ModuleDependencyGraph {
10141014
on fingerprintedExternalDependency: FingerprintedExternalDependency
10151015
) -> [DependencySource] {
10161016
var foundSources = [DependencySource]()
1017-
for dependent in collectUntracedNodesUsing(fingerprintedExternalDependency) {
1017+
for dependent in collectUntracedNodesUsing(.testing, fingerprintedExternalDependency) {
10181018
let dependencySource = dependent.dependencySource!
10191019
foundSources.append(dependencySource)
10201020
// findSwiftDepsToRecompileWhenWholeSwiftDepChanges is reflexive

0 commit comments

Comments
 (0)