@@ -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
0 commit comments