@@ -294,7 +294,6 @@ internal extension InterModuleDependencyGraph {
294294 let sourceModuleInfo = try moduleInfo ( of: sourceModuleId)
295295 // Visit the module's dependencies
296296 var hasOutOfDateModuleDependency = false
297- var mostRecentlyUpdatedDependencyOutput : TimePoint = . zero
298297 for dependencyId in sourceModuleInfo. directDependencies ?? [ ] {
299298 // If we have not already visited this module, recurse.
300299 if !visited. contains ( dependencyId) {
@@ -304,32 +303,101 @@ internal extension InterModuleDependencyGraph {
304303 }
305304 // Even if we're not revisiting a dependency, we must check if it's already known to be out of date.
306305 hasOutOfDateModuleDependency = hasOutOfDateModuleDependency || modulesRequiringRebuild. contains ( dependencyId)
307-
308- // Keep track of dependencies' output file time stamp to determine if it is newer than the current module.
309- if let depOutputTimeStamp = try ? fileSystem. lastModificationTime ( for: VirtualPath . lookup ( moduleInfo ( of: dependencyId) . modulePath. path) ) ,
310- depOutputTimeStamp > mostRecentlyUpdatedDependencyOutput {
311- mostRecentlyUpdatedDependencyOutput = depOutputTimeStamp
312- }
313306 }
314307
315308 if hasOutOfDateModuleDependency {
316309 reporter? . reportExplicitDependencyWillBeReBuilt ( sourceModuleId. moduleNameForDiagnostic, reason: " Invalidated by downstream dependency " )
317310 modulesRequiringRebuild. insert ( sourceModuleId)
318- } else if try ! IncrementalCompilationState. IncrementalDependencyAndInputSetup. verifyModuleDependencyUpToDate ( moduleID: sourceModuleId, moduleInfo: sourceModuleInfo,
319- fileSystem: fileSystem, reporter: reporter) {
311+ } else if try ! verifyModuleDependencyUpToDate( moduleID: sourceModuleId, fileSystem: fileSystem, reporter: reporter) {
320312 reporter? . reportExplicitDependencyWillBeReBuilt ( sourceModuleId. moduleNameForDiagnostic, reason: " Out-of-date " )
321313 modulesRequiringRebuild. insert ( sourceModuleId)
322- } else if let outputModTime = try ? fileSystem. lastModificationTime ( for: VirtualPath . lookup ( sourceModuleInfo. modulePath. path) ) ,
323- outputModTime < mostRecentlyUpdatedDependencyOutput {
324- // If a prior variant of this module dependnecy exists, and is older than any of its direct or transitive
325- // module dependency outputs, it must also be re-built.
326- reporter? . reportExplicitDependencyWillBeReBuilt ( sourceModuleId. moduleNameForDiagnostic, reason: " Has newer module dependency inputs " )
327- modulesRequiringRebuild. insert ( sourceModuleId)
328314 }
329315
330316 // Now that we've determined if this module must be rebuilt, mark it as visited.
331317 visited. insert ( sourceModuleId)
332318 }
319+
320+ func verifyModuleDependencyUpToDate( moduleID: ModuleDependencyId ,
321+ fileSystem: FileSystem ,
322+ reporter: IncrementalCompilationState . Reporter ? ) throws -> Bool {
323+ let checkedModuleInfo = try moduleInfo ( of: moduleID)
324+ // Verify that the specified input exists and is older than the specified output
325+ let verifyInputOlderThanOutputModTime : ( String , VirtualPath , TimePoint ) -> Bool =
326+ { moduleName, inputPath, outputModTime in
327+ guard let inputModTime =
328+ try ? fileSystem. lastModificationTime ( for: inputPath) else {
329+ reporter? . report ( " Unable to 'stat' \( inputPath. description) " )
330+ return false
331+ }
332+ if inputModTime > outputModTime {
333+ reporter? . reportExplicitDependencyOutOfDate ( moduleName,
334+ inputPath: inputPath. description)
335+ return false
336+ }
337+ return true
338+ }
339+
340+ // Check if the output file exists
341+ guard let outputModTime = try ? fileSystem. lastModificationTime ( for: VirtualPath . lookup ( checkedModuleInfo. modulePath. path) ) else {
342+ reporter? . report ( " Module output not found: ' \( moduleID. moduleNameForDiagnostic) ' " )
343+ return false
344+ }
345+
346+ // Check if a dependency of this module has a newer output than this module
347+ for dependencyId in checkedModuleInfo. directDependencies ?? [ ] {
348+ let dependencyInfo = try moduleInfo ( of: dependencyId)
349+ if !verifyInputOlderThanOutputModTime( moduleID. moduleName,
350+ VirtualPath . lookup ( dependencyInfo. modulePath. path) ,
351+ outputModTime) {
352+ return false
353+ }
354+ }
355+
356+ // Check if any of the textual sources of this module are newer than this module
357+ switch checkedModuleInfo. details {
358+ case . swift( let swiftDetails) :
359+ if let moduleInterfacePath = swiftDetails. moduleInterfacePath {
360+ if !verifyInputOlderThanOutputModTime( moduleID. moduleName,
361+ VirtualPath . lookup ( moduleInterfacePath. path) ,
362+ outputModTime) {
363+ return false
364+ }
365+ }
366+ if let bridgingHeaderPath = swiftDetails. bridgingHeaderPath {
367+ if !verifyInputOlderThanOutputModTime( moduleID. moduleName,
368+ VirtualPath . lookup ( bridgingHeaderPath. path) ,
369+ outputModTime) {
370+ return false
371+ }
372+ }
373+ for bridgingSourceFile in swiftDetails. bridgingSourceFiles ?? [ ] {
374+ if !verifyInputOlderThanOutputModTime( moduleID. moduleName,
375+ VirtualPath . lookup ( bridgingSourceFile. path) ,
376+ outputModTime) {
377+ return false
378+ }
379+ }
380+ case . clang( _) :
381+ for inputSourceFile in checkedModuleInfo. sourceFiles ?? [ ] {
382+ if !verifyInputOlderThanOutputModTime( moduleID. moduleName,
383+ try VirtualPath ( path: inputSourceFile) ,
384+ outputModTime) {
385+ return false
386+ }
387+ }
388+ case . swiftPrebuiltExternal( _) :
389+ // TODO: We have to give-up here until we have a way to verify the timestamp of the binary module.
390+ // We can do better here by knowing if this module hasn't changed - which would allows us to not
391+ // invalidate any of the dependencies that depend on it.
392+ reporter? . report ( " Unable to verify binary module dependency up-to-date: \( moduleID. moduleNameForDiagnostic) " )
393+ return false ;
394+ case . swiftPlaceholder( _) :
395+ // TODO: This should never ever happen. Hard error?
396+ return false ;
397+ }
398+
399+ return true
400+ }
333401}
334402
335403internal extension InterModuleDependencyGraph {
0 commit comments