diff --git a/src/active_query.rs b/src/active_query.rs index 87b834b..720518b 100644 --- a/src/active_query.rs +++ b/src/active_query.rs @@ -6,7 +6,7 @@ use crate::{ key::{DatabaseKeyIndex, DependencyIndex}, tracked_struct::{Disambiguator, KeyStruct}, zalsa_local::EMPTY_DEPENDENCIES, - Cycle, Id, Revision, + Cycle, Revision, }; use super::zalsa_local::{EdgeKind, QueryEdges, QueryOrigin, QueryRevisions}; @@ -48,7 +48,7 @@ pub(crate) struct ActiveQuery { /// Map from tracked struct keys (which include the hash + disambiguator) to their /// final id. - pub(crate) tracked_struct_ids: FxHashMap, + pub(crate) tracked_struct_ids: FxHashMap, } impl ActiveQuery { diff --git a/src/function/diff_outputs.rs b/src/function/diff_outputs.rs index f365abc..eb3afbe 100644 --- a/src/function/diff_outputs.rs +++ b/src/function/diff_outputs.rs @@ -1,10 +1,9 @@ +use super::{memo::Memo, Configuration, IngredientImpl}; use crate::{ hash::FxHashSet, key::DependencyIndex, zalsa_local::QueryRevisions, AsDynDatabase as _, DatabaseKeyIndex, Event, EventKind, }; -use super::{memo::Memo, Configuration, IngredientImpl}; - impl IngredientImpl where C: Configuration, @@ -16,20 +15,24 @@ where db: &C::DbView, key: DatabaseKeyIndex, old_memo: &Memo>, - revisions: &QueryRevisions, + revisions: &mut QueryRevisions, ) { // Iterate over the outputs of the `old_memo` and put them into a hashset - let mut old_outputs = FxHashSet::default(); - old_memo.revisions.origin.outputs().for_each(|i| { - old_outputs.insert(i); - }); + let mut old_outputs: FxHashSet<_> = old_memo.revisions.origin.outputs().collect(); // Iterate over the outputs of the current query // and remove elements from `old_outputs` when we find them for new_output in revisions.origin.outputs() { - if old_outputs.contains(&new_output) { - old_outputs.remove(&new_output); - } + old_outputs.remove(&new_output); + } + + if !old_outputs.is_empty() { + revisions.tracked_struct_ids.retain(|_k, value| { + !old_outputs.contains(&DependencyIndex { + ingredient_index: value.ingredient_index, + key_index: Some(value.key_index), + }) + }); } for old_output in old_outputs { diff --git a/src/function/execute.rs b/src/function/execute.rs index 0f1876b..152fc34 100644 --- a/src/function/execute.rs +++ b/src/function/execute.rs @@ -81,7 +81,7 @@ where // old value. if let Some(old_memo) = &opt_old_memo { self.backdate_if_appropriate(old_memo, &mut revisions, &value); - self.diff_outputs(db, database_key_index, old_memo, &revisions); + self.diff_outputs(db, database_key_index, old_memo, &mut revisions); } tracing::debug!("{database_key_index:?}: read_upgrade: result.revisions = {revisions:#?}"); diff --git a/src/function/specify.rs b/src/function/specify.rs index 14b6c3d..d261371 100644 --- a/src/function/specify.rs +++ b/src/function/specify.rs @@ -73,7 +73,7 @@ where if let Some(old_memo) = self.get_memo_from_table_for(zalsa, key) { self.backdate_if_appropriate(&old_memo, &mut revisions, &value); - self.diff_outputs(db, database_key_index, &old_memo, &revisions); + self.diff_outputs(db, database_key_index, &old_memo, &mut revisions); } let memo = Memo { diff --git a/src/tracked_struct.rs b/src/tracked_struct.rs index 6b83d0a..98e3033 100644 --- a/src/tracked_struct.rs +++ b/src/tracked_struct.rs @@ -277,8 +277,9 @@ where None => { // This is a new tracked struct, so create an entry in the struct map. let id = self.allocate(zalsa, zalsa_local, current_revision, ¤t_deps, fields); - zalsa_local.add_output(self.database_key_index(id).into()); - zalsa_local.store_tracked_struct_id(key_struct, id); + let key = self.database_key_index(id); + zalsa_local.add_output(key.into()); + zalsa_local.store_tracked_struct_id(key_struct, key); C::struct_from_id(id) } } diff --git a/src/zalsa_local.rs b/src/zalsa_local.rs index e70cd38..877b47b 100644 --- a/src/zalsa_local.rs +++ b/src/zalsa_local.rs @@ -281,12 +281,15 @@ impl ZalsaLocal { ); self.with_query_stack(|stack| { let top_query = stack.last().unwrap(); - top_query.tracked_struct_ids.get(key_struct).cloned() + top_query + .tracked_struct_ids + .get(key_struct) + .map(|index| index.key_index()) }) } #[track_caller] - pub(crate) fn store_tracked_struct_id(&self, key_struct: KeyStruct, id: Id) { + pub(crate) fn store_tracked_struct_id(&self, key_struct: KeyStruct, id: DatabaseKeyIndex) { debug_assert!( self.query_in_progress(), "cannot create a tracked struct disambiguator outside of a tracked function" @@ -351,7 +354,7 @@ pub(crate) struct QueryRevisions { /// The ids of tracked structs created by this query. /// This is used to seed the next round if the query is /// re-executed. - pub(super) tracked_struct_ids: FxHashMap, + pub(super) tracked_struct_ids: FxHashMap, } impl QueryRevisions { @@ -508,7 +511,10 @@ impl ActiveQueryGuard<'_> { } /// Initialize the tracked struct ids with the values from the prior execution. - pub(crate) fn seed_tracked_struct_ids(&self, tracked_struct_ids: &FxHashMap) { + pub(crate) fn seed_tracked_struct_ids( + &self, + tracked_struct_ids: &FxHashMap, + ) { self.local_state.with_query_stack(|stack| { assert_eq!(stack.len(), self.push_len); let frame = stack.last_mut().unwrap(); diff --git a/tests/tracked_struct_recreate_new_revision.rs b/tests/tracked_struct_recreate_new_revision.rs index 61341a3..147ad60 100644 --- a/tests/tracked_struct_recreate_new_revision.rs +++ b/tests/tracked_struct_recreate_new_revision.rs @@ -1,4 +1,5 @@ -//! Test that a `tracked` struct on a `salsa::input` doesn't panic when recreating a new revision. +//! Test that re-creating a `tracked` struct after it was deleted in a previous +//! revision doesn't panic. #![allow(warnings)] use salsa::Setter; @@ -10,7 +11,6 @@ struct MyInput { #[salsa::tracked] struct TrackedStruct<'db> { - #[id] field: u32, }