diff --git a/Cargo.lock b/Cargo.lock index 6d910ad0ab..d4f78a22be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -376,7 +376,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.66", + "syn", ] [[package]] @@ -617,7 +617,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.66", + "syn", ] [[package]] @@ -628,7 +628,7 @@ checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" dependencies = [ "darling_core", "quote", - "syn 2.0.66", + "syn", ] [[package]] @@ -699,7 +699,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn", ] [[package]] @@ -1092,7 +1092,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn", ] [[package]] @@ -1260,7 +1260,7 @@ dependencies = [ "Inflector", "proc-macro2", "quote", - "syn 2.0.66", + "syn", ] [[package]] @@ -1386,7 +1386,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2ae40017ac09cd2c6a53504cb3c871c7f2b41466eac5bc66ba63f39073b467b" dependencies = [ "quote", - "syn 2.0.66", + "syn", ] [[package]] @@ -2010,7 +2010,7 @@ dependencies = [ "ruff_python_stdlib", "ruff_text_size", "rustc-hash", - "salsa-2022", + "salsa", "smallvec", "smol_str", "tempfile", @@ -2196,7 +2196,7 @@ dependencies = [ "ruff_source_file", "ruff_text_size", "rustc-hash", - "salsa-2022", + "salsa", "tracing", "zip", ] @@ -2345,7 +2345,7 @@ dependencies = [ "proc-macro2", "quote", "ruff_python_trivia", - "syn 2.0.66", + "syn", ] [[package]] @@ -2719,9 +2719,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] -name = "salsa-2022" -version = "0.1.0" -source = "git+https://github.com/salsa-rs/salsa.git?rev=05b4e3ebdcdc47730cdd359e7e97fb2470527279#05b4e3ebdcdc47730cdd359e7e97fb2470527279" +name = "salsa" +version = "0.18.0" +source = "git+https://github.com/salsa-rs/salsa.git?rev=f706aa2d32d473ee633a77c1af01d180c85da308#f706aa2d32d473ee633a77c1af01d180c85da308" dependencies = [ "arc-swap", "crossbeam", @@ -2732,20 +2732,21 @@ dependencies = [ "log", "parking_lot", "rustc-hash", - "salsa-2022-macros", + "salsa-macros", "smallvec", ] [[package]] -name = "salsa-2022-macros" -version = "0.1.0" -source = "git+https://github.com/salsa-rs/salsa.git?rev=05b4e3ebdcdc47730cdd359e7e97fb2470527279#05b4e3ebdcdc47730cdd359e7e97fb2470527279" +name = "salsa-macros" +version = "0.18.0" +source = "git+https://github.com/salsa-rs/salsa.git?rev=f706aa2d32d473ee633a77c1af01d180c85da308#f706aa2d32d473ee633a77c1af01d180c85da308" dependencies = [ "eyre", "heck 0.4.1", "proc-macro2", "quote", - "syn 1.0.109", + "syn", + "synstructure", ] [[package]] @@ -2778,7 +2779,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.66", + "syn", ] [[package]] @@ -2827,7 +2828,7 @@ checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn", ] [[package]] @@ -2838,7 +2839,7 @@ checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn", ] [[package]] @@ -2860,7 +2861,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn", ] [[package]] @@ -2901,7 +2902,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.66", + "syn", ] [[package]] @@ -3007,7 +3008,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.66", + "syn", ] [[package]] @@ -3016,17 +3017,6 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "syn" version = "2.0.66" @@ -3046,7 +3036,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn", ] [[package]] @@ -3102,7 +3092,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.66", + "syn", ] [[package]] @@ -3113,7 +3103,7 @@ checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn", "test-case-core", ] @@ -3134,7 +3124,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn", ] [[package]] @@ -3256,7 +3246,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn", ] [[package]] @@ -3492,7 +3482,7 @@ checksum = "9881bea7cbe687e36c9ab3b778c36cd0487402e270304e8b1296d5085303c1a2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn", ] [[package]] @@ -3577,7 +3567,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.66", + "syn", "wasm-bindgen-shared", ] @@ -3611,7 +3601,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3644,7 +3634,7 @@ checksum = "b7f89739351a2e03cb94beb799d47fb2cac01759b40ec441f7de39b00cbf7ef0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn", ] [[package]] @@ -3928,7 +3918,7 @@ checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn", "synstructure", ] @@ -3949,7 +3939,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn", ] [[package]] @@ -3969,7 +3959,7 @@ checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn", "synstructure", ] @@ -3998,7 +3988,7 @@ checksum = "97cf56601ee5052b4417d90c8755c6683473c926039908196cf35d99f893ebe7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index fd1ab491e0..fbf2f728de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -106,7 +106,7 @@ rand = { version = "0.8.5" } rayon = { version = "1.10.0" } regex = { version = "1.10.2" } rustc-hash = { version = "1.1.0" } -salsa = { git = "https://github.com/salsa-rs/salsa.git", package = "salsa-2022", rev = "05b4e3ebdcdc47730cdd359e7e97fb2470527279" } +salsa = { git = "https://github.com/salsa-rs/salsa.git", rev = "f706aa2d32d473ee633a77c1af01d180c85da308" } schemars = { version = "0.8.16" } seahash = { version = "4.1.0" } serde = { version = "1.0.197", features = ["derive"] } diff --git a/crates/red_knot_python_semantic/src/db.rs b/crates/red_knot_python_semantic/src/db.rs index 9c61096ebb..bede75991f 100644 --- a/crates/red_knot_python_semantic/src/db.rs +++ b/crates/red_knot_python_semantic/src/db.rs @@ -13,10 +13,10 @@ use crate::types::{infer_types, public_symbol_ty}; #[salsa::jar(db=Db)] pub struct Jar( - ModuleNameIngredient, + ModuleNameIngredient<'_>, ModuleResolverSearchPaths, - ScopeId, - PublicSymbolId, + ScopeId<'_>, + PublicSymbolId<'_>, symbol_table, resolve_module_query, file_to_module, @@ -37,9 +37,10 @@ pub(crate) mod tests { use std::marker::PhantomData; use std::sync::Arc; + use salsa::id::AsId; use salsa::ingredient::Ingredient; use salsa::storage::HasIngredientsFor; - use salsa::{AsId, DebugWithDb}; + use salsa::DebugWithDb; use ruff_db::file_system::{FileSystem, MemoryFileSystem, OsFileSystem}; use ruff_db::vfs::Vfs; @@ -82,7 +83,6 @@ pub(crate) mod tests { /// This useful for testing advanced file system features like permissions, symlinks, etc. /// /// Note that any files written to the memory file system won't be copied over. - #[allow(unused)] pub(crate) fn with_os_file_system(&mut self) { self.file_system = TestFileSystem::Os(OsFileSystem); } @@ -157,44 +157,43 @@ pub(crate) mod tests { enum TestFileSystem { Memory(MemoryFileSystem), - #[allow(unused)] Os(OsFileSystem), } - pub(crate) fn assert_will_run_function_query( - db: &Db, + pub(crate) fn assert_will_run_function_query<'db, C, Db, Jar>( + db: &'db Db, to_function: impl FnOnce(&C) -> &salsa::function::FunctionIngredient, - key: C::Key, + input: &C::Input<'db>, events: &[salsa::Event], ) where C: salsa::function::Configuration + salsa::storage::IngredientsFor, Jar: HasIngredientsFor, Db: salsa::DbWithJar, - C::Key: AsId, + C::Input<'db>: AsId, { - will_run_function_query(db, to_function, key, events, true); + will_run_function_query(db, to_function, input, events, true); } - pub(crate) fn assert_will_not_run_function_query( - db: &Db, + pub(crate) fn assert_will_not_run_function_query<'db, C, Db, Jar>( + db: &'db Db, to_function: impl FnOnce(&C) -> &salsa::function::FunctionIngredient, - key: C::Key, + input: &C::Input<'db>, events: &[salsa::Event], ) where C: salsa::function::Configuration + salsa::storage::IngredientsFor, Jar: HasIngredientsFor, Db: salsa::DbWithJar, - C::Key: AsId, + C::Input<'db>: AsId, { - will_run_function_query(db, to_function, key, events, false); + will_run_function_query(db, to_function, input, events, false); } - fn will_run_function_query( - db: &Db, + fn will_run_function_query<'db, C, Db, Jar>( + db: &'db Db, to_function: impl FnOnce(&C) -> &salsa::function::FunctionIngredient, - key: C::Key, + input: &C::Input<'db>, events: &[salsa::Event], should_run: bool, ) where @@ -202,7 +201,7 @@ pub(crate) mod tests { + salsa::storage::IngredientsFor, Jar: HasIngredientsFor, Db: salsa::DbWithJar, - C::Key: AsId, + C::Input<'db>: AsId, { let (jar, _) = <_ as salsa::storage::HasJar<::Jar>>::jar(db); @@ -218,7 +217,7 @@ pub(crate) mod tests { let did_run = events.iter().any(|event| { if let salsa::EventKind::WillExecute { database_key } = event.kind { database_key.ingredient_index() == ingredient_index - && database_key.key_index() == key.as_id() + && database_key.key_index() == input.as_id() } else { false } @@ -229,7 +228,7 @@ pub(crate) mod tests { "Expected query {:?} to run but it didn't", DebugIdx { db: PhantomData::, - value_id: key.as_id(), + value_id: input.as_id(), ingredient: function_ingredient, } ); @@ -238,7 +237,7 @@ pub(crate) mod tests { "Expected query {:?} not to run but it did", DebugIdx { db: PhantomData::, - value_id: key.as_id(), + value_id: input.as_id(), ingredient: function_ingredient, } ); diff --git a/crates/red_knot_python_semantic/src/module/resolver.rs b/crates/red_knot_python_semantic/src/module/resolver.rs index 9275836fae..673d7adb23 100644 --- a/crates/red_knot_python_semantic/src/module/resolver.rs +++ b/crates/red_knot_python_semantic/src/module/resolver.rs @@ -41,9 +41,9 @@ pub fn resolve_module(db: &dyn Db, module_name: ModuleName) -> Option { /// This query should not be called directly. Instead, use [`resolve_module`]. It only exists /// because Salsa requires the module name to be an ingredient. #[salsa::tracked] -pub(crate) fn resolve_module_query( - db: &dyn Db, - module_name: internal::ModuleNameIngredient, +pub(crate) fn resolve_module_query<'db>( + db: &'db dyn Db, + module_name: internal::ModuleNameIngredient<'db>, ) -> Option { let _ = tracing::trace_span!("resolve_module", module_name = ?module_name.debug(db)).enter(); @@ -221,7 +221,7 @@ pub(crate) mod internal { /// /// This is needed because Salsa requires that all query arguments are salsa ingredients. #[salsa::interned] - pub(crate) struct ModuleNameIngredient { + pub(crate) struct ModuleNameIngredient<'db> { #[return_ref] pub(super) name: ModuleName, } diff --git a/crates/red_knot_python_semantic/src/semantic_index.rs b/crates/red_knot_python_semantic/src/semantic_index.rs index 13c20f3e34..402abffc6c 100644 --- a/crates/red_knot_python_semantic/src/semantic_index.rs +++ b/crates/red_knot_python_semantic/src/semantic_index.rs @@ -42,7 +42,7 @@ pub(crate) fn semantic_index(db: &dyn Db, file: VfsFile) -> SemanticIndex { /// Salsa can avoid invalidating dependent queries if this scope's symbol table /// is unchanged. #[salsa::tracked] -pub(crate) fn symbol_table(db: &dyn Db, scope: ScopeId) -> Arc { +pub(crate) fn symbol_table<'db>(db: &'db dyn Db, scope: ScopeId<'db>) -> Arc { let _ = tracing::trace_span!("symbol_table", scope = ?scope.debug(db)).enter(); let index = semantic_index(db, scope.file(db)); @@ -51,7 +51,7 @@ pub(crate) fn symbol_table(db: &dyn Db, scope: ScopeId) -> Arc { /// Returns the root scope of `file`. #[salsa::tracked] -pub(crate) fn root_scope(db: &dyn Db, file: VfsFile) -> ScopeId { +pub(crate) fn root_scope(db: &dyn Db, file: VfsFile) -> ScopeId<'_> { let _ = tracing::trace_span!("root_scope", file = ?file.debug(db.upcast())).enter(); FileScopeId::root().to_scope_id(db, file) @@ -59,7 +59,11 @@ pub(crate) fn root_scope(db: &dyn Db, file: VfsFile) -> ScopeId { /// Returns the symbol with the given name in `file`'s public scope or `None` if /// no symbol with the given name exists. -pub fn public_symbol(db: &dyn Db, file: VfsFile, name: &str) -> Option { +pub fn public_symbol<'db>( + db: &'db dyn Db, + file: VfsFile, + name: &str, +) -> Option> { let root_scope = root_scope(db, file); let symbol_table = symbol_table(db, root_scope); let local = symbol_table.symbol_id_by_name(name)?; @@ -104,7 +108,6 @@ impl SemanticIndex { } /// Returns the ID of the `expression`'s enclosing scope. - #[allow(unused)] pub(crate) fn expression_scope_id(&self, expression: &ast::Expr) -> FileScopeId { self.expression_scopes[&NodeKey::from_node(expression)] } @@ -116,7 +119,6 @@ impl SemanticIndex { } /// Returns the [`Scope`] with the given id. - #[allow(unused)] pub(crate) fn scope(&self, id: FileScopeId) -> &Scope { &self.scopes[id] } @@ -140,13 +142,11 @@ impl SemanticIndex { } /// Returns an iterator over the direct child scopes of `scope`. - #[allow(unused)] pub(crate) fn child_scopes(&self, scope: FileScopeId) -> ChildrenIter { ChildrenIter::new(self, scope) } /// Returns an iterator over all ancestors of `scope`, starting with `scope` itself. - #[allow(unused)] pub(crate) fn ancestor_scopes(&self, scope: FileScopeId) -> AncestorsIter { AncestorsIter::new(self, scope) } diff --git a/crates/red_knot_python_semantic/src/semantic_index/ast_ids.rs b/crates/red_knot_python_semantic/src/semantic_index/ast_ids.rs index 61e218456a..184916fc2e 100644 --- a/crates/red_knot_python_semantic/src/semantic_index/ast_ids.rs +++ b/crates/red_knot_python_semantic/src/semantic_index/ast_ids.rs @@ -65,7 +65,7 @@ impl std::fmt::Debug for AstIds { } } -fn ast_ids(db: &dyn Db, scope: ScopeId) -> &AstIds { +fn ast_ids<'db>(db: &'db dyn Db, scope: ScopeId) -> &'db AstIds { semantic_index(db, scope.file(db)).ast_ids(scope.file_scope_id(db)) } diff --git a/crates/red_knot_python_semantic/src/semantic_index/symbol.rs b/crates/red_knot_python_semantic/src/semantic_index/symbol.rs index d2498f19d2..62282a1a5f 100644 --- a/crates/red_knot_python_semantic/src/semantic_index/symbol.rs +++ b/crates/red_knot_python_semantic/src/semantic_index/symbol.rs @@ -1,7 +1,3 @@ -// Allow unused underscore violations generated by the salsa macro -// TODO(micha): Contribute fix upstream -#![allow(clippy::used_underscore_binding)] - use std::hash::{Hash, Hasher}; use std::ops::Range; @@ -78,7 +74,7 @@ bitflags! { /// ID that uniquely identifies a public symbol defined in a module's root scope. #[salsa::tracked] -pub struct PublicSymbolId { +pub struct PublicSymbolId<'db> { #[id] pub(crate) file: VfsFile, #[id] @@ -132,7 +128,7 @@ impl ScopedSymbolId { /// Returns a mapping from [`FileScopeId`] to globally unique [`ScopeId`]. #[salsa::tracked(return_ref)] -pub(crate) fn scopes_map(db: &dyn Db, file: VfsFile) -> ScopesMap { +pub(crate) fn scopes_map(db: &dyn Db, file: VfsFile) -> ScopesMap<'_> { let _ = tracing::trace_span!("scopes_map", file = ?file.debug(db.upcast())).enter(); let index = semantic_index(db, file); @@ -152,19 +148,19 @@ pub(crate) fn scopes_map(db: &dyn Db, file: VfsFile) -> ScopesMap { /// because they allow for more efficient storage of associated data /// (use of an [`IndexVec`] keyed by [`FileScopeId`] over an [`FxHashMap`] keyed by [`ScopeId`]). #[derive(Eq, PartialEq, Debug)] -pub(crate) struct ScopesMap { - scopes: IndexVec, +pub(crate) struct ScopesMap<'db> { + scopes: IndexVec>, } -impl ScopesMap { +impl<'db> ScopesMap<'db> { /// Gets the program-wide unique scope id for the given file specific `scope_id`. - fn get(&self, scope: FileScopeId) -> ScopeId { + fn get(&self, scope: FileScopeId) -> ScopeId<'db> { self.scopes[scope] } } #[salsa::tracked(return_ref)] -pub(crate) fn public_symbols_map(db: &dyn Db, file: VfsFile) -> PublicSymbolsMap { +pub(crate) fn public_symbols_map(db: &dyn Db, file: VfsFile) -> PublicSymbolsMap<'_> { let _ = tracing::trace_span!("public_symbols_map", file = ?file.debug(db.upcast())).enter(); let module_scope = root_scope(db, file); @@ -182,20 +178,20 @@ pub(crate) fn public_symbols_map(db: &dyn Db, file: VfsFile) -> PublicSymbolsMap /// Maps [`LocalSymbolId`] of a file's root scope to the corresponding [`PublicSymbolId`] (Salsa ingredients). #[derive(Eq, PartialEq, Debug)] -pub(crate) struct PublicSymbolsMap { - symbols: IndexVec, +pub(crate) struct PublicSymbolsMap<'db> { + symbols: IndexVec>, } -impl PublicSymbolsMap { +impl<'db> PublicSymbolsMap<'db> { /// Resolve the [`PublicSymbolId`] for the module-level `symbol_id`. - fn public(&self, symbol_id: ScopedSymbolId) -> PublicSymbolId { + fn public(&self, symbol_id: ScopedSymbolId) -> PublicSymbolId<'db> { self.symbols[symbol_id] } } /// A cross-module identifier of a scope that can be used as a salsa query parameter. #[salsa::tracked] -pub struct ScopeId { +pub struct ScopeId<'db> { #[allow(clippy::used_underscore_binding)] #[id] pub file: VfsFile, @@ -213,7 +209,7 @@ impl FileScopeId { FileScopeId::from_u32(0) } - pub fn to_scope_id(self, db: &dyn Db, file: VfsFile) -> ScopeId { + pub fn to_scope_id(self, db: &dyn Db, file: VfsFile) -> ScopeId<'_> { scopes_map(db, file).get(self) } } @@ -284,7 +280,6 @@ impl SymbolTable { &self.symbols[symbol_id.into()] } - #[allow(unused)] pub(crate) fn symbol_ids(&self) -> impl Iterator { self.symbols.indices() } diff --git a/crates/red_knot_python_semantic/src/types.rs b/crates/red_knot_python_semantic/src/types.rs index 991281e24b..97e870d6a2 100644 --- a/crates/red_knot_python_semantic/src/types.rs +++ b/crates/red_knot_python_semantic/src/types.rs @@ -27,7 +27,11 @@ mod infer; /// /// Prefer [`public_symbol_ty`] when resolving the type of symbol from another file. #[tracing::instrument(level = "debug", skip(db))] -pub(crate) fn expression_ty(db: &dyn Db, file: VfsFile, expression: &ast::Expr) -> Type { +pub(crate) fn expression_ty<'db>( + db: &'db dyn Db, + file: VfsFile, + expression: &ast::Expr, +) -> Type<'db> { let index = semantic_index(db, file); let file_scope = index.expression_scope_id(expression); let expression_id = expression.scope_ast_id(db, file, file_scope); @@ -61,7 +65,7 @@ pub(crate) fn expression_ty(db: &dyn Db, file: VfsFile, expression: &ast::Expr) /// /// This being a query ensures that the invalidation short-circuits if the type of this symbol didn't change. #[salsa::tracked] -pub(crate) fn public_symbol_ty(db: &dyn Db, symbol: PublicSymbolId) -> Type { +pub(crate) fn public_symbol_ty<'db>(db: &'db dyn Db, symbol: PublicSymbolId<'db>) -> Type<'db> { let _ = tracing::trace_span!("public_symbol_ty", symbol = ?symbol.debug(db)).enter(); let file = symbol.file(db); @@ -72,14 +76,18 @@ pub(crate) fn public_symbol_ty(db: &dyn Db, symbol: PublicSymbolId) -> Type { } /// Shorthand for `public_symbol_ty` that takes a symbol name instead of a [`PublicSymbolId`]. -pub fn public_symbol_ty_by_name(db: &dyn Db, file: VfsFile, name: &str) -> Option { +pub fn public_symbol_ty_by_name<'db>( + db: &'db dyn Db, + file: VfsFile, + name: &str, +) -> Option> { let symbol = public_symbol(db, file, name)?; Some(public_symbol_ty(db, symbol)) } /// Infers all types for `scope`. #[salsa::tracked(return_ref)] -pub(crate) fn infer_types(db: &dyn Db, scope: ScopeId) -> TypeInference { +pub(crate) fn infer_types<'db>(db: &'db dyn Db, scope: ScopeId<'db>) -> TypeInference<'db> { let _ = tracing::trace_span!("infer_types", scope = ?scope.debug(db)).enter(); let file = scope.file(db); @@ -120,7 +128,7 @@ pub(crate) fn infer_types(db: &dyn Db, scope: ScopeId) -> TypeInference { /// unique ID for a type #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum Type { +pub enum Type<'db> { /// the dynamic type: a statically-unknown set of values Any, /// the empty set of values @@ -133,20 +141,20 @@ pub enum Type { /// the None object (TODO remove this in favor of Instance(types.NoneType) None, /// a specific function object - Function(TypeId), + Function(TypeId<'db, ScopedFunctionTypeId>), /// a specific module object - Module(TypeId), + Module(TypeId<'db, ScopedModuleTypeId>), /// a specific class object - Class(TypeId), + Class(TypeId<'db, ScopedClassTypeId>), /// the set of Python objects with the given class in their __class__'s method resolution order - Instance(TypeId), - Union(TypeId), - Intersection(TypeId), + Instance(TypeId<'db, ScopedClassTypeId>), + Union(TypeId<'db, ScopedUnionTypeId>), + Intersection(TypeId<'db, ScopedIntersectionTypeId>), IntLiteral(i64), // TODO protocols, callable types, overloads, generics, type vars } -impl Type { +impl<'db> Type<'db> { pub const fn is_unbound(&self) -> bool { matches!(self, Type::Unbound) } @@ -155,7 +163,7 @@ impl Type { matches!(self, Type::Unknown) } - pub fn member(&self, context: &TypingContext, name: &Name) -> Option { + pub fn member(&self, context: &TypingContext<'db, '_>, name: &Name) -> Option> { match self { Type::Any => Some(Type::Any), Type::Never => todo!("attribute lookup on Never type"), @@ -191,18 +199,18 @@ impl Type { /// ID that uniquely identifies a type in a program. #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] -pub struct TypeId { +pub struct TypeId<'db, L> { /// The scope in which this type is defined or was created. - scope: ScopeId, + scope: ScopeId<'db>, /// The type's local ID in its scope. scoped: L, } -impl TypeId +impl<'db, Id> TypeId<'db, Id> where Id: Copy, { - pub fn scope(&self) -> ScopeId { + pub fn scope(&self) -> ScopeId<'db> { self.scope } @@ -211,7 +219,7 @@ where } /// Resolves the type ID to the actual type. - pub(crate) fn lookup<'a>(self, context: &'a TypingContext) -> &'a Id::Ty + pub(crate) fn lookup<'a>(self, context: &'a TypingContext<'db, 'a>) -> &'a Id::Ty<'db> where Id: ScopedTypeId, { @@ -223,13 +231,13 @@ where /// ID that uniquely identifies a type in a scope. pub(crate) trait ScopedTypeId { /// The type that this ID points to. - type Ty; + type Ty<'db>; /// Looks up the type in `index`. /// /// ## Panics /// May panic if this type is from another scope than `index`, or might just return an invalid type. - fn lookup_scoped(self, index: &TypeInference) -> &Self::Ty; + fn lookup_scoped<'a, 'db>(self, index: &'a TypeInference<'db>) -> &'a Self::Ty<'db>; } /// ID uniquely identifying a function type in a `scope`. @@ -237,28 +245,28 @@ pub(crate) trait ScopedTypeId { pub struct ScopedFunctionTypeId; impl ScopedTypeId for ScopedFunctionTypeId { - type Ty = FunctionType; + type Ty<'db> = FunctionType<'db>; - fn lookup_scoped(self, types: &TypeInference) -> &Self::Ty { + fn lookup_scoped<'a, 'db>(self, types: &'a TypeInference<'db>) -> &'a Self::Ty<'db> { types.function_ty(self) } } #[derive(Debug, Eq, PartialEq, Clone)] -pub struct FunctionType { +pub struct FunctionType<'a> { /// name of the function at definition name: Name, /// types of all decorators on this function - decorators: Vec, + decorators: Vec>, } -impl FunctionType { +impl<'a> FunctionType<'a> { fn name(&self) -> &str { self.name.as_str() } #[allow(unused)] - pub(crate) fn decorators(&self) -> &[Type] { + pub(crate) fn decorators(&self) -> &[Type<'a>] { self.decorators.as_slice() } } @@ -267,18 +275,18 @@ impl FunctionType { pub struct ScopedClassTypeId; impl ScopedTypeId for ScopedClassTypeId { - type Ty = ClassType; + type Ty<'db> = ClassType<'db>; - fn lookup_scoped(self, types: &TypeInference) -> &Self::Ty { + fn lookup_scoped<'a, 'db>(self, types: &'a TypeInference<'db>) -> &'a Self::Ty<'db> { types.class_ty(self) } } -impl TypeId { +impl<'db> TypeId<'db, ScopedClassTypeId> { /// Returns the class member of this class named `name`. /// /// The member resolves to a member of the class itself or any of its bases. - fn class_member(self, context: &TypingContext, name: &Name) -> Option { + fn class_member(self, context: &TypingContext<'db, '_>, name: &Name) -> Option> { if let Some(member) = self.own_class_member(context, name) { return Some(member); } @@ -294,7 +302,7 @@ impl TypeId { } /// Returns the inferred type of the class member named `name`. - fn own_class_member(self, context: &TypingContext, name: &Name) -> Option { + fn own_class_member(self, context: &TypingContext<'db, '_>, name: &Name) -> Option> { let class = self.lookup(context); let symbols = symbol_table(context.db, class.body_scope); @@ -306,23 +314,23 @@ impl TypeId { } #[derive(Debug, Eq, PartialEq, Clone)] -pub struct ClassType { +pub struct ClassType<'db> { /// Name of the class at definition name: Name, /// Types of all class bases - bases: Vec, + bases: Vec>, - body_scope: ScopeId, + body_scope: ScopeId<'db>, } -impl ClassType { +impl<'db> ClassType<'db> { fn name(&self) -> &str { self.name.as_str() } #[allow(unused)] - pub(super) fn bases(&self) -> &[Type] { + pub(super) fn bases(&self) -> &'db [Type] { self.bases.as_slice() } } @@ -331,26 +339,26 @@ impl ClassType { pub struct ScopedUnionTypeId; impl ScopedTypeId for ScopedUnionTypeId { - type Ty = UnionType; + type Ty<'db> = UnionType<'db>; - fn lookup_scoped(self, types: &TypeInference) -> &Self::Ty { + fn lookup_scoped<'a, 'db>(self, types: &'a TypeInference<'db>) -> &'a Self::Ty<'db> { types.union_ty(self) } } #[derive(Debug, Eq, PartialEq, Clone)] -pub struct UnionType { +pub struct UnionType<'db> { // the union type includes values in any of these types - elements: FxIndexSet, + elements: FxIndexSet>, } -struct UnionTypeBuilder<'a> { - elements: FxIndexSet, - context: &'a TypingContext<'a>, +struct UnionTypeBuilder<'db, 'a> { + elements: FxIndexSet>, + context: &'a TypingContext<'db, 'a>, } -impl<'a> UnionTypeBuilder<'a> { - fn new(context: &'a TypingContext<'a>) -> Self { +impl<'db, 'a> UnionTypeBuilder<'db, 'a> { + fn new(context: &'a TypingContext<'db, 'a>) -> Self { Self { context, elements: FxIndexSet::default(), @@ -358,7 +366,7 @@ impl<'a> UnionTypeBuilder<'a> { } /// Adds a type to this union. - fn add(mut self, ty: Type) -> Self { + fn add(mut self, ty: Type<'db>) -> Self { match ty { Type::Union(union_id) => { let union = union_id.lookup(self.context); @@ -372,7 +380,7 @@ impl<'a> UnionTypeBuilder<'a> { self } - fn build(self) -> UnionType { + fn build(self) -> UnionType<'db> { UnionType { elements: self.elements, } @@ -383,9 +391,9 @@ impl<'a> UnionTypeBuilder<'a> { pub struct ScopedIntersectionTypeId; impl ScopedTypeId for ScopedIntersectionTypeId { - type Ty = IntersectionType; + type Ty<'db> = IntersectionType<'db>; - fn lookup_scoped(self, types: &TypeInference) -> &Self::Ty { + fn lookup_scoped<'a, 'db>(self, types: &'a TypeInference<'db>) -> &'a Self::Ty<'db> { types.intersection_ty(self) } } @@ -397,26 +405,26 @@ impl ScopedTypeId for ScopedIntersectionTypeId { // have to represent it as a single-element intersection if it did) in exchange for better // efficiency in the within-intersection case. #[derive(Debug, PartialEq, Eq, Clone)] -pub struct IntersectionType { +pub struct IntersectionType<'db> { // the intersection type includes only values in all of these types - positive: FxIndexSet, + positive: FxIndexSet>, // the intersection type does not include any value in any of these types - negative: FxIndexSet, + negative: FxIndexSet>, } #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub struct ScopedModuleTypeId; impl ScopedTypeId for ScopedModuleTypeId { - type Ty = ModuleType; + type Ty<'db> = ModuleType; - fn lookup_scoped(self, types: &TypeInference) -> &Self::Ty { + fn lookup_scoped<'a, 'db>(self, types: &'a TypeInference<'db>) -> &'a Self::Ty<'db> { types.module_ty() } } -impl TypeId { - fn member(self, context: &TypingContext, name: &Name) -> Option { +impl<'db> TypeId<'db, ScopedModuleTypeId> { + fn member(self, context: &TypingContext<'db, '_>, name: &Name) -> Option> { context.public_symbol_ty(self.scope.file(context.db), name) } } @@ -431,24 +439,28 @@ pub struct ModuleType { /// This abstraction is necessary to support a uniform API that can be used /// while in the process of building the type inference structure for a scope /// but also when all types should be resolved by querying the db. -pub struct TypingContext<'a> { - db: &'a dyn Db, +pub struct TypingContext<'db, 'inference> { + db: &'db dyn Db, /// The Local type inference scope that is in the process of being built. /// /// Bypass the `db` when resolving the types for this scope. - local: Option<(ScopeId, &'a TypeInference)>, + local: Option<(ScopeId<'db>, &'inference TypeInference<'db>)>, } -impl<'a> TypingContext<'a> { +impl<'db, 'inference> TypingContext<'db, 'inference> { /// Creates a context that resolves all types by querying the db. #[allow(unused)] - pub(super) fn global(db: &'a dyn Db) -> Self { + pub(super) fn global(db: &'db dyn Db) -> Self { Self { db, local: None } } /// Creates a context that by-passes the `db` when resolving types from `scope_id` and instead uses `types`. - fn scoped(db: &'a dyn Db, scope_id: ScopeId, types: &'a TypeInference) -> Self { + fn scoped( + db: &'db dyn Db, + scope_id: ScopeId<'db>, + types: &'inference TypeInference<'db>, + ) -> Self { Self { db, local: Some((scope_id, types)), @@ -456,7 +468,7 @@ impl<'a> TypingContext<'a> { } /// Returns the [`TypeInference`] results (not guaranteed to be complete) for `scope_id`. - fn types(&self, scope_id: ScopeId) -> &'a TypeInference { + fn types(&self, scope_id: ScopeId<'db>) -> &'inference TypeInference<'db> { if let Some((scope, local_types)) = self.local { if scope == scope_id { return local_types; @@ -466,7 +478,7 @@ impl<'a> TypingContext<'a> { infer_types(self.db, scope_id) } - fn module_ty(&self, file: VfsFile) -> Type { + fn module_ty(&self, file: VfsFile) -> Type<'db> { let scope = root_scope(self.db, file); Type::Module(TypeId { @@ -479,7 +491,7 @@ impl<'a> TypingContext<'a> { /// /// This function calls [`public_symbol_ty`] if the local scope isn't the module scope of `file`. /// It otherwise tries to resolve the symbol type locally. - fn public_symbol_ty(&self, file: VfsFile, name: &Name) -> Option { + fn public_symbol_ty(&self, file: VfsFile, name: &Name) -> Option> { let symbol = public_symbol(self.db, file, name)?; if let Some((scope, local_types)) = self.local { @@ -581,7 +593,7 @@ mod tests { assert_will_run_function_query::( &db, |ty| &ty.function, - a_root_scope, + &a_root_scope, &events, ); @@ -629,7 +641,7 @@ mod tests { assert_will_not_run_function_query::( &db, |ty| &ty.function, - a_root_scope, + &a_root_scope, &events, ); @@ -676,7 +688,7 @@ mod tests { assert_will_not_run_function_query::( &db, |ty| &ty.function, - a_root_scope, + &a_root_scope, &events, ); Ok(()) diff --git a/crates/red_knot_python_semantic/src/types/display.rs b/crates/red_knot_python_semantic/src/types/display.rs index 3c8d3908c9..d038512cd8 100644 --- a/crates/red_knot_python_semantic/src/types/display.rs +++ b/crates/red_knot_python_semantic/src/types/display.rs @@ -4,7 +4,7 @@ use std::fmt::{Display, Formatter}; use crate::types::{IntersectionType, Type, TypingContext, UnionType}; -impl Type { +impl Type<'_> { pub fn display<'a>(&'a self, context: &'a TypingContext) -> DisplayType<'a> { DisplayType { ty: self, context } } @@ -12,8 +12,8 @@ impl Type { #[derive(Copy, Clone)] pub struct DisplayType<'a> { - ty: &'a Type, - context: &'a TypingContext<'a>, + ty: &'a Type<'a>, + context: &'a TypingContext<'a, 'a>, } impl Display for DisplayType<'_> { @@ -71,15 +71,15 @@ impl std::fmt::Debug for DisplayType<'_> { } } -impl UnionType { - fn display<'a>(&'a self, context: &'a TypingContext<'a>) -> DisplayUnionType<'a> { +impl UnionType<'_> { + fn display<'a>(&'a self, context: &'a TypingContext<'a, 'a>) -> DisplayUnionType<'a> { DisplayUnionType { context, ty: self } } } struct DisplayUnionType<'a> { - ty: &'a UnionType, - context: &'a TypingContext<'a>, + ty: &'a UnionType<'a>, + context: &'a TypingContext<'a, 'a>, } impl Display for DisplayUnionType<'_> { @@ -134,15 +134,15 @@ impl std::fmt::Debug for DisplayUnionType<'_> { } } -impl IntersectionType { - fn display<'a>(&'a self, context: &'a TypingContext<'a>) -> DisplayIntersectionType<'a> { +impl IntersectionType<'_> { + fn display<'a>(&'a self, context: &'a TypingContext<'a, 'a>) -> DisplayIntersectionType<'a> { DisplayIntersectionType { ty: self, context } } } struct DisplayIntersectionType<'a> { - ty: &'a IntersectionType, - context: &'a TypingContext<'a>, + ty: &'a IntersectionType<'a>, + context: &'a TypingContext<'a, 'a>, } impl Display for DisplayIntersectionType<'_> { diff --git a/crates/red_knot_python_semantic/src/types/infer.rs b/crates/red_knot_python_semantic/src/types/infer.rs index 7f7715693b..d490013c4d 100644 --- a/crates/red_knot_python_semantic/src/types/infer.rs +++ b/crates/red_knot_python_semantic/src/types/infer.rs @@ -23,33 +23,33 @@ use crate::Db; /// The inferred types for a single scope. #[derive(Debug, Eq, PartialEq, Default, Clone)] -pub(crate) struct TypeInference { +pub(crate) struct TypeInference<'db> { /// The type of the module if the scope is a module scope. module_type: Option, /// The types of the defined classes in this scope. - class_types: IndexVec, + class_types: IndexVec>, /// The types of the defined functions in this scope. - function_types: IndexVec, + function_types: IndexVec>, - union_types: IndexVec, - intersection_types: IndexVec, + union_types: IndexVec>, + intersection_types: IndexVec>, /// The types of every expression in this scope. - expression_tys: IndexVec, + expression_tys: IndexVec>, /// The public types of every symbol in this scope. - symbol_tys: IndexVec, + symbol_tys: IndexVec>, } -impl TypeInference { +impl<'db> TypeInference<'db> { #[allow(unused)] - pub(super) fn expression_ty(&self, expression: ScopeExpressionId) -> Type { + pub(super) fn expression_ty(&self, expression: ScopeExpressionId) -> Type<'db> { self.expression_tys[expression] } - pub(super) fn symbol_ty(&self, symbol: ScopedSymbolId) -> Type { + pub(super) fn symbol_ty(&self, symbol: ScopedSymbolId) -> Type<'db> { self.symbol_tys[symbol] } @@ -57,19 +57,19 @@ impl TypeInference { self.module_type.as_ref().unwrap() } - pub(super) fn class_ty(&self, id: ScopedClassTypeId) -> &ClassType { + pub(super) fn class_ty(&self, id: ScopedClassTypeId) -> &ClassType<'db> { &self.class_types[id] } - pub(super) fn function_ty(&self, id: ScopedFunctionTypeId) -> &FunctionType { + pub(super) fn function_ty(&self, id: ScopedFunctionTypeId) -> &FunctionType<'db> { &self.function_types[id] } - pub(super) fn union_ty(&self, id: ScopedUnionTypeId) -> &UnionType { + pub(super) fn union_ty(&self, id: ScopedUnionTypeId) -> &UnionType<'db> { &self.union_types[id] } - pub(super) fn intersection_ty(&self, id: ScopedIntersectionTypeId) -> &IntersectionType { + pub(super) fn intersection_ty(&self, id: ScopedIntersectionTypeId) -> &IntersectionType<'db> { &self.intersection_types[id] } @@ -90,20 +90,20 @@ pub(super) struct TypeInferenceBuilder<'a> { // Cached lookups index: &'a SemanticIndex, - scope: ScopeId, + scope: ScopeId<'a>, file_scope_id: FileScopeId, file_id: VfsFile, symbol_table: Arc, /// The type inference results - types: TypeInference, - definition_tys: FxHashMap, + types: TypeInference<'a>, + definition_tys: FxHashMap>, children_scopes: ChildrenIter<'a>, } -impl<'a> TypeInferenceBuilder<'a> { +impl<'db> TypeInferenceBuilder<'db> { /// Creates a new builder for inferring the types of `scope`. - pub(super) fn new(db: &'a dyn Db, scope: ScopeId, index: &'a SemanticIndex) -> Self { + pub(super) fn new(db: &'db dyn Db, scope: ScopeId<'db>, index: &'db SemanticIndex) -> Self { let file_scope_id = scope.file_scope_id(db); let file = scope.file(db); let children_scopes = index.child_scopes(file_scope_id); @@ -410,7 +410,7 @@ impl<'a> TypeInferenceBuilder<'a> { } } - fn infer_decorator(&mut self, decorator: &ast::Decorator) -> Type { + fn infer_decorator(&mut self, decorator: &ast::Decorator) -> Type<'db> { let ast::Decorator { range: _, expression, @@ -419,7 +419,7 @@ impl<'a> TypeInferenceBuilder<'a> { self.infer_expression(expression) } - fn infer_arguments(&mut self, arguments: &ast::Arguments) -> Vec { + fn infer_arguments(&mut self, arguments: &ast::Arguments) -> Vec> { let mut types = Vec::with_capacity( arguments .args @@ -440,7 +440,7 @@ impl<'a> TypeInferenceBuilder<'a> { types } - fn infer_expression(&mut self, expression: &ast::Expr) -> Type { + fn infer_expression(&mut self, expression: &ast::Expr) -> Type<'db> { let ty = match expression { ast::Expr::NoneLiteral(ast::ExprNoneLiteral { range: _ }) => Type::None, ast::Expr::NumberLiteral(literal) => self.infer_number_literal_expression(literal), @@ -459,7 +459,7 @@ impl<'a> TypeInferenceBuilder<'a> { } #[allow(clippy::unused_self)] - fn infer_number_literal_expression(&mut self, literal: &ast::ExprNumberLiteral) -> Type { + fn infer_number_literal_expression(&mut self, literal: &ast::ExprNumberLiteral) -> Type<'db> { let ast::ExprNumberLiteral { range: _, value } = literal; match value { @@ -472,7 +472,7 @@ impl<'a> TypeInferenceBuilder<'a> { } } - fn infer_named_expression(&mut self, named: &ast::ExprNamed) -> Type { + fn infer_named_expression(&mut self, named: &ast::ExprNamed) -> Type<'db> { let ast::ExprNamed { range: _, target, @@ -490,7 +490,7 @@ impl<'a> TypeInferenceBuilder<'a> { value_ty } - fn infer_if_expression(&mut self, if_expression: &ast::ExprIf) -> Type { + fn infer_if_expression(&mut self, if_expression: &ast::ExprIf) -> Type<'db> { let ast::ExprIf { range: _, test, @@ -512,7 +512,7 @@ impl<'a> TypeInferenceBuilder<'a> { self.union_ty(union) } - fn infer_name_expression(&mut self, name: &ast::ExprName) -> Type { + fn infer_name_expression(&mut self, name: &ast::ExprName) -> Type<'db> { let ast::ExprName { range: _, id, ctx } = name; match ctx { @@ -546,7 +546,7 @@ impl<'a> TypeInferenceBuilder<'a> { } } - fn infer_attribute_expression(&mut self, attribute: &ast::ExprAttribute) -> Type { + fn infer_attribute_expression(&mut self, attribute: &ast::ExprAttribute) -> Type<'db> { let ast::ExprAttribute { value, attr, @@ -566,7 +566,7 @@ impl<'a> TypeInferenceBuilder<'a> { } } - fn infer_binary_expression(&mut self, binary: &ast::ExprBinOp) -> Type { + fn infer_binary_expression(&mut self, binary: &ast::ExprBinOp) -> Type<'db> { let ast::ExprBinOp { left, op, @@ -623,7 +623,7 @@ impl<'a> TypeInferenceBuilder<'a> { todo!("Infer type parameters") } - pub(super) fn finish(mut self) -> TypeInference { + pub(super) fn finish(mut self) -> TypeInference<'db> { let symbol_tys: IndexVec<_, _> = self .index .symbol_table(self.file_scope_id) @@ -636,32 +636,32 @@ impl<'a> TypeInferenceBuilder<'a> { self.types } - fn union_ty(&mut self, ty: UnionType) -> Type { + fn union_ty(&mut self, ty: UnionType<'db>) -> Type<'db> { Type::Union(TypeId { scope: self.scope, scoped: self.types.union_types.push(ty), }) } - fn function_ty(&mut self, ty: FunctionType) -> Type { + fn function_ty(&mut self, ty: FunctionType<'db>) -> Type<'db> { Type::Function(TypeId { scope: self.scope, scoped: self.types.function_types.push(ty), }) } - fn class_ty(&mut self, ty: ClassType) -> Type { + fn class_ty(&mut self, ty: ClassType<'db>) -> Type<'db> { Type::Class(TypeId { scope: self.scope, scoped: self.types.class_types.push(ty), }) } - fn typing_context(&self) -> TypingContext { + fn typing_context(&self) -> TypingContext<'db, '_> { TypingContext::scoped(self.db, self.scope, &self.types) } - fn local_definition_ty(&mut self, symbol: ScopedSymbolId) -> Type { + fn local_definition_ty(&mut self, symbol: ScopedSymbolId) -> Type<'db> { let symbol = self.symbol_table.symbol(symbol); let mut definitions = symbol .definitions() diff --git a/crates/ruff_db/src/vfs.rs b/crates/ruff_db/src/vfs.rs index 261a14a71e..f9ca06eb6f 100644 --- a/crates/ruff_db/src/vfs.rs +++ b/crates/ruff_db/src/vfs.rs @@ -251,7 +251,6 @@ impl VfsFile { /// an empty string, which is the closest to the content that the file contains now. Returning /// an empty string shouldn't be a problem because the query will be re-executed as soon as the /// changes are applied to the database. - #[allow(unused)] pub(crate) fn read(&self, db: &dyn Db) -> String { let path = self.path(db);