Merge pull request #20995 from Veykril/push-kysxxnruzslp

internal: Move `SymbolsDatabase` over to new salsa style
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index f2faf99..bb1741a 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -35,6 +35,9 @@
 
 mod display;
 
+#[doc(hidden)]
+pub use hir_def::ModuleId;
+
 use std::{
     fmt,
     mem::discriminant,
@@ -48,8 +51,8 @@
     AdtId, AssocItemId, AssocItemLoc, AttrDefId, CallableDefId, ConstId, ConstParamId,
     CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, ExternCrateId,
     FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
-    LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId, SyntheticSyntax,
-    TupleId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId,
+    LocalFieldId, Lookup, MacroExpander, MacroId, StaticId, StructId, SyntheticSyntax, TupleId,
+    TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId,
     expr_store::{ExpressionStoreDiagnostics, ExpressionStoreSourceMap},
     hir::{
         BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, LabelId, Pat,
diff --git a/crates/ide-db/src/apply_change.rs b/crates/ide-db/src/apply_change.rs
index 008b6fd..6a85c6e 100644
--- a/crates/ide-db/src/apply_change.rs
+++ b/crates/ide-db/src/apply_change.rs
@@ -3,10 +3,12 @@
 use base_db::SourceRootId;
 use profile::Bytes;
 use rustc_hash::FxHashSet;
-use salsa::{Database as _, Durability};
-use triomphe::Arc;
+use salsa::{Database as _, Durability, Setter as _};
 
-use crate::{ChangeWithProcMacros, RootDatabase, symbol_index::SymbolsDatabase};
+use crate::{
+    ChangeWithProcMacros, RootDatabase,
+    symbol_index::{LibraryRoots, LocalRoots},
+};
 
 impl RootDatabase {
     pub fn request_cancellation(&mut self) {
@@ -29,8 +31,8 @@
                     local_roots.insert(root_id);
                 }
             }
-            self.set_local_roots_with_durability(Arc::new(local_roots), Durability::MEDIUM);
-            self.set_library_roots_with_durability(Arc::new(library_roots), Durability::MEDIUM);
+            LocalRoots::get(self).set_roots(self).to(local_roots);
+            LibraryRoots::get(self).set_roots(self).to(library_roots);
         }
         change.apply(self);
     }
diff --git a/crates/ide-db/src/items_locator.rs b/crates/ide-db/src/items_locator.rs
index 4b0a84a..0d30553 100644
--- a/crates/ide-db/src/items_locator.rs
+++ b/crates/ide-db/src/items_locator.rs
@@ -10,7 +10,7 @@
 use crate::{
     RootDatabase,
     imports::import_assets::NameToImport,
-    symbol_index::{self, SymbolsDatabase as _},
+    symbol_index::{self, SymbolIndex},
 };
 
 /// A value to use, when uncertain which limit to pick.
@@ -110,7 +110,7 @@
             local_query
         }
     };
-    local_query.search(&[db.module_symbols(module)], |local_candidate| {
+    local_query.search(&[SymbolIndex::module_symbols(db, module)], |local_candidate| {
         cb(match local_candidate.def {
             hir::ModuleDef::Macro(macro_def) => ItemInNs::Macros(macro_def),
             def => ItemInNs::from(def),
diff --git a/crates/ide-db/src/lib.rs b/crates/ide-db/src/lib.rs
index 7efa97b..0301b50 100644
--- a/crates/ide-db/src/lib.rs
+++ b/crates/ide-db/src/lib.rs
@@ -64,7 +64,7 @@
 };
 use triomphe::Arc;
 
-use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase};
+use crate::line_index::LineIndex;
 pub use rustc_hash::{FxHashMap, FxHashSet, FxHasher};
 
 pub use ::line_index;
@@ -195,8 +195,12 @@
         db.set_all_crates(Arc::new(Box::new([])));
         CrateGraphBuilder::default().set_in_db(&mut db);
         db.set_proc_macros_with_durability(Default::default(), Durability::MEDIUM);
-        db.set_local_roots_with_durability(Default::default(), Durability::MEDIUM);
-        db.set_library_roots_with_durability(Default::default(), Durability::MEDIUM);
+        _ = crate::symbol_index::LibraryRoots::builder(Default::default())
+            .durability(Durability::MEDIUM)
+            .new(&db);
+        _ = crate::symbol_index::LocalRoots::builder(Default::default())
+            .durability(Durability::MEDIUM)
+            .new(&db);
         db.set_expand_proc_attr_macros_with_durability(false, Durability::HIGH);
         db.update_base_query_lru_capacities(lru_capacity);
         db
diff --git a/crates/ide-db/src/prime_caches.rs b/crates/ide-db/src/prime_caches.rs
index e661857..1463fdb 100644
--- a/crates/ide-db/src/prime_caches.rs
+++ b/crates/ide-db/src/prime_caches.rs
@@ -11,7 +11,7 @@
 use crate::{
     FxIndexMap, RootDatabase,
     base_db::{Crate, RootQueryDb},
-    symbol_index::SymbolsDatabase,
+    symbol_index::SymbolIndex,
 };
 
 /// We're indexing many crates.
@@ -107,8 +107,9 @@
                     Ok::<_, crossbeam_channel::SendError<_>>(())
                 };
                 let handle_symbols = |module| {
-                    let cancelled =
-                        Cancelled::catch(AssertUnwindSafe(|| _ = db.module_symbols(module)));
+                    let cancelled = Cancelled::catch(AssertUnwindSafe(|| {
+                        _ = SymbolIndex::module_symbols(&db, module)
+                    }));
 
                     match cancelled {
                         Ok(()) => progress_sender
diff --git a/crates/ide-db/src/symbol_index.rs b/crates/ide-db/src/symbol_index.rs
index c5ea9bc..ae95883 100644
--- a/crates/ide-db/src/symbol_index.rs
+++ b/crates/ide-db/src/symbol_index.rs
@@ -27,7 +27,7 @@
     ops::ControlFlow,
 };
 
-use base_db::{RootQueryDb, SourceDatabase, SourceRootId};
+use base_db::{RootQueryDb, SourceRootId};
 use fst::{Automaton, Streamer, raw::IndexedValue};
 use hir::{
     Crate, Module,
@@ -37,7 +37,6 @@
 };
 use rayon::prelude::*;
 use rustc_hash::FxHashSet;
-use triomphe::Arc;
 
 use crate::RootDatabase;
 
@@ -102,63 +101,26 @@
     }
 }
 
-#[query_group::query_group]
-pub trait SymbolsDatabase: HirDatabase + SourceDatabase {
-    /// The symbol index for a given module. These modules should only be in source roots that
-    /// are inside local_roots.
-    // FIXME: Is it worth breaking the encapsulation boundary of `hir`, and make this take a `ModuleId`,
-    // in order for it to be a non-interned query?
-    #[salsa::invoke_interned(module_symbols)]
-    fn module_symbols(&self, module: Module) -> Arc<SymbolIndex>;
-
-    /// The symbol index for a given source root within library_roots.
-    #[salsa::invoke_interned(library_symbols)]
-    fn library_symbols(&self, source_root_id: SourceRootId) -> Arc<SymbolIndex>;
-
-    #[salsa::transparent]
-    /// The symbol indices of modules that make up a given crate.
-    fn crate_symbols(&self, krate: Crate) -> Box<[Arc<SymbolIndex>]>;
-
-    /// The set of "local" (that is, from the current workspace) roots.
-    /// Files in local roots are assumed to change frequently.
-    #[salsa::input]
-    fn local_roots(&self) -> Arc<FxHashSet<SourceRootId>>;
-
-    /// The set of roots for crates.io libraries.
-    /// Files in libraries are assumed to never change.
-    #[salsa::input]
-    fn library_roots(&self) -> Arc<FxHashSet<SourceRootId>>;
+/// The set of roots for crates.io libraries.
+/// Files in libraries are assumed to never change.
+#[salsa::input(singleton, debug)]
+pub struct LibraryRoots {
+    #[returns(ref)]
+    pub roots: FxHashSet<SourceRootId>,
 }
 
-fn library_symbols(db: &dyn SymbolsDatabase, source_root_id: SourceRootId) -> Arc<SymbolIndex> {
-    let _p = tracing::info_span!("library_symbols").entered();
-
-    // We call this without attaching because this runs in parallel, so we need to attach here.
-    hir::attach_db(db, || {
-        let mut symbol_collector = SymbolCollector::new(db);
-
-        db.source_root_crates(source_root_id)
-            .iter()
-            .flat_map(|&krate| Crate::from(krate).modules(db))
-            // we specifically avoid calling other SymbolsDatabase queries here, even though they do the same thing,
-            // as the index for a library is not going to really ever change, and we do not want to store each
-            // the module or crate indices for those in salsa unless we need to.
-            .for_each(|module| symbol_collector.collect(module));
-
-        Arc::new(SymbolIndex::new(symbol_collector.finish()))
-    })
+/// The set of "local" (that is, from the current workspace) roots.
+/// Files in local roots are assumed to change frequently.
+#[salsa::input(singleton, debug)]
+pub struct LocalRoots {
+    #[returns(ref)]
+    pub roots: FxHashSet<SourceRootId>,
 }
 
-fn module_symbols(db: &dyn SymbolsDatabase, module: Module) -> Arc<SymbolIndex> {
-    let _p = tracing::info_span!("module_symbols").entered();
-
-    // We call this without attaching because this runs in parallel, so we need to attach here.
-    hir::attach_db(db, || Arc::new(SymbolIndex::new(SymbolCollector::new_module(db, module))))
-}
-
-pub fn crate_symbols(db: &dyn SymbolsDatabase, krate: Crate) -> Box<[Arc<SymbolIndex>]> {
+/// The symbol indices of modules that make up a given crate.
+pub fn crate_symbols(db: &dyn HirDatabase, krate: Crate) -> Box<[&SymbolIndex]> {
     let _p = tracing::info_span!("crate_symbols").entered();
-    krate.modules(db).into_iter().map(|module| db.module_symbols(module)).collect()
+    krate.modules(db).into_iter().map(|module| SymbolIndex::module_symbols(db, module)).collect()
 }
 
 // Feature: Workspace Symbol
@@ -190,20 +152,26 @@
     let _p = tracing::info_span!("world_symbols", query = ?query.query).entered();
 
     let indices: Vec<_> = if query.libs {
-        db.library_roots()
+        LibraryRoots::get(db)
+            .roots(db)
             .par_iter()
-            .map_with(db.clone(), |snap, &root| snap.library_symbols(root))
+            .for_each_with(db.clone(), |snap, &root| _ = SymbolIndex::library_symbols(snap, root));
+        LibraryRoots::get(db)
+            .roots(db)
+            .iter()
+            .map(|&root| SymbolIndex::library_symbols(db, root))
             .collect()
     } else {
         let mut crates = Vec::new();
 
-        for &root in db.local_roots().iter() {
+        for &root in LocalRoots::get(db).roots(db).iter() {
             crates.extend(db.source_root_crates(root).iter().copied())
         }
-        let indices: Vec<_> = crates
-            .into_par_iter()
-            .map_with(db.clone(), |snap, krate| snap.crate_symbols(krate.into()))
-            .collect();
+        crates
+            .par_iter()
+            .for_each_with(db.clone(), |snap, &krate| _ = crate_symbols(snap, krate.into()));
+        let indices: Vec<_> =
+            crates.into_iter().map(|krate| crate_symbols(db, krate.into())).collect();
         indices.iter().flat_map(|indices| indices.iter().cloned()).collect()
     };
 
@@ -221,6 +189,62 @@
     map: fst::Map<Vec<u8>>,
 }
 
+impl SymbolIndex {
+    /// The symbol index for a given source root within library_roots.
+    pub fn library_symbols(db: &dyn HirDatabase, source_root_id: SourceRootId) -> &SymbolIndex {
+        // FIXME:
+        #[salsa::interned]
+        struct InternedSourceRootId {
+            id: SourceRootId,
+        }
+        #[salsa::tracked(returns(ref))]
+        fn library_symbols(
+            db: &dyn HirDatabase,
+            source_root_id: InternedSourceRootId<'_>,
+        ) -> SymbolIndex {
+            let _p = tracing::info_span!("library_symbols").entered();
+
+            // We call this without attaching because this runs in parallel, so we need to attach here.
+            hir::attach_db(db, || {
+                let mut symbol_collector = SymbolCollector::new(db);
+
+                db.source_root_crates(source_root_id.id(db))
+                    .iter()
+                    .flat_map(|&krate| Crate::from(krate).modules(db))
+                    // we specifically avoid calling other SymbolsDatabase queries here, even though they do the same thing,
+                    // as the index for a library is not going to really ever change, and we do not want to store each
+                    // the module or crate indices for those in salsa unless we need to.
+                    .for_each(|module| symbol_collector.collect(module));
+
+                SymbolIndex::new(symbol_collector.finish())
+            })
+        }
+        library_symbols(db, InternedSourceRootId::new(db, source_root_id))
+    }
+
+    /// The symbol index for a given module. These modules should only be in source roots that
+    /// are inside local_roots.
+    pub fn module_symbols(db: &dyn HirDatabase, module: Module) -> &SymbolIndex {
+        // FIXME:
+        #[salsa::interned]
+        struct InternedModuleId {
+            id: hir::ModuleId,
+        }
+
+        #[salsa::tracked(returns(ref))]
+        fn module_symbols(db: &dyn HirDatabase, module: InternedModuleId<'_>) -> SymbolIndex {
+            let _p = tracing::info_span!("module_symbols").entered();
+
+            // We call this without attaching because this runs in parallel, so we need to attach here.
+            hir::attach_db(db, || {
+                SymbolIndex::new(SymbolCollector::new_module(db, module.id(db).into()))
+            })
+        }
+
+        module_symbols(db, InternedModuleId::new(db, hir::ModuleId::from(module)))
+    }
+}
+
 impl fmt::Debug for SymbolIndex {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("SymbolIndex").field("n_symbols", &self.symbols.len()).finish()
@@ -309,7 +333,7 @@
 impl Query {
     pub(crate) fn search<'sym, T>(
         self,
-        indices: &'sym [Arc<SymbolIndex>],
+        indices: &'sym [&SymbolIndex],
         cb: impl FnMut(&'sym FileSymbol) -> ControlFlow<T>,
     ) -> Option<T> {
         let _p = tracing::info_span!("symbol_index::Query::search").entered();
@@ -344,7 +368,7 @@
 
     fn search_maps<'sym, T>(
         &self,
-        indices: &'sym [Arc<SymbolIndex>],
+        indices: &'sym [&SymbolIndex],
         mut stream: fst::map::Union<'_>,
         mut cb: impl FnMut(&'sym FileSymbol) -> ControlFlow<T>,
     ) -> Option<T> {
@@ -397,7 +421,7 @@
 mod tests {
 
     use expect_test::expect_file;
-    use salsa::Durability;
+    use salsa::Setter;
     use test_fixture::{WORKSPACE, WithFixture};
 
     use super::*;
@@ -535,7 +559,7 @@
 
         let mut local_roots = FxHashSet::default();
         local_roots.insert(WORKSPACE);
-        db.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH);
+        LocalRoots::get(&db).set_roots(&mut db).to(local_roots);
 
         let mut query = Query::new("Foo".to_owned());
         let mut symbols = world_symbols(&db, query.clone());
diff --git a/crates/ide-ssr/src/lib.rs b/crates/ide-ssr/src/lib.rs
index 43ad12c1..66ece4e 100644
--- a/crates/ide-ssr/src/lib.rs
+++ b/crates/ide-ssr/src/lib.rs
@@ -80,7 +80,7 @@
 
 use crate::{errors::bail, matching::MatchFailureReason};
 use hir::{FileRange, Semantics};
-use ide_db::symbol_index::SymbolsDatabase;
+use ide_db::symbol_index::LocalRoots;
 use ide_db::text_edit::TextEdit;
 use ide_db::{EditionedFileId, FileId, FxHashMap, RootDatabase, base_db::SourceDatabase};
 use resolving::ResolvedRule;
@@ -138,8 +138,8 @@
 
     /// Constructs an instance using the start of the first file in `db` as the lookup context.
     pub fn at_first_file(db: &'db ide_db::RootDatabase) -> Result<MatchFinder<'db>, SsrError> {
-        if let Some(first_file_id) = db
-            .local_roots()
+        if let Some(first_file_id) = LocalRoots::get(db)
+            .roots(db)
             .iter()
             .next()
             .and_then(|root| db.source_root(*root).source_root(db).iter().next())
diff --git a/crates/ide-ssr/src/search.rs b/crates/ide-ssr/src/search.rs
index 72f857c..56484ae 100644
--- a/crates/ide-ssr/src/search.rs
+++ b/crates/ide-ssr/src/search.rs
@@ -9,6 +9,7 @@
     EditionedFileId, FileId, FxHashSet,
     defs::Definition,
     search::{SearchScope, UsageSearchResult},
+    symbol_index::LocalRoots,
 };
 use syntax::{AstNode, SyntaxKind, SyntaxNode, ast};
 
@@ -156,8 +157,7 @@
         if self.restrict_ranges.is_empty() {
             // Unrestricted search.
             use ide_db::base_db::SourceDatabase;
-            use ide_db::symbol_index::SymbolsDatabase;
-            for &root in self.sema.db.local_roots().iter() {
+            for &root in LocalRoots::get(self.sema.db).roots(self.sema.db).iter() {
                 let sr = self.sema.db.source_root(root).source_root(self.sema.db);
                 for file_id in sr.iter() {
                     callback(file_id);
diff --git a/crates/ide-ssr/src/tests.rs b/crates/ide-ssr/src/tests.rs
index 1bb435f..8520335 100644
--- a/crates/ide-ssr/src/tests.rs
+++ b/crates/ide-ssr/src/tests.rs
@@ -2,10 +2,10 @@
 use hir::{FilePosition, FileRange};
 use ide_db::{
     EditionedFileId, FxHashSet,
-    base_db::{SourceDatabase, salsa::Durability},
+    base_db::{SourceDatabase, salsa::Setter},
+    symbol_index::LocalRoots,
 };
 use test_utils::RangeOrOffset;
-use triomphe::Arc;
 
 use crate::{MatchFinder, SsrRule};
 
@@ -66,7 +66,6 @@
 /// `code` may optionally contain a cursor marker `$0`. If it doesn't, then the position will be
 /// the start of the file. If there's a second cursor marker, then we'll return a single range.
 pub(crate) fn single_file(code: &str) -> (ide_db::RootDatabase, FilePosition, Vec<FileRange>) {
-    use ide_db::symbol_index::SymbolsDatabase;
     use test_fixture::{WORKSPACE, WithFixture};
     let (mut db, file_id, range_or_offset) = if code.contains(test_utils::CURSOR_MARKER) {
         ide_db::RootDatabase::with_range_or_offset(code)
@@ -88,7 +87,7 @@
     }
     let mut local_roots = FxHashSet::default();
     local_roots.insert(WORKSPACE);
-    db.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH);
+    LocalRoots::get(&db).set_roots(&mut db).to(local_roots);
     (db, position, selections)
 }
 
diff --git a/crates/ide/src/ssr.rs b/crates/ide/src/ssr.rs
index 7df4499..dc8f343 100644
--- a/crates/ide/src/ssr.rs
+++ b/crates/ide/src/ssr.rs
@@ -59,11 +59,9 @@
     use expect_test::expect;
     use ide_assists::{Assist, AssistResolveStrategy};
     use ide_db::{
-        FileRange, FxHashSet, RootDatabase, base_db::salsa::Durability,
-        symbol_index::SymbolsDatabase,
+        FileRange, FxHashSet, RootDatabase, base_db::salsa::Setter as _, symbol_index::LocalRoots,
     };
     use test_fixture::WithFixture;
-    use triomphe::Arc;
 
     use super::ssr_assists;
 
@@ -74,7 +72,7 @@
         let (mut db, file_id, range_or_offset) = RootDatabase::with_range_or_offset(ra_fixture);
         let mut local_roots = FxHashSet::default();
         local_roots.insert(test_fixture::WORKSPACE);
-        db.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH);
+        LocalRoots::get(&db).set_roots(&mut db).to(local_roots);
         ssr_assists(
             &db,
             &resolve,
diff --git a/crates/rust-analyzer/src/cli/ssr.rs b/crates/rust-analyzer/src/cli/ssr.rs
index e3e3a14..975e81a 100644
--- a/crates/rust-analyzer/src/cli/ssr.rs
+++ b/crates/rust-analyzer/src/cli/ssr.rs
@@ -50,7 +50,6 @@
     /// for much else.
     pub fn run(self) -> anyhow::Result<()> {
         use ide_db::base_db::SourceDatabase;
-        use ide_db::symbol_index::SymbolsDatabase;
         let cargo_config =
             CargoConfig { all_targets: true, set_test: true, ..CargoConfig::default() };
         let load_cargo_config = LoadCargoConfig {
@@ -69,7 +68,7 @@
             match_finder.add_search_pattern(pattern)?;
         }
         if let Some(debug_snippet) = &self.debug {
-            for &root in db.local_roots().iter() {
+            for &root in ide_db::symbol_index::LocalRoots::get(db).roots(db).iter() {
                 let sr = db.source_root(root).source_root(db);
                 for file_id in sr.iter() {
                     for debug_info in match_finder.debug_where_text_equal(