@@ -149,12 +149,12 @@ extension IncrementalCompilationState.FirstWaveComputer {
149149 throws -> Set < ModuleDependencyId > {
150150 let mainModuleInfo = moduleDependencyGraph. mainModule
151151 var modulesRequiringRebuild : Set < ModuleDependencyId > = [ ]
152- var visitedModules : Set < ModuleDependencyId > = [ ]
152+ var visited : Set < ModuleDependencyId > = [ ]
153153 // Scan from the main module's dependencies to avoid reporting
154154 // the main module itself in the results.
155155 for dependencyId in mainModuleInfo. directDependencies ?? [ ] {
156- try outOfDateModuleScan ( on: moduleDependencyGraph, from: dependencyId, visited : & visitedModules ,
157- modulesRequiringRebuild: & modulesRequiringRebuild)
156+ try outOfDateModuleScan ( on: moduleDependencyGraph, from: dependencyId,
157+ visited : & visited , modulesRequiringRebuild: & modulesRequiringRebuild)
158158 }
159159
160160 reporter? . reportExplicitDependencyReBuildSet ( Array ( modulesRequiringRebuild) )
@@ -164,31 +164,46 @@ extension IncrementalCompilationState.FirstWaveComputer {
164164 /// Perform a postorder DFS to locate modules which are out-of-date with respect
165165 /// to their inputs. Upon encountering such a module, add it to the set of invalidated
166166 /// modules, along with the path from the root to this module.
167+ ///
168+ /// Returns the last-modification-time of the newest module dependency output file,
169+ /// direct or transitive.
167170 private func outOfDateModuleScan( on moduleDependencyGraph: InterModuleDependencyGraph ,
168171 from moduleId: ModuleDependencyId ,
169172 visited: inout Set < ModuleDependencyId > ,
170173 modulesRequiringRebuild: inout Set < ModuleDependencyId > ) throws {
171174 let moduleInfo = try moduleDependencyGraph. moduleInfo ( of: moduleId)
172175 // Visit the module's dependencies
173176 var hasOutOfDateModuleDependency = false
177+ var mostRecentlyUpdatedDependencyOutput : TimePoint = . zero
174178 for dependencyId in moduleInfo. directDependencies ?? [ ] {
175179 // If we have not already visited this module, recurse.
176180 if !visited. contains ( dependencyId) {
177181 try outOfDateModuleScan ( on: moduleDependencyGraph, from: dependencyId,
178- visited: & visited,
179- modulesRequiringRebuild: & modulesRequiringRebuild)
182+ visited: & visited, modulesRequiringRebuild: & modulesRequiringRebuild)
180183 }
181184 // Even if we're not revisiting a dependency, we must check if it's already known to be out of date.
182185 hasOutOfDateModuleDependency = hasOutOfDateModuleDependency || modulesRequiringRebuild. contains ( dependencyId)
186+
187+ // Keep track of dependencies' output file time stamp to determine if it is newer than the current module.
188+ if let depOutputTimeStamp = try ? fileSystem. lastModificationTime ( for: VirtualPath . lookup ( moduleDependencyGraph. moduleInfo ( of: dependencyId) . modulePath. path) ) ,
189+ depOutputTimeStamp > mostRecentlyUpdatedDependencyOutput {
190+ mostRecentlyUpdatedDependencyOutput = depOutputTimeStamp
191+ }
183192 }
184193
185194 if hasOutOfDateModuleDependency {
186- reporter? . reportExplicitDependencyWillBeReBuilt ( moduleId. moduleNameForDiagnostic, reason: " Invalidated by downstream dependency " )
187- modulesRequiringRebuild. insert ( moduleId)
195+ reporter? . reportExplicitDependencyWillBeReBuilt ( moduleId. moduleNameForDiagnostic, reason: " Invalidated by downstream dependency " )
196+ modulesRequiringRebuild. insert ( moduleId)
188197 } else if try ! IncrementalCompilationState. IncrementalDependencyAndInputSetup. verifyModuleDependencyUpToDate ( moduleID: moduleId, moduleInfo: moduleInfo,
189198 fileSystem: fileSystem, reporter: reporter) {
190- reporter? . reportExplicitDependencyWillBeReBuilt ( moduleId. moduleNameForDiagnostic, reason: " Out-of-date " )
191- modulesRequiringRebuild. insert ( moduleId)
199+ reporter? . reportExplicitDependencyWillBeReBuilt ( moduleId. moduleNameForDiagnostic, reason: " Out-of-date " )
200+ modulesRequiringRebuild. insert ( moduleId)
201+ } else if let outputModTime = try ? fileSystem. lastModificationTime ( for: VirtualPath . lookup ( moduleInfo. modulePath. path) ) ,
202+ outputModTime < mostRecentlyUpdatedDependencyOutput {
203+ // If a prior variant of this module dependnecy exists, and is older than any of its direct or transitive
204+ // module dependency outputs, it must also be re-built.
205+ reporter? . reportExplicitDependencyWillBeReBuilt ( moduleId. moduleNameForDiagnostic, reason: " Has newer module dependency inputs " )
206+ modulesRequiringRebuild. insert ( moduleId)
192207 }
193208
194209 // Now that we've determined if this module must be rebuilt, mark it as visited.
0 commit comments