Files
Rintaro Ishizaki 1276d6bfef Release SemanticIndexManager state on workspace shutdown
Two related retain cycles kept SemanticIndexManager (and the
TaskScheduler / BuildServerManager / ToolchainRegistry chain it
transitively holds) alive past workspace teardown.

1. SemanticIndexManager.inProgressIndexTasks (and the analogous
   preparation / per-file-change dictionaries) hold
   `Task<Void, Never>` values whose bodies capture `self`. The
   scheduler's per-task `.finished` callback normally clears the
   entry, but that callback is only invoked from
   `QueuedTask.execute` / `finalizeExecution`. A `.low`-priority
   `UpdateIndexStoreTaskDescription` that sat in `pendingTasks`
   (e.g. with background indexing paused) and was cancelled by
   `TaskScheduler.shutDown` without ever executing leaves its
   entry behind, pinning the SemanticIndexManager and everything
   downstream.

   Add `SemanticIndexManager.shutDown`, which cancels every
   in-progress indexTask and drops `inProgressIndexTasks`,
   `inProgressPreparationTasks`, `inProgressPrepareForEditorTask`,
   and `fileOrBuildTargetChangedTasks`. Call it from
   `Workspace.shutdown`.

2. `TaskScheduler.finalizeTaskExecution` unconditionally appended
   `.cancelledToBeRescheduled` tasks back to `pendingTasks`. After
   `shutDown` cleared the array, a racing `cancelToBeRescheduled`
   (from a `setMaxConcurrentTasksByPriority` sleep that elapsed
   mid-shutdown) would re-populate it. The re-added entry never
   drains - `poke` early-returns on `isShutDown` - and keeps the
   QueuedTask (and the SemanticIndexManager its callback captures)
   alive. Gate the append on `!isShutDown`.
2026-06-26 10:50:39 -07:00

31 KiB