@@ -51,7 +51,8 @@ private struct OpaqueQueuedIndexTask: Equatable {
5151}
5252
5353private enum InProgressIndexStore {
54- /// We are waiting for preparation of the file's target to finish before we can index it.
54+ /// We are waiting for preparation of the file's target to be scheduled. The next step is that we wait for
55+ /// prepration to finish before we can update the index store for this file.
5556 ///
5657 /// `preparationTaskID` identifies the preparation task so that we can transition a file's index state to
5758 /// `updatingIndexStore` when its preparation task has finished.
@@ -60,6 +61,16 @@ private enum InProgressIndexStore {
6061 /// task is still the sole owner of it and responsible for its cancellation.
6162 case waitingForPreparation( preparationTaskID: UUID , indexTask: Task < Void , Never > )
6263
64+ /// We have started preparing this file and are waiting for preparation to finish before we can update the index
65+ /// store for this file.
66+ ///
67+ /// `preparationTaskID` identifies the preparation task so that we can transition a file's index state to
68+ /// `updatingIndexStore` when its preparation task has finished.
69+ ///
70+ /// `indexTask` is a task that finishes after both preparation and index store update are done. Whoever owns the index
71+ /// task is still the sole owner of it and responsible for its cancellation.
72+ case preparing( preparationTaskID: UUID , indexTask: Task < Void , Never > )
73+
6374 /// The file's target has been prepared and we are updating the file's index store.
6475 ///
6576 /// `updateIndexStoreTask` is the task that updates the index store itself.
@@ -210,7 +221,7 @@ package final actor SemanticIndexManager {
210221 }
211222 let indexTasks = inProgressIndexTasks. mapValues { status in
212223 switch status {
213- case . waitingForPreparation:
224+ case . waitingForPreparation, . preparing :
214225 return IndexTaskStatus . scheduled
215226 case . updatingIndexStore( updateIndexStoreTask: let updateIndexStoreTask, indexTask: _) :
216227 return updateIndexStoreTask. isExecuting ? IndexTaskStatus . executing : IndexTaskStatus . scheduled
@@ -284,7 +295,17 @@ package final actor SemanticIndexManager {
284295 }
285296 if !indexFilesWithUpToDateUnit {
286297 let index = index. checked ( for: . modifiedFiles)
287- filesToIndex = filesToIndex. filter { !index. hasUpToDateUnit ( for: $0) }
298+ filesToIndex = filesToIndex. filter {
299+ if index. hasUpToDateUnit ( for: $0) {
300+ return false
301+ }
302+ if case . waitingForPreparation = inProgressIndexTasks [ $0] {
303+ // We haven't started preparing the file yet. Scheduling a new index operation for it won't produce any
304+ // more recent results.
305+ return false
306+ }
307+ return true
308+ }
288309 }
289310 await scheduleBackgroundIndex ( files: filesToIndex, indexFilesWithUpToDateUnit: indexFilesWithUpToDateUnit)
290311 generateBuildGraphTask = nil
@@ -312,11 +333,11 @@ package final actor SemanticIndexManager {
312333 for (_, status) in inProgressIndexTasks {
313334 switch status {
314335 case . waitingForPreparation( preparationTaskID: _, indexTask: let indexTask) ,
336+ . preparing( preparationTaskID: _, indexTask: let indexTask) ,
315337 . updatingIndexStore( updateIndexStoreTask: _, indexTask: let indexTask) :
316338 taskGroup. addTask {
317339 await indexTask. value
318340 }
319-
320341 }
321342 }
322343 await taskGroup. waitForAll ( )
@@ -462,7 +483,9 @@ package final actor SemanticIndexManager {
462483 private func prepare(
463484 targets: [ BuildTargetIdentifier ] ,
464485 purpose: TargetPreparationPurpose ,
465- priority: TaskPriority ?
486+ priority: TaskPriority ? ,
487+ executionStatusChangedCallback: @escaping ( QueuedTask < AnyIndexTaskDescription > , TaskExecutionState ) async -> Void =
488+ { _, _ in }
466489 ) async {
467490 // Perform a quick initial check whether the target is up-to-date, in which case we don't need to schedule a
468491 // preparation operation at all.
@@ -490,6 +513,7 @@ package final actor SemanticIndexManager {
490513 return
491514 }
492515 let preparationTask = await indexTaskScheduler. schedule ( priority: priority, taskDescription) { task, newState in
516+ await executionStatusChangedCallback ( task, newState)
493517 guard case . finished = newState else {
494518 self . indexProgressStatusDidChange ( )
495519 return
@@ -547,28 +571,36 @@ package final actor SemanticIndexManager {
547571 testHooks: testHooks
548572 )
549573 )
574+
550575 let updateIndexTask = await indexTaskScheduler. schedule ( priority: priority, taskDescription) { task, newState in
551576 guard case . finished = newState else {
552577 self . indexProgressStatusDidChange ( )
553578 return
554579 }
555580 for fileAndTarget in filesAndTargets {
556- if case . updatingIndexStore( OpaqueQueuedIndexTask ( task) , _) = self . inProgressIndexTasks [
557- fileAndTarget. file. sourceFile
558- ] {
559- self . inProgressIndexTasks [ fileAndTarget. file. sourceFile] = nil
581+ switch self . inProgressIndexTasks [ fileAndTarget. file. sourceFile] {
582+ case . updatingIndexStore( let registeredTask, _) :
583+ if registeredTask == OpaqueQueuedIndexTask ( task) {
584+ self . inProgressIndexTasks [ fileAndTarget. file. sourceFile] = nil
585+ }
586+ case . waitingForPreparation( let registeredTask, _) , . preparing( let registeredTask, _) :
587+ if registeredTask == preparationTaskID {
588+ self . inProgressIndexTasks [ fileAndTarget. file. sourceFile] = nil
589+ }
590+ case nil :
591+ break
560592 }
561593 }
562594 self . indexProgressStatusDidChange ( )
563595 }
564596 for fileAndTarget in filesAndTargets {
565- if case . waitingForPreparation( preparationTaskID, let indexTask) = inProgressIndexTasks [
566- fileAndTarget. file. sourceFile
567- ] {
597+ switch inProgressIndexTasks [ fileAndTarget. file. sourceFile] {
598+ case . waitingForPreparation( preparationTaskID, let indexTask) , . preparing( preparationTaskID, let indexTask) :
568599 inProgressIndexTasks [ fileAndTarget. file. sourceFile] = . updatingIndexStore(
569600 updateIndexStoreTask: OpaqueQueuedIndexTask ( updateIndexTask) ,
570601 indexTask: indexTask
571602 )
603+ default : break
572604 }
573605 }
574606 return await updateIndexTask. waitToFinishPropagatingCancellation ( )
@@ -639,9 +671,24 @@ package final actor SemanticIndexManager {
639671 // (https://github.com/swiftlang/sourcekit-lsp/issues/1262)
640672 for targetsBatch in sortedTargets. partition ( intoBatchesOfSize: 1 ) {
641673 let preparationTaskID = UUID ( )
674+ let filesToIndex = targetsBatch. flatMap ( { filesByTarget [ $0] ! } )
675+
642676 let indexTask = Task ( priority: priority) {
643677 // First prepare the targets.
644- await prepare ( targets: targetsBatch, purpose: . forIndexing, priority: priority)
678+ await prepare ( targets: targetsBatch, purpose: . forIndexing, priority: priority) { task, newState in
679+ if case . executing = newState {
680+ for file in filesToIndex {
681+ if case . waitingForPreparation( preparationTaskID: preparationTaskID, indexTask: let indexTask) =
682+ self . inProgressIndexTasks [ file. sourceFile]
683+ {
684+ self . inProgressIndexTasks [ file. sourceFile] = . preparing(
685+ preparationTaskID: preparationTaskID,
686+ indexTask: indexTask
687+ )
688+ }
689+ }
690+ }
691+ }
645692
646693 // And after preparation is done, index the files in the targets.
647694 await withTaskGroup ( of: Void . self) { taskGroup in
@@ -665,7 +712,6 @@ package final actor SemanticIndexManager {
665712 }
666713 indexTasks. append ( indexTask)
667714
668- let filesToIndex = targetsBatch. flatMap ( { filesByTarget [ $0] ! } )
669715 // The number of index tasks that don't currently have an in-progress task associated with it.
670716 // The denominator in the index progress should get incremented by this amount.
671717 // We don't want to increment the denominator for tasks that already have an index in progress.
0 commit comments