@@ -158,6 +158,7 @@ internal extension InterModuleDependencyGraph {
158158 /// between it and the root (source module being built by this driver
159159 /// instance) must also be re-built.
160160 func computeInvalidatedModuleDependencies( fileSystem: FileSystem ,
161+ cas: SwiftScanCAS ? ,
161162 forRebuild: Bool ,
162163 reporter: IncrementalCompilationState . Reporter ? = nil )
163164 throws -> Set < ModuleDependencyId > {
@@ -169,7 +170,7 @@ internal extension InterModuleDependencyGraph {
169170 for dependencyId in mainModuleInfo. directDependencies ?? [ ] {
170171 try outOfDateModuleScan ( from: dependencyId, visited: & visited,
171172 modulesRequiringRebuild: & modulesRequiringRebuild,
172- fileSystem: fileSystem, forRebuild: forRebuild,
173+ fileSystem: fileSystem, cas : cas , forRebuild: forRebuild,
173174 reporter: reporter)
174175 }
175176
@@ -183,10 +184,11 @@ internal extension InterModuleDependencyGraph {
183184 /// filter out those with a fully up-to-date output
184185 func filterMandatoryModuleDependencyCompileJobs( _ allJobs: [ Job ] ,
185186 fileSystem: FileSystem ,
187+ cas: SwiftScanCAS ? ,
186188 reporter: IncrementalCompilationState . Reporter ? = nil ) throws -> [ Job ] {
187189 // Determine which module pre-build jobs must be re-run
188190 let modulesRequiringReBuild =
189- try computeInvalidatedModuleDependencies ( fileSystem: fileSystem, forRebuild: true , reporter: reporter)
191+ try computeInvalidatedModuleDependencies ( fileSystem: fileSystem, cas : cas , forRebuild: true , reporter: reporter)
190192
191193 // Filter the `.generatePCM` and `.compileModuleFromInterface` jobs for
192194 // modules which do *not* need re-building.
@@ -209,6 +211,7 @@ internal extension InterModuleDependencyGraph {
209211 visited: inout Set < ModuleDependencyId > ,
210212 modulesRequiringRebuild: inout Set < ModuleDependencyId > ,
211213 fileSystem: FileSystem ,
214+ cas: SwiftScanCAS ? ,
212215 forRebuild: Bool ,
213216 reporter: IncrementalCompilationState . Reporter ? = nil ) throws {
214217 let reportOutOfDate = { ( name: String , reason: String ) in
@@ -227,7 +230,7 @@ internal extension InterModuleDependencyGraph {
227230 if !visited. contains ( dependencyId) {
228231 try outOfDateModuleScan ( from: dependencyId, visited: & visited,
229232 modulesRequiringRebuild: & modulesRequiringRebuild,
230- fileSystem: fileSystem, forRebuild: forRebuild,
233+ fileSystem: fileSystem, cas : cas , forRebuild: forRebuild,
231234 reporter: reporter)
232235 }
233236 // Even if we're not revisiting a dependency, we must check if it's already known to be out of date.
@@ -237,7 +240,7 @@ internal extension InterModuleDependencyGraph {
237240 if hasOutOfDateModuleDependency {
238241 reportOutOfDate ( sourceModuleId. moduleNameForDiagnostic, " Invalidated by downstream dependency " )
239242 modulesRequiringRebuild. insert ( sourceModuleId)
240- } else if try ! verifyModuleDependencyUpToDate( moduleID: sourceModuleId, fileSystem: fileSystem, reporter: reporter) {
243+ } else if try ! verifyModuleDependencyUpToDate( moduleID: sourceModuleId, fileSystem: fileSystem, cas : cas , reporter: reporter) {
241244 reportOutOfDate ( sourceModuleId. moduleNameForDiagnostic, " Out-of-date " )
242245 modulesRequiringRebuild. insert ( sourceModuleId)
243246 }
@@ -246,10 +249,44 @@ internal extension InterModuleDependencyGraph {
246249 visited. insert ( sourceModuleId)
247250 }
248251
252+ func outputMissingFromCAS( moduleInfo: ModuleInfo ,
253+ cas: SwiftScanCAS ? ) throws -> Bool {
254+ func casOutputMissing( _ key: String ? ) throws -> Bool {
255+ // Caching not enabled.
256+ guard let id = key, let cas = cas else { return false }
257+ // Do a local query to see if the output exists.
258+ let result = try cas. queryCacheKey ( id, globally: false )
259+ // Make sure all outputs are available in local CAS.
260+ guard let outputs = result else { return true }
261+ return !outputs. allSatisfy { $0. isMaterialized }
262+ }
263+
264+ switch moduleInfo. details {
265+ case . swift( let swiftDetails) :
266+ return try casOutputMissing ( swiftDetails. moduleCacheKey)
267+ case . clang( let clangDetails) :
268+ return try casOutputMissing ( clangDetails. moduleCacheKey)
269+ case . swiftPrebuiltExternal( _) :
270+ return false ;
271+ case . swiftPlaceholder( _) :
272+ // TODO: This should never ever happen. Hard error?
273+ return true ;
274+ }
275+ }
276+
249277 func verifyModuleDependencyUpToDate( moduleID: ModuleDependencyId ,
250278 fileSystem: FileSystem ,
279+ cas: SwiftScanCAS ? ,
251280 reporter: IncrementalCompilationState . Reporter ? ) throws -> Bool {
252281 let checkedModuleInfo = try moduleInfo ( of: moduleID)
282+ // Check if there is a module cache key available, then the content that pointed by the cache key must
283+ // exist for module to be up-to-date. Treat any CAS error as missing.
284+ let missingFromCAS = ( try ? outputMissingFromCAS ( moduleInfo: checkedModuleInfo, cas: cas) ) ?? true
285+ if missingFromCAS {
286+ reporter? . reportExplicitDependencyMissingFromCAS ( moduleID. moduleName)
287+ return false
288+ }
289+
253290 // Verify that the specified input exists and is older than the specified output
254291 let verifyInputOlderThanOutputModTime : ( String , VirtualPath , TimePoint ) -> Bool =
255292 { moduleName, inputPath, outputModTime in
0 commit comments