mirror of
https://github.com/salsa-rs/salsa.git
synced 2025-07-07 21:35:17 +00:00
ensure tracked struct ingredients are mapped correctly to tracked fields
This commit is contained in:
parent
c90c2f2e8a
commit
9436f8ff6b
5 changed files with 94 additions and 23 deletions
|
@ -2,49 +2,49 @@
|
|||
#[macro_export]
|
||||
macro_rules! setup_tracked_struct {
|
||||
(
|
||||
// Attributes on the function
|
||||
// Attributes on the function.
|
||||
attrs: [$(#[$attr:meta]),*],
|
||||
|
||||
// Visibility of the struct
|
||||
// Visibility of the struct.
|
||||
vis: $vis:vis,
|
||||
|
||||
// Name of the struct
|
||||
// Name of the struct.
|
||||
Struct: $Struct:ident,
|
||||
|
||||
// Name of the `'db` lifetime that the user gave
|
||||
// Name of the `'db` lifetime that the user gave.
|
||||
db_lt: $db_lt:lifetime,
|
||||
|
||||
// Name user gave for `new`
|
||||
// Name user gave for `new`.
|
||||
new_fn: $new_fn:ident,
|
||||
|
||||
// Field names
|
||||
// Field names.
|
||||
field_ids: [$($field_id:ident),*],
|
||||
|
||||
// Tracked field names
|
||||
// Tracked field names.
|
||||
tracked_ids: [$($tracked_id:ident),*],
|
||||
|
||||
// Tracked field names
|
||||
// Visibility and names of tracked fields.
|
||||
tracked_getters: [$($tracked_getter_vis:vis $tracked_getter_id:ident),*],
|
||||
|
||||
// Untracked field names
|
||||
// Visibility and names of untracked fields.
|
||||
untracked_getters: [$($untracked_getter_vis:vis $untracked_getter_id:ident),*],
|
||||
|
||||
// Field types, may reference `db_lt`
|
||||
// Field types, may reference `db_lt`.
|
||||
field_tys: [$($field_ty:ty),*],
|
||||
|
||||
// Tracked field types
|
||||
// Tracked field types.
|
||||
tracked_tys: [$($tracked_ty:ty),*],
|
||||
|
||||
// Untracked field types
|
||||
// Untracked field types.
|
||||
untracked_tys: [$($untracked_ty:ty),*],
|
||||
|
||||
// Indices for each field from 0..N -- must be unsuffixed (e.g., `0`, `1`).
|
||||
field_indices: [$($field_index:tt),*],
|
||||
|
||||
// Indices of tracked fields.
|
||||
// Absolute indices of any tracked fields, relative to all other fields of this struct.
|
||||
tracked_indices: [$($tracked_index:tt),*],
|
||||
|
||||
// Indices of untracked fields.
|
||||
// Absolute indices of any untracked fields.
|
||||
untracked_indices: [$($untracked_index:tt),*],
|
||||
|
||||
// A set of "field options" for each field.
|
||||
|
@ -64,7 +64,7 @@ macro_rules! setup_tracked_struct {
|
|||
// A set of "field options" for each untracked field.
|
||||
untracked_options: [$($untracked_option:tt),*],
|
||||
|
||||
// Number of fields
|
||||
// Number of fields.
|
||||
num_fields: $N:literal,
|
||||
|
||||
// If true, generate a debug impl.
|
||||
|
@ -107,10 +107,6 @@ macro_rules! setup_tracked_struct {
|
|||
$(stringify!($field_id),)*
|
||||
];
|
||||
|
||||
const TRACKED_FIELD_DEBUG_NAMES: &'static [&'static str] = &[
|
||||
$(stringify!($tracked_id),)*
|
||||
];
|
||||
|
||||
type Fields<$db_lt> = ($($field_ty,)*);
|
||||
|
||||
type Revisions = $zalsa::Array<$Revision, $N>;
|
||||
|
|
|
@ -84,22 +84,29 @@ impl Macro {
|
|||
let struct_ident = &self.struct_item.ident;
|
||||
let db_lt = db_lifetime::db_lifetime(&self.struct_item.generics);
|
||||
let new_fn = salsa_struct.constructor_name();
|
||||
|
||||
let field_ids = salsa_struct.field_ids();
|
||||
let tracked_ids = salsa_struct.tracked_ids();
|
||||
|
||||
let tracked_vis = salsa_struct.tracked_vis();
|
||||
let untracked_vis = salsa_struct.untracked_vis();
|
||||
|
||||
let tracked_getter_ids = salsa_struct.tracked_getter_ids();
|
||||
let untracked_getter_ids = salsa_struct.untracked_getter_ids();
|
||||
|
||||
let field_indices = salsa_struct.field_indices();
|
||||
let tracked_indices = salsa_struct.tracked_indices();
|
||||
let untracked_indices = salsa_struct.untracked_indices();
|
||||
let num_fields = salsa_struct.num_fields();
|
||||
|
||||
let field_options = salsa_struct.field_options();
|
||||
let tracked_options = salsa_struct.tracked_options();
|
||||
let untracked_options = salsa_struct.untracked_options();
|
||||
|
||||
let field_tys = salsa_struct.field_tys();
|
||||
let tracked_tys = salsa_struct.tracked_tys();
|
||||
let untracked_tys = salsa_struct.untracked_tys();
|
||||
|
||||
let num_fields = salsa_struct.num_fields();
|
||||
let generate_debug_impl = salsa_struct.generate_debug_impl();
|
||||
|
||||
let zalsa = self.hygiene.ident("zalsa");
|
||||
|
|
|
@ -79,7 +79,6 @@ pub enum Op {
|
|||
pub struct Function<'db> {
|
||||
pub name: FunctionId<'db>,
|
||||
|
||||
#[tracked]
|
||||
name_span: Span<'db>,
|
||||
|
||||
#[tracked]
|
||||
|
|
|
@ -26,7 +26,6 @@ pub mod tracked_field;
|
|||
pub trait Configuration: Sized + 'static {
|
||||
const DEBUG_NAME: &'static str;
|
||||
const FIELD_DEBUG_NAMES: &'static [&'static str];
|
||||
const TRACKED_FIELD_DEBUG_NAMES: &'static [&'static str];
|
||||
|
||||
/// A (possibly empty) tuple of the fields for this struct.
|
||||
type Fields<'db>: Send + Sync;
|
||||
|
@ -109,7 +108,9 @@ impl<C: Configuration> Jar for JarImpl<C> {
|
|||
let struct_ingredient = <IngredientImpl<C>>::new(struct_index);
|
||||
|
||||
std::iter::once(Box::new(struct_ingredient) as _)
|
||||
.chain((0..C::TRACKED_FIELD_DEBUG_NAMES.len()).map(|field_index| {
|
||||
// Note that we create ingredients for untracked fields as well, in order to
|
||||
// keep field indices relative to the entire struct.
|
||||
.chain((0..C::FIELD_DEBUG_NAMES.len()).map(|field_index| {
|
||||
Box::new(<FieldIngredientImpl<C>>::new(struct_index, field_index)) as _
|
||||
}))
|
||||
.collect()
|
||||
|
|
68
tests/tracked_struct_mixed_tracked_fields.rs
Normal file
68
tests/tracked_struct_mixed_tracked_fields.rs
Normal file
|
@ -0,0 +1,68 @@
|
|||
mod common;
|
||||
|
||||
use salsa::{Database, Setter};
|
||||
|
||||
// A tracked struct with mixed tracked and untracked fields to ensure
|
||||
// the correct field indices are used when tracking dependencies.
|
||||
#[salsa::tracked]
|
||||
struct Tracked<'db> {
|
||||
untracked_1: usize,
|
||||
|
||||
#[tracked]
|
||||
tracked_1: usize,
|
||||
|
||||
untracked_2: usize,
|
||||
|
||||
untracked_3: usize,
|
||||
|
||||
#[tracked]
|
||||
tracked_2: usize,
|
||||
|
||||
untracked_4: usize,
|
||||
}
|
||||
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
field1: usize,
|
||||
field2: usize,
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn intermediate(db: &dyn salsa::Database, input: MyInput) -> Tracked<'_> {
|
||||
Tracked::new(db, 0, input.field1(db), 0, 0, input.field2(db), 0)
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn accumulate(db: &dyn salsa::Database, input: MyInput) -> (usize, usize) {
|
||||
let tracked = intermediate(db, input);
|
||||
let one = read_tracked_1(db, tracked);
|
||||
let two = read_tracked_2(db, tracked);
|
||||
|
||||
(one, two)
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn read_tracked_1<'db>(db: &'db dyn Database, tracked: Tracked<'db>) -> usize {
|
||||
tracked.tracked_1(db)
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn read_tracked_2<'db>(db: &'db dyn Database, tracked: Tracked<'db>) -> usize {
|
||||
tracked.tracked_2(db)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn execute() {
|
||||
let mut db = salsa::DatabaseImpl::default();
|
||||
let input = MyInput::new(&db, 1, 1);
|
||||
|
||||
assert_eq!(accumulate(&db, input), (1, 1));
|
||||
|
||||
// Should only re-execute `read_tracked_1`.
|
||||
input.set_field1(&mut db).to(2);
|
||||
assert_eq!(accumulate(&db, input), (2, 1));
|
||||
|
||||
// Should only re-execute `read_tracked_2`.
|
||||
input.set_field2(&mut db).to(2);
|
||||
assert_eq!(accumulate(&db, input), (2, 2));
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue