require databases and ingredients to be static

This commit is contained in:
Niko Matsakis 2024-07-06 08:15:27 -04:00
parent a1bf3a613f
commit e1920bdda6
27 changed files with 65 additions and 73 deletions

View file

@ -81,7 +81,7 @@ pub(crate) fn should_backdate_value_fn(should_backdate: bool) -> syn::ImplItemFn
pub(crate) fn panic_cycle_recovery_fn() -> syn::ImplItemFn {
parse_quote! {
fn recover_from_cycle<'db>(
_db: &'db salsa::function::DynDb<'db, Self>,
_db: &'db salsa::function::DynDb<Self>,
_cycle: &salsa::Cycle,
_key: salsa::Id,
) -> Self::Value<'db> {

View file

@ -193,15 +193,12 @@ fn per_jar_impls(args: &Args, input: &syn::ItemStruct, storage: &syn::Ident) ->
vec![
parse_quote! {
impl salsa::storage::DbWithJar<#jar_path> for #db {
fn as_jar_db<'db>(&'db self) -> &'db <#jar_path as salsa::jar::Jar<'db>>::DynDb
where
'db: 'db,
fn as_jar_db<'db>(&'db self) -> &'db <#jar_path as salsa::jar::Jar>::DynDb
{
self as &'db <#jar_path as salsa::jar::Jar<'db>>::DynDb
self as &'db <#jar_path as salsa::jar::Jar>::DynDb
}
}
},
parse_quote! {
impl salsa::storage::HasJar<#jar_path> for #db {
fn jar(&self) -> (&#jar_path, &salsa::Runtime) {
@ -215,7 +212,6 @@ fn per_jar_impls(args: &Args, input: &syn::ItemStruct, storage: &syn::Ident) ->
}
}
},
parse_quote! {
impl salsa::storage::JarFromJars<#jar_path> for #db {
fn jar_from_jars<'db>(jars: &Self::Jars) -> &#jar_path {
@ -226,7 +222,7 @@ fn per_jar_impls(args: &Args, input: &syn::ItemStruct, storage: &syn::Ident) ->
&mut jars.#jar_index
}
}
}
},
]
})
.collect()

View file

@ -13,17 +13,12 @@ pub(crate) fn debug_with_db(input: syn::DeriveInput) -> syn::Result<proc_macro2:
));
}
let db_lt = match input.generics.lifetimes().next() {
Some(lt) => lt.lifetime.clone(),
None => syn::Lifetime::new("'_", Span::call_site()),
};
// Generate the type of database we expect. This hardcodes the convention of using `jar::Jar`.
// That's not great and should be fixed but we'd have to add a custom attribute and I am too lazy.
#[allow(non_snake_case)]
let DB: syn::Type = parse_quote! {
<crate::Jar as salsa::jar::Jar< #db_lt >>::DynDb
<crate::Jar as salsa::jar::Jar>::DynDb
};
let structure: synstructure::Structure = synstructure::Structure::new(&input);

View file

@ -113,8 +113,8 @@ pub(crate) fn jar_impl(
.collect();
// ANCHOR: init_jar
quote! {
unsafe impl<'salsa_db> salsa::jar::Jar<'salsa_db> for #jar_struct {
type DynDb = dyn #jar_trait + 'salsa_db;
unsafe impl salsa::jar::Jar for #jar_struct {
type DynDb = dyn #jar_trait;
unsafe fn init_jar<DB>(place: *mut Self, routes: &mut salsa::routes::Routes<DB>)
where

View file

@ -282,9 +282,8 @@ impl<A: AllowedOptions> SalsaStruct<A> {
pub(crate) fn db_dyn_ty(&self) -> syn::Type {
let jar_ty = self.jar_ty();
let lt_db = self.maybe_elided_db_lifetime();
parse_quote! {
<#jar_ty as salsa::jar::Jar< #lt_db >>::DynDb
<#jar_ty as salsa::jar::Jar>::DynDb
}
}

View file

@ -453,7 +453,7 @@ fn fn_configuration(args: &FnArgs, item_fn: &syn::ItemFn) -> Configuration {
let cycle_strategy = CycleRecoveryStrategy::Fallback;
let cycle_fullback = parse_quote! {
fn recover_from_cycle<'db>(__db: &'db salsa::function::DynDb<'db, Self>, __cycle: &salsa::Cycle, __id: salsa::Id) -> Self::Value<'db> {
fn recover_from_cycle<'db>(__db: &'db salsa::function::DynDb<Self>, __cycle: &salsa::Cycle, __id: salsa::Id) -> Self::Value<'db> {
let (__jar, __runtime) = <_ as salsa::storage::HasJar<#jar_ty>>::jar(__db);
let __ingredients =
<_ as salsa::storage::HasIngredientsFor<#fn_ty>>::ingredient(__jar);
@ -483,7 +483,7 @@ fn fn_configuration(args: &FnArgs, item_fn: &syn::ItemFn) -> Configuration {
// Create the `execute` function, which (a) maps from the interned id to the actual
// keys and then (b) invokes the function itself (which we embed within).
let execute_fn = parse_quote! {
fn execute<'db>(__db: &'db salsa::function::DynDb<'db, Self>, __id: salsa::Id) -> Self::Value<'db> {
fn execute<'db>(__db: &'db salsa::function::DynDb<Self>, __id: salsa::Id) -> Self::Value<'db> {
#inner_fn
let (__jar, __runtime) = <_ as salsa::storage::HasJar<#jar_ty>>::jar(__db);
@ -858,8 +858,7 @@ fn accumulated_fn(
-> Vec<<__A as salsa::accumulator::Accumulator>::Data>
};
let (db_lifetime, _) = db_lifetime_and_ty(&mut accumulated_fn.sig)?;
let predicate: syn::WherePredicate = parse_quote!(<#jar_ty as salsa::jar::Jar<#db_lifetime>>::DynDb: salsa::storage::HasJar<<__A as salsa::accumulator::Accumulator>::Jar>);
let predicate: syn::WherePredicate = parse_quote!(<#jar_ty as salsa::jar::Jar>::DynDb: salsa::storage::HasJar<<__A as salsa::accumulator::Accumulator>::Jar>);
if let Some(where_clause) = &mut accumulated_fn.sig.generics.where_clause {
where_clause.predicates.push(predicate);

View file

@ -101,7 +101,7 @@ impl<Data: Clone> AccumulatorIngredient<Data> {
impl<DB: ?Sized, Data> Ingredient<DB> for AccumulatorIngredient<Data>
where
DB: crate::Database,
Data: Clone,
Data: Clone + 'static,
{
fn ingredient_index(&self) -> IngredientIndex {
self.index

View file

@ -76,13 +76,13 @@ pub struct FunctionIngredient<C: Configuration> {
debug_name: &'static str,
}
pub trait Configuration {
type Jar: for<'db> Jar<'db>;
pub trait Configuration: 'static {
type Jar: Jar;
/// The "salsa struct type" that this function is associated with.
/// This can be just `salsa::Id` for functions that intern their arguments
/// and are not clearly associated with any one salsa struct.
type SalsaStruct<'db>: SalsaStructInDb<DynDb<'db, Self>>;
type SalsaStruct<'db>: SalsaStructInDb<DynDb<Self>>;
/// The input to the function
type Input<'db>;
@ -122,7 +122,7 @@ pub fn should_backdate_value<V: Eq>(old_value: &V, new_value: &V) -> bool {
old_value == new_value
}
pub type DynDb<'bound, C> = <<C as Configuration>::Jar as Jar<'bound>>::DynDb;
pub type DynDb<C> = <<C as Configuration>::Jar as Jar>::DynDb;
/// This type is used to make configuration types for the functions in entities;
/// e.g. you can do `Config<X, 0>` and `Config<X, 1>`.
@ -172,7 +172,7 @@ where
fn insert_memo<'db>(
&'db self,
db: &'db DynDb<'db, C>,
db: &'db DynDb<C>,
key: Id,
memo: memo::Memo<C::Value<'db>>,
) -> Option<&C::Value<'db>> {
@ -194,7 +194,7 @@ where
/// Register this function as a dependent fn of the given salsa struct.
/// When instances of that salsa struct are deleted, we'll get a callback
/// so we can remove any data keyed by them.
fn register<'db>(&self, db: &'db DynDb<'db, C>) {
fn register<'db>(&self, db: &'db DynDb<C>) {
if !self.registered.fetch_or(true) {
<C::SalsaStruct<'db> as SalsaStructInDb<_>>::register_dependent_fn(db, self.index)
}

View file

@ -14,9 +14,9 @@ where
{
/// Returns all the values accumulated into `accumulator` by this query and its
/// transitive inputs.
pub fn accumulated<'db, A>(&'db self, db: &'db DynDb<'db, C>, key: Id) -> Vec<A::Data>
pub fn accumulated<'db, A>(&'db self, db: &'db DynDb<C>, key: Id) -> Vec<A::Data>
where
DynDb<'db, C>: HasJar<A::Jar>,
DynDb<C>: HasJar<A::Jar>,
A: Accumulator,
{
// To start, ensure that the value is up to date:

View file

@ -13,7 +13,7 @@ where
/// for each output that was generated before but is not generated now.
pub(super) fn diff_outputs(
&self,
db: &DynDb<'_, C>,
db: &DynDb<C>,
key: DatabaseKeyIndex,
old_memo: &Memo<C::Value<'_>>,
revisions: &QueryRevisions,
@ -37,7 +37,7 @@ where
}
}
fn report_stale_output(db: &DynDb<'_, C>, key: DatabaseKeyIndex, output: DependencyIndex) {
fn report_stale_output(db: &DynDb<C>, key: DatabaseKeyIndex, output: DependencyIndex) {
let runtime_id = db.runtime().id();
db.salsa_event(Event {
runtime_id,

View file

@ -24,7 +24,7 @@ where
/// * `opt_old_memo`, the older memo, if any existed. Used for backdated.
pub(super) fn execute<'db>(
&'db self,
db: &'db DynDb<'db, C>,
db: &'db DynDb<C>,
active_query: ActiveQueryGuard<'_>,
opt_old_memo: Option<Arc<Memo<C::Value<'_>>>>,
) -> StampedValue<&C::Value<'db>> {

View file

@ -8,7 +8,7 @@ impl<C> FunctionIngredient<C>
where
C: Configuration,
{
pub fn fetch<'db>(&'db self, db: &'db DynDb<'db, C>, key: Id) -> &C::Value<'db> {
pub fn fetch<'db>(&'db self, db: &'db DynDb<C>, key: Id) -> &C::Value<'db> {
let runtime = db.runtime();
runtime.unwind_if_revision_cancelled(db);
@ -35,7 +35,7 @@ where
#[inline]
fn compute_value<'db>(
&'db self,
db: &'db DynDb<'db, C>,
db: &'db DynDb<C>,
key: Id,
) -> StampedValue<&'db C::Value<'db>> {
loop {
@ -48,7 +48,7 @@ where
#[inline]
fn fetch_hot<'db>(
&'db self,
db: &'db DynDb<'db, C>,
db: &'db DynDb<C>,
key: Id,
) -> Option<StampedValue<&'db C::Value<'db>>> {
let memo_guard = self.memo_map.get(key);
@ -69,7 +69,7 @@ where
fn fetch_cold<'db>(
&'db self,
db: &'db DynDb<'db, C>,
db: &'db DynDb<C>,
key: Id,
) -> Option<StampedValue<&'db C::Value<'db>>> {
let runtime = db.runtime();

View file

@ -20,7 +20,7 @@ where
{
pub(super) fn maybe_changed_after<'db>(
&'db self,
db: &'db DynDb<'db, C>,
db: &'db DynDb<C>,
key: Id,
revision: Revision,
) -> bool {
@ -57,7 +57,7 @@ where
fn maybe_changed_after_cold<'db>(
&'db self,
db: &'db DynDb<'db, C>,
db: &'db DynDb<C>,
key_index: Id,
revision: Revision,
) -> Option<bool> {

View file

@ -19,12 +19,12 @@ where
/// It only works if the key is a tracked struct created in the current query.
fn specify<'db>(
&'db self,
db: &'db DynDb<'db, C>,
db: &'db DynDb<C>,
key: Id,
value: C::Value<'db>,
origin: impl Fn(DatabaseKeyIndex) -> QueryOrigin,
) where
C::Input<'db>: TrackedStructInDb<DynDb<'db, C>>,
C::Input<'db>: TrackedStructInDb<DynDb<C>>,
{
let runtime = db.runtime();
@ -94,9 +94,9 @@ where
/// Specify the value for `key` *and* record that we did so.
/// Used for explicit calls to `specify`, but not needed for pre-declared tracked struct fields.
pub fn specify_and_record<'db>(&'db self, db: &'db DynDb<'db, C>, key: Id, value: C::Value<'db>)
pub fn specify_and_record<'db>(&'db self, db: &'db DynDb<C>, key: Id, value: C::Value<'db>)
where
C::Input<'db>: TrackedStructInDb<DynDb<'db, C>>,
C::Input<'db>: TrackedStructInDb<DynDb<C>>,
{
self.specify(db, key, value, |database_key_index| {
QueryOrigin::Assigned(database_key_index)
@ -113,7 +113,7 @@ where
/// it would have specified `key` again.
pub(super) fn validate_specified_value(
&self,
db: &DynDb<'_, C>,
db: &DynDb<C>,
executor: DatabaseKeyIndex,
key: Id,
) {

View file

@ -1,4 +1,4 @@
use std::fmt;
use std::{any::Any, fmt};
use crate::{
cycle::CycleRecoveryStrategy, key::DependencyIndex, runtime::local_state::QueryOrigin,
@ -16,7 +16,7 @@ use super::Revision;
/// The exact ingredients are determined by
/// [`IngredientsFor`](`crate::storage::IngredientsFor`) implementations generated by the
/// macro.
pub trait Ingredient<DB: ?Sized> {
pub trait Ingredient<DB: ?Sized>: Any {
/// Returns the [`IngredientIndex`] of this ingredient.
fn ingredient_index(&self) -> IngredientIndex;

View file

@ -12,8 +12,8 @@ use crate::{
IngredientIndex, Revision,
};
pub trait InputId: FromId {}
impl<T: FromId> InputId for T {}
pub trait InputId: FromId + 'static {}
impl<T: FromId + 'static> InputId for T {}
pub struct InputIngredient<Id>
where

View file

@ -28,7 +28,8 @@ pub struct InputFieldIngredient<K, F> {
impl<K, F> InputFieldIngredient<K, F>
where
K: Eq + Hash + AsId,
K: Eq + Hash + AsId + 'static,
F: 'static,
{
pub fn new(index: IngredientIndex, debug_name: &'static str) -> Self {
Self {
@ -108,7 +109,8 @@ where
impl<DB: ?Sized, K, F> Ingredient<DB> for InputFieldIngredient<K, F>
where
K: FromId,
K: FromId + 'static,
F: 'static,
{
fn ingredient_index(&self) -> IngredientIndex {
self.index

View file

@ -18,7 +18,7 @@ use super::ingredient::Ingredient;
use super::routes::IngredientIndex;
use super::Revision;
pub trait Configuration: Sized {
pub trait Configuration: Sized + 'static {
type Data<'db>: InternedData;
type Struct<'db>: Copy;

View file

@ -10,8 +10,8 @@ use super::routes::Routes;
/// # Safety
///
/// `init_jar` must fully initialize the jar
pub unsafe trait Jar<'db>: Sized {
type DynDb: ?Sized + HasJar<Self> + Database + 'db;
pub unsafe trait Jar: Sized {
type DynDb: ?Sized + HasJar<Self> + Database;
/// Initializes the jar at `place`
///

View file

@ -13,7 +13,8 @@ pub struct Setter<'setter, K, F> {
impl<'setter, K, F> Setter<'setter, K, F>
where
K: Eq + Hash + AsId,
K: Eq + Hash + AsId + 'static,
F: 'static,
{
pub fn new(
runtime: &'setter mut Runtime,

View file

@ -206,9 +206,9 @@ pub trait HasJars: HasJarsDyn + Sized {
}
pub trait DbWithJar<J>: HasJar<J> + Database {
fn as_jar_db<'db>(&'db self) -> &<J as Jar<'db>>::DynDb
fn as_jar_db<'db>(&'db self) -> &'db <J as Jar>::DynDb
where
J: Jar<'db>;
J: Jar;
}
pub trait JarFromJars<J>: HasJars {
@ -225,7 +225,7 @@ pub trait HasJar<J> {
// ANCHOR: HasJarsDyn
/// Dyn friendly subset of HasJars
pub trait HasJarsDyn {
pub trait HasJarsDyn: 'static {
fn runtime(&self) -> &Runtime;
fn runtime_mut(&mut self) -> &mut Runtime;

View file

@ -25,7 +25,7 @@ mod tracked_field;
/// Trait that defines the key properties of a tracked struct.
/// Implemented by the `#[salsa::tracked]` macro when applied
/// to a struct.
pub trait Configuration: Sized {
pub trait Configuration: Sized + 'static {
/// A (possibly empty) tuple of the fields for this struct.
type Fields<'db>;

View file

@ -6,7 +6,7 @@ error[E0308]: mismatched types
| |
| arguments to this method are incorrect
|
= note: expected mutable reference `&mut dyn Db`
= note: expected mutable reference `&mut (dyn Db + 'static)`
found type `{integer}`
note: method defined here
--> tests/compile-fail/span-input-setter.rs:18:5

View file

@ -6,7 +6,7 @@ error[E0308]: mismatched types
| |
| arguments to this method are incorrect
|
= note: expected reference `&dyn Db`
= note: expected reference `&(dyn Db + 'static)`
found type `{integer}`
note: method defined here
--> tests/compile-fail/span-tracked-getter.rs:18:5

View file

@ -1,16 +1,16 @@
error[E0277]: the trait bound `MyInput: TrackedStructInDb<dyn Db>` is not satisfied
error[E0277]: the trait bound `MyInput: TrackedStructInDb<(dyn Db + 'static)>` is not satisfied
--> tests/compile-fail/specify-does-not-work-if-the-key-is-a-salsa-input.rs:20:1
|
20 | #[salsa::tracked(jar = Jar, specify)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TrackedStructInDb<dyn Db>` is not implemented for `MyInput`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TrackedStructInDb<(dyn Db + 'static)>` is not implemented for `MyInput`
|
= help: the trait `TrackedStructInDb<DB>` is implemented for `MyTracked<'db>`
note: required by a bound in `function::specify::<impl FunctionIngredient<C>>::specify_and_record`
--> src/function/specify.rs
|
| pub fn specify_and_record<'db>(&'db self, db: &'db DynDb<'db, C>, key: Id, value: C::Value<'db>)
| pub fn specify_and_record<'db>(&'db self, db: &'db DynDb<C>, key: Id, value: C::Value<'db>)
| ------------------ required by a bound in this associated function
| where
| C::Input<'db>: TrackedStructInDb<DynDb<'db, C>>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `function::specify::<impl FunctionIngredient<C>>::specify_and_record`
| C::Input<'db>: TrackedStructInDb<DynDb<C>>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `function::specify::<impl FunctionIngredient<C>>::specify_and_record`
= note: this error originates in the attribute macro `salsa::tracked` (in Nightly builds, run with -Z macro-backtrace for more info)

View file

@ -1,16 +1,16 @@
error[E0277]: the trait bound `MyInterned<'_>: TrackedStructInDb<dyn Db>` is not satisfied
error[E0277]: the trait bound `MyInterned<'_>: TrackedStructInDb<(dyn Db + 'static)>` is not satisfied
--> tests/compile-fail/specify-does-not-work-if-the-key-is-a-salsa-interned.rs:20:1
|
20 | #[salsa::tracked(jar = Jar, specify)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TrackedStructInDb<dyn Db>` is not implemented for `MyInterned<'_>`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TrackedStructInDb<(dyn Db + 'static)>` is not implemented for `MyInterned<'_>`
|
= help: the trait `TrackedStructInDb<DB>` is implemented for `MyTracked<'db>`
note: required by a bound in `function::specify::<impl FunctionIngredient<C>>::specify_and_record`
--> src/function/specify.rs
|
| pub fn specify_and_record<'db>(&'db self, db: &'db DynDb<'db, C>, key: Id, value: C::Value<'db>)
| pub fn specify_and_record<'db>(&'db self, db: &'db DynDb<C>, key: Id, value: C::Value<'db>)
| ------------------ required by a bound in this associated function
| where
| C::Input<'db>: TrackedStructInDb<DynDb<'db, C>>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `function::specify::<impl FunctionIngredient<C>>::specify_and_record`
| C::Input<'db>: TrackedStructInDb<DynDb<C>>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `function::specify::<impl FunctionIngredient<C>>::specify_and_record`
= note: this error originates in the attribute macro `salsa::tracked` (in Nightly builds, run with -Z macro-backtrace for more info)

View file

@ -93,8 +93,8 @@ struct DerivedCustom<'db> {
value: u32,
}
impl<'db> DebugWithDb<dyn Db + 'db> for DerivedCustom<'db> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &(dyn Db + 'db)) -> std::fmt::Result {
impl<'db> DebugWithDb<dyn Db> for DerivedCustom<'db> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>, db: &dyn Db) -> std::fmt::Result {
write!(
f,
"{:?} / {:?}",