mirror of
https://github.com/salsa-rs/salsa.git
synced 2025-08-04 19:08:32 +00:00
make tracked structs coarse-grained by default
This commit is contained in:
parent
88dc597fc9
commit
c90c2f2e8a
23 changed files with 269 additions and 88 deletions
|
@ -20,19 +20,36 @@ macro_rules! setup_tracked_struct {
|
|||
// Field names
|
||||
field_ids: [$($field_id:ident),*],
|
||||
|
||||
// Field names
|
||||
field_getters: [$($field_getter_vis:vis $field_getter_id:ident),*],
|
||||
// Tracked field names
|
||||
tracked_ids: [$($tracked_id:ident),*],
|
||||
|
||||
// Tracked field names
|
||||
tracked_getters: [$($tracked_getter_vis:vis $tracked_getter_id:ident),*],
|
||||
|
||||
// Untracked field names
|
||||
untracked_getters: [$($untracked_getter_vis:vis $untracked_getter_id:ident),*],
|
||||
|
||||
// Field types, may reference `db_lt`
|
||||
field_tys: [$($field_ty:ty),*],
|
||||
|
||||
// Tracked field types
|
||||
tracked_tys: [$($tracked_ty:ty),*],
|
||||
|
||||
// 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 fields to be used for id computations
|
||||
id_field_indices: [$($id_field_index:tt),*],
|
||||
// Indices of tracked fields.
|
||||
tracked_indices: [$($tracked_index:tt),*],
|
||||
|
||||
// A set of "field options". Each field option is a tuple `(maybe_clone, maybe_backdate)` where:
|
||||
// Indices of untracked fields.
|
||||
untracked_indices: [$($untracked_index:tt),*],
|
||||
|
||||
// A set of "field options" for each field.
|
||||
//
|
||||
// Each field option is a tuple `(maybe_clone, maybe_backdate)` where:
|
||||
//
|
||||
// * `maybe_clone` is either the identifier `clone` or `no_clone`
|
||||
// * `maybe_backdate` is either the identifier `backdate` or `no_backdate`
|
||||
|
@ -41,6 +58,12 @@ macro_rules! setup_tracked_struct {
|
|||
// (see e.g. @maybe_clone below).
|
||||
field_options: [$($field_option:tt),*],
|
||||
|
||||
// A set of "field options" for each tracked field.
|
||||
tracked_options: [$($tracked_option:tt),*],
|
||||
|
||||
// A set of "field options" for each untracked field.
|
||||
untracked_options: [$($untracked_option:tt),*],
|
||||
|
||||
// Number of fields
|
||||
num_fields: $N:literal,
|
||||
|
||||
|
@ -84,6 +107,10 @@ 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>;
|
||||
|
@ -98,8 +125,8 @@ macro_rules! setup_tracked_struct {
|
|||
s.0
|
||||
}
|
||||
|
||||
fn id_fields(fields: &Self::Fields<'_>) -> impl std::hash::Hash {
|
||||
( $( &fields.$id_field_index ),* )
|
||||
fn untracked_fields(fields: &Self::Fields<'_>) -> impl std::hash::Hash {
|
||||
( $( &fields.$untracked_index ),* )
|
||||
}
|
||||
|
||||
fn new_revisions(current_revision: $Revision) -> Self::Revisions {
|
||||
|
@ -133,6 +160,7 @@ macro_rules! setup_tracked_struct {
|
|||
pub fn ingredient(db: &dyn $zalsa::Database) -> &$zalsa_struct::IngredientImpl<$Configuration> {
|
||||
static CACHE: $zalsa::IngredientCache<$zalsa_struct::IngredientImpl<$Configuration>> =
|
||||
$zalsa::IngredientCache::new();
|
||||
|
||||
CACHE.get_or_create(db, || {
|
||||
db.zalsa().add_or_lookup_jar_by_type(&<$zalsa_struct::JarImpl::<$Configuration>>::default())
|
||||
})
|
||||
|
@ -199,17 +227,33 @@ macro_rules! setup_tracked_struct {
|
|||
}
|
||||
|
||||
$(
|
||||
$field_getter_vis fn $field_getter_id<$Db>(self, db: &$db_lt $Db) -> $crate::maybe_cloned_ty!($field_option, $db_lt, $field_ty)
|
||||
$tracked_getter_vis fn $tracked_getter_id<$Db>(self, db: &$db_lt $Db) -> $crate::maybe_cloned_ty!($tracked_option, $db_lt, $tracked_ty)
|
||||
where
|
||||
// FIXME(rust-lang/rust#65991): The `db` argument *should* have the type `dyn Database`
|
||||
$Db: ?Sized + $zalsa::Database,
|
||||
{
|
||||
let db = db.as_dyn_database();
|
||||
let fields = $Configuration::ingredient(db).field(db, self, $field_index);
|
||||
let fields = $Configuration::ingredient(db).tracked_field(db, self, $tracked_index);
|
||||
$crate::maybe_clone!(
|
||||
$field_option,
|
||||
$field_ty,
|
||||
&fields.$field_index,
|
||||
$tracked_option,
|
||||
$tracked_ty,
|
||||
&fields.$tracked_index,
|
||||
)
|
||||
}
|
||||
)*
|
||||
|
||||
$(
|
||||
$untracked_getter_vis fn $untracked_getter_id<$Db>(self, db: &$db_lt $Db) -> $crate::maybe_cloned_ty!($untracked_option, $db_lt, $untracked_ty)
|
||||
where
|
||||
// FIXME(rust-lang/rust#65991): The `db` argument *should* have the type `dyn Database`
|
||||
$Db: ?Sized + $zalsa::Database,
|
||||
{
|
||||
let db = db.as_dyn_database();
|
||||
let fields = $Configuration::ingredient(db).untracked_field(db, self, $untracked_index);
|
||||
$crate::maybe_clone!(
|
||||
$untracked_option,
|
||||
$untracked_ty,
|
||||
&fields.$untracked_index,
|
||||
)
|
||||
}
|
||||
)*
|
||||
|
|
|
@ -64,7 +64,7 @@ impl crate::options::AllowedOptions for InputStruct {
|
|||
impl SalsaStructAllowedOptions for InputStruct {
|
||||
const KIND: &'static str = "input";
|
||||
|
||||
const ALLOW_ID: bool = false;
|
||||
const ALLOW_TRACKED: bool = false;
|
||||
|
||||
const HAS_LIFETIME: bool = false;
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ impl crate::options::AllowedOptions for InternedStruct {
|
|||
impl SalsaStructAllowedOptions for InternedStruct {
|
||||
const KIND: &'static str = "interned";
|
||||
|
||||
const ALLOW_ID: bool = false;
|
||||
const ALLOW_TRACKED: bool = false;
|
||||
|
||||
const HAS_LIFETIME: bool = true;
|
||||
|
||||
|
|
|
@ -41,8 +41,8 @@ pub(crate) trait SalsaStructAllowedOptions: AllowedOptions {
|
|||
/// The kind of struct (e.g., interned, input, tracked).
|
||||
const KIND: &'static str;
|
||||
|
||||
/// Are `#[id]` fields allowed?
|
||||
const ALLOW_ID: bool;
|
||||
/// Are `#[tracked]` fields allowed?
|
||||
const ALLOW_TRACKED: bool;
|
||||
|
||||
/// Does this kind of struct have a `'db` lifetime?
|
||||
const HAS_LIFETIME: bool;
|
||||
|
@ -57,7 +57,7 @@ pub(crate) trait SalsaStructAllowedOptions: AllowedOptions {
|
|||
pub(crate) struct SalsaField<'s> {
|
||||
field: &'s syn::Field,
|
||||
|
||||
pub(crate) has_id_attr: bool,
|
||||
pub(crate) has_tracked_attr: bool,
|
||||
pub(crate) has_default_attr: bool,
|
||||
pub(crate) has_ref_attr: bool,
|
||||
pub(crate) has_no_eq_attr: bool,
|
||||
|
@ -69,7 +69,7 @@ const BANNED_FIELD_NAMES: &[&str] = &["from", "new"];
|
|||
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub(crate) const FIELD_OPTION_ATTRIBUTES: &[(&str, fn(&syn::Attribute, &mut SalsaField))] = &[
|
||||
("id", |_, ef| ef.has_id_attr = true),
|
||||
("tracked", |_, ef| ef.has_tracked_attr = true),
|
||||
("default", |_, ef| ef.has_default_attr = true),
|
||||
("return_ref", |_, ef| ef.has_ref_attr = true),
|
||||
("no_eq", |_, ef| ef.has_no_eq_attr = true),
|
||||
|
@ -105,7 +105,7 @@ where
|
|||
fields,
|
||||
};
|
||||
|
||||
this.maybe_disallow_id_fields()?;
|
||||
this.maybe_disallow_tracked_fields()?;
|
||||
this.maybe_disallow_default_fields()?;
|
||||
|
||||
this.check_generics()?;
|
||||
|
@ -129,24 +129,24 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Disallow `#[id]` attributes on the fields of this struct.
|
||||
/// Disallow `#[tracked]` attributes on the fields of this struct.
|
||||
///
|
||||
/// If an `#[id]` field is found, return an error.
|
||||
/// If an `#[tracked]` field is found, return an error.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `kind`, the attribute name (e.g., `input` or `interned`)
|
||||
fn maybe_disallow_id_fields(&self) -> syn::Result<()> {
|
||||
if A::ALLOW_ID {
|
||||
fn maybe_disallow_tracked_fields(&self) -> syn::Result<()> {
|
||||
if A::ALLOW_TRACKED {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Check if any field has the `#[id]` attribute.
|
||||
// Check if any field has the `#[tracked]` attribute.
|
||||
for ef in &self.fields {
|
||||
if ef.has_id_attr {
|
||||
if ef.has_tracked_attr {
|
||||
return Err(syn::Error::new_spanned(
|
||||
ef.field,
|
||||
format!("`#[id]` cannot be used with `#[salsa::{}]`", A::KIND),
|
||||
format!("`#[tracked]` cannot be used with `#[salsa::{}]`", A::KIND),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -199,25 +199,34 @@ where
|
|||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn tracked_ids(&self) -> Vec<&syn::Ident> {
|
||||
self.tracked_fields_iter()
|
||||
.map(|(_, f)| f.field.ident.as_ref().unwrap())
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn field_indices(&self) -> Vec<Literal> {
|
||||
(0..self.fields.len())
|
||||
.map(Literal::usize_unsuffixed)
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn num_fields(&self) -> Literal {
|
||||
Literal::usize_unsuffixed(self.fields.len())
|
||||
pub(crate) fn tracked_indices(&self) -> Vec<Literal> {
|
||||
self.tracked_fields_iter()
|
||||
.map(|(index, _)| Literal::usize_unsuffixed(index))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn id_field_indices(&self) -> Vec<Literal> {
|
||||
self.fields
|
||||
.iter()
|
||||
.zip(0..)
|
||||
.filter_map(|(f, index)| if f.has_id_attr { Some(index) } else { None })
|
||||
.map(Literal::usize_unsuffixed)
|
||||
pub(crate) fn untracked_indices(&self) -> Vec<Literal> {
|
||||
self.untracked_fields_iter()
|
||||
.map(|(index, _)| Literal::usize_unsuffixed(index))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn num_fields(&self) -> Literal {
|
||||
Literal::usize_unsuffixed(self.fields.len())
|
||||
}
|
||||
|
||||
pub(crate) fn required_fields(&self) -> Vec<TokenStream> {
|
||||
self.fields
|
||||
.iter()
|
||||
|
@ -237,10 +246,34 @@ where
|
|||
self.fields.iter().map(|f| &f.field.vis).collect()
|
||||
}
|
||||
|
||||
pub(crate) fn tracked_vis(&self) -> Vec<&syn::Visibility> {
|
||||
self.tracked_fields_iter()
|
||||
.map(|(_, f)| &f.field.vis)
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn untracked_vis(&self) -> Vec<&syn::Visibility> {
|
||||
self.untracked_fields_iter()
|
||||
.map(|(_, f)| &f.field.vis)
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn field_getter_ids(&self) -> Vec<&syn::Ident> {
|
||||
self.fields.iter().map(|f| &f.get_name).collect()
|
||||
}
|
||||
|
||||
pub(crate) fn tracked_getter_ids(&self) -> Vec<&syn::Ident> {
|
||||
self.tracked_fields_iter()
|
||||
.map(|(_, f)| &f.get_name)
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn untracked_getter_ids(&self) -> Vec<&syn::Ident> {
|
||||
self.untracked_fields_iter()
|
||||
.map(|(_, f)| &f.get_name)
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn field_setter_ids(&self) -> Vec<&syn::Ident> {
|
||||
self.fields.iter().map(|f| &f.set_name).collect()
|
||||
}
|
||||
|
@ -256,6 +289,18 @@ where
|
|||
self.fields.iter().map(|f| &f.field.ty).collect()
|
||||
}
|
||||
|
||||
pub(crate) fn tracked_tys(&self) -> Vec<&syn::Type> {
|
||||
self.tracked_fields_iter()
|
||||
.map(|(_, f)| &f.field.ty)
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn untracked_tys(&self) -> Vec<&syn::Type> {
|
||||
self.untracked_fields_iter()
|
||||
.map(|(_, f)| &f.field.ty)
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn field_indexed_tys(&self) -> Vec<syn::Ident> {
|
||||
self.fields
|
||||
.iter()
|
||||
|
@ -265,29 +310,18 @@ where
|
|||
}
|
||||
|
||||
pub(crate) fn field_options(&self) -> Vec<TokenStream> {
|
||||
self.fields
|
||||
.iter()
|
||||
.map(|f| {
|
||||
let clone_ident = if f.has_ref_attr {
|
||||
syn::Ident::new("no_clone", Span::call_site())
|
||||
} else {
|
||||
syn::Ident::new("clone", Span::call_site())
|
||||
};
|
||||
self.fields.iter().map(SalsaField::options).collect()
|
||||
}
|
||||
|
||||
let backdate_ident = if f.has_no_eq_attr {
|
||||
syn::Ident::new("no_backdate", Span::call_site())
|
||||
} else {
|
||||
syn::Ident::new("backdate", Span::call_site())
|
||||
};
|
||||
pub(crate) fn tracked_options(&self) -> Vec<TokenStream> {
|
||||
self.tracked_fields_iter()
|
||||
.map(|(_, f)| f.options())
|
||||
.collect()
|
||||
}
|
||||
|
||||
let default_ident = if f.has_default_attr {
|
||||
syn::Ident::new("default", Span::call_site())
|
||||
} else {
|
||||
syn::Ident::new("required", Span::call_site())
|
||||
};
|
||||
|
||||
quote!((#clone_ident, #backdate_ident, #default_ident))
|
||||
})
|
||||
pub(crate) fn untracked_options(&self) -> Vec<TokenStream> {
|
||||
self.untracked_fields_iter()
|
||||
.map(|(_, f)| f.options())
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
@ -298,6 +332,20 @@ where
|
|||
pub fn generate_lifetime(&self) -> bool {
|
||||
self.args.no_lifetime.is_none()
|
||||
}
|
||||
|
||||
fn tracked_fields_iter(&self) -> impl Iterator<Item = (usize, &SalsaField<'s>)> {
|
||||
self.fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, f)| f.has_tracked_attr)
|
||||
}
|
||||
|
||||
fn untracked_fields_iter(&self) -> impl Iterator<Item = (usize, &SalsaField<'s>)> {
|
||||
self.fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, f)| !f.has_tracked_attr)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s> SalsaField<'s> {
|
||||
|
@ -318,7 +366,7 @@ impl<'s> SalsaField<'s> {
|
|||
let set_name = Ident::new(&format!("set_{}", field_name_str), field_name.span());
|
||||
let mut result = SalsaField {
|
||||
field,
|
||||
has_id_attr: false,
|
||||
has_tracked_attr: false,
|
||||
has_ref_attr: false,
|
||||
has_default_attr: false,
|
||||
has_no_eq_attr: false,
|
||||
|
@ -337,4 +385,26 @@ impl<'s> SalsaField<'s> {
|
|||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn options(&self) -> TokenStream {
|
||||
let clone_ident = if self.has_ref_attr {
|
||||
syn::Ident::new("no_clone", Span::call_site())
|
||||
} else {
|
||||
syn::Ident::new("clone", Span::call_site())
|
||||
};
|
||||
|
||||
let backdate_ident = if self.has_no_eq_attr {
|
||||
syn::Ident::new("no_backdate", Span::call_site())
|
||||
} else {
|
||||
syn::Ident::new("backdate", Span::call_site())
|
||||
};
|
||||
|
||||
let default_ident = if self.has_default_attr {
|
||||
syn::Ident::new("default", Span::call_site())
|
||||
} else {
|
||||
syn::Ident::new("required", Span::call_site())
|
||||
};
|
||||
|
||||
quote!((#clone_ident, #backdate_ident, #default_ident))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ impl crate::options::AllowedOptions for TrackedStruct {
|
|||
impl SalsaStructAllowedOptions for TrackedStruct {
|
||||
const KIND: &'static str = "tracked";
|
||||
|
||||
const ALLOW_ID: bool = true;
|
||||
const ALLOW_TRACKED: bool = true;
|
||||
|
||||
const HAS_LIFETIME: bool = true;
|
||||
|
||||
|
@ -85,13 +85,21 @@ impl Macro {
|
|||
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 field_vis = salsa_struct.field_vis();
|
||||
let field_getter_ids = salsa_struct.field_getter_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 id_field_indices = salsa_struct.id_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 generate_debug_impl = salsa_struct.generate_debug_impl();
|
||||
|
||||
let zalsa = self.hygiene.ident("zalsa");
|
||||
|
@ -112,11 +120,18 @@ impl Macro {
|
|||
db_lt: #db_lt,
|
||||
new_fn: #new_fn,
|
||||
field_ids: [#(#field_ids),*],
|
||||
field_getters: [#(#field_vis #field_getter_ids),*],
|
||||
tracked_ids: [#(#tracked_ids),*],
|
||||
tracked_getters: [#(#tracked_vis #tracked_getter_ids),*],
|
||||
untracked_getters: [#(#untracked_vis #untracked_getter_ids),*],
|
||||
field_tys: [#(#field_tys),*],
|
||||
tracked_tys: [#(#tracked_tys),*],
|
||||
untracked_tys: [#(#untracked_tys),*],
|
||||
field_indices: [#(#field_indices),*],
|
||||
id_field_indices: [#(#id_field_indices),*],
|
||||
tracked_indices: [#(#tracked_indices),*],
|
||||
untracked_indices: [#(#untracked_indices),*],
|
||||
field_options: [#(#field_options),*],
|
||||
tracked_options: [#(#tracked_options),*],
|
||||
untracked_options: [#(#untracked_options),*],
|
||||
num_fields: #num_fields,
|
||||
generate_debug_impl: #generate_debug_impl,
|
||||
unused_names: [
|
||||
|
|
|
@ -28,6 +28,7 @@ pub struct FunctionId<'db> {
|
|||
// ANCHOR: program
|
||||
#[salsa::tracked]
|
||||
pub struct Program<'db> {
|
||||
#[tracked]
|
||||
#[return_ref]
|
||||
pub statements: Vec<Statement<'db>>,
|
||||
}
|
||||
|
@ -76,14 +77,16 @@ pub enum Op {
|
|||
// ANCHOR: functions
|
||||
#[salsa::tracked]
|
||||
pub struct Function<'db> {
|
||||
#[id]
|
||||
pub name: FunctionId<'db>,
|
||||
|
||||
#[tracked]
|
||||
name_span: Span<'db>,
|
||||
|
||||
#[tracked]
|
||||
#[return_ref]
|
||||
pub args: Vec<VariableId<'db>>,
|
||||
|
||||
#[tracked]
|
||||
#[return_ref]
|
||||
pub body: Expression<'db>,
|
||||
}
|
||||
|
@ -91,7 +94,9 @@ pub struct Function<'db> {
|
|||
|
||||
#[salsa::tracked]
|
||||
pub struct Span<'db> {
|
||||
#[tracked]
|
||||
pub start: usize,
|
||||
#[tracked]
|
||||
pub end: usize,
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ 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;
|
||||
|
@ -49,7 +50,7 @@ pub trait Configuration: Sized + 'static {
|
|||
/// Deref the struct to yield the underlying id.
|
||||
fn deref_struct(s: Self::Struct<'_>) -> Id;
|
||||
|
||||
fn id_fields(fields: &Self::Fields<'_>) -> impl Hash;
|
||||
fn untracked_fields(fields: &Self::Fields<'_>) -> impl Hash;
|
||||
|
||||
/// Create a new value revision array where each element is set to `current_revision`.
|
||||
fn new_revisions(current_revision: Revision) -> Self::Revisions;
|
||||
|
@ -108,7 +109,7 @@ 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::FIELD_DEBUG_NAMES.len()).map(|field_index| {
|
||||
.chain((0..C::TRACKED_FIELD_DEBUG_NAMES.len()).map(|field_index| {
|
||||
Box::new(<FieldIngredientImpl<C>>::new(struct_index, field_index)) as _
|
||||
}))
|
||||
.collect()
|
||||
|
@ -368,7 +369,7 @@ where
|
|||
|
||||
let identity_hash = IdentityHash {
|
||||
ingredient_index: self.ingredient_index,
|
||||
hash: crate::hash::hash(&C::id_fields(&fields)),
|
||||
hash: crate::hash::hash(&C::untracked_fields(&fields)),
|
||||
};
|
||||
|
||||
let (current_deps, disambiguator) = zalsa_local.disambiguate(identity_hash);
|
||||
|
@ -623,10 +624,11 @@ where
|
|||
unsafe { self.to_self_ref(&value.fields) }
|
||||
}
|
||||
|
||||
/// Access to this value field.
|
||||
/// Access to this tracked field.
|
||||
///
|
||||
/// Note that this function returns the entire tuple of value fields.
|
||||
/// The caller is responible for selecting the appropriate element.
|
||||
pub fn field<'db>(
|
||||
pub fn tracked_field<'db>(
|
||||
&'db self,
|
||||
db: &'db dyn crate::Database,
|
||||
s: C::Struct<'db>,
|
||||
|
@ -650,6 +652,25 @@ where
|
|||
|
||||
unsafe { self.to_self_ref(&data.fields) }
|
||||
}
|
||||
|
||||
/// Access to this untracked field.
|
||||
///
|
||||
/// Note that this function returns the entire tuple of value fields.
|
||||
/// The caller is responible for selecting the appropriate element.
|
||||
pub fn untracked_field<'db>(
|
||||
&'db self,
|
||||
db: &'db dyn crate::Database,
|
||||
s: C::Struct<'db>,
|
||||
_field_index: usize,
|
||||
) -> &'db C::Fields<'db> {
|
||||
let (zalsa, _) = db.zalsas();
|
||||
let id = C::deref_struct(s);
|
||||
let data = Self::data(zalsa.table(), id);
|
||||
|
||||
data.read_lock(zalsa.current_revision());
|
||||
|
||||
unsafe { self.to_self_ref(&data.fields) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> Ingredient for IngredientImpl<C>
|
||||
|
|
|
@ -17,8 +17,8 @@ struct InputWithRecover(u32);
|
|||
struct InputWithLru(u32);
|
||||
|
||||
#[salsa::input]
|
||||
struct InputWithIdField {
|
||||
#[id]
|
||||
struct InputWithTrackedField {
|
||||
#[tracked]
|
||||
field: u32,
|
||||
}
|
||||
|
||||
|
|
|
@ -34,15 +34,22 @@ error: `lru` option not allowed here
|
|||
16 | #[salsa::input(lru =12)]
|
||||
| ^^^
|
||||
|
||||
error: `#[id]` cannot be used with `#[salsa::input]`
|
||||
error: `#[tracked]` cannot be used with `#[salsa::input]`
|
||||
--> tests/compile-fail/input_struct_incompatibles.rs:21:5
|
||||
|
|
||||
21 | / #[id]
|
||||
21 | / #[tracked]
|
||||
22 | | field: u32,
|
||||
| |______________^
|
||||
|
||||
error: cannot find attribute `id` in this scope
|
||||
error: cannot find attribute `tracked` in this scope
|
||||
--> tests/compile-fail/input_struct_incompatibles.rs:21:7
|
||||
|
|
||||
21 | #[id]
|
||||
| ^^
|
||||
21 | #[tracked]
|
||||
| ^^^^^^^
|
||||
|
|
||||
help: consider importing one of these attribute macros
|
||||
|
|
||||
1 + use salsa::tracked;
|
||||
|
|
||||
1 + use salsa_macros::tracked;
|
||||
|
|
||||
|
|
|
@ -29,8 +29,8 @@ struct InternedWithLru {
|
|||
}
|
||||
|
||||
#[salsa::interned]
|
||||
struct InternedWithIdField {
|
||||
#[id]
|
||||
struct InternedWithTrackedField {
|
||||
#[tracked]
|
||||
field: u32,
|
||||
}
|
||||
|
||||
|
|
|
@ -34,15 +34,22 @@ error: `lru` option not allowed here
|
|||
26 | #[salsa::interned(lru = 12)]
|
||||
| ^^^
|
||||
|
||||
error: `#[id]` cannot be used with `#[salsa::interned]`
|
||||
error: `#[tracked]` cannot be used with `#[salsa::interned]`
|
||||
--> tests/compile-fail/interned_struct_incompatibles.rs:33:5
|
||||
|
|
||||
33 | / #[id]
|
||||
33 | / #[tracked]
|
||||
34 | | field: u32,
|
||||
| |______________^
|
||||
|
||||
error: cannot find attribute `id` in this scope
|
||||
error: cannot find attribute `tracked` in this scope
|
||||
--> tests/compile-fail/interned_struct_incompatibles.rs:33:7
|
||||
|
|
||||
33 | #[id]
|
||||
| ^^
|
||||
33 | #[tracked]
|
||||
| ^^^^^^^
|
||||
|
|
||||
help: consider importing one of these attribute macros
|
||||
|
|
||||
1 + use salsa::tracked;
|
||||
|
|
||||
1 + use salsa_macros::tracked;
|
||||
|
|
||||
|
|
|
@ -14,9 +14,9 @@ struct MyInput {
|
|||
|
||||
#[salsa::tracked]
|
||||
struct MyTracked<'db> {
|
||||
#[id]
|
||||
identifier: u32,
|
||||
|
||||
#[tracked]
|
||||
#[return_ref]
|
||||
field: Bomb,
|
||||
}
|
||||
|
|
|
@ -28,7 +28,9 @@ fn final_result_depends_on_y(db: &dyn LogDatabase, input: MyInput) -> u32 {
|
|||
|
||||
#[salsa::tracked]
|
||||
struct MyTracked<'db> {
|
||||
#[tracked]
|
||||
x: u32,
|
||||
#[tracked]
|
||||
y: u32,
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ fn result_depends_on_y(db: &dyn LogDatabase, input: MyInput) -> u32 {
|
|||
db.push_log(format!("result_depends_on_y({:?})", input));
|
||||
input.y(db) - 1
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn execute() {
|
||||
// result_depends_on_x = x + 1
|
||||
|
|
|
@ -21,6 +21,7 @@ struct MyInput {
|
|||
|
||||
#[salsa::tracked]
|
||||
struct MyTracked<'db> {
|
||||
#[tracked]
|
||||
counter: usize,
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ struct MyInput {
|
|||
|
||||
#[salsa::tracked]
|
||||
struct MyTracked<'db> {
|
||||
#[tracked]
|
||||
counter: usize,
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@ impl From<bool> for BadEq {
|
|||
|
||||
#[salsa::tracked]
|
||||
struct MyTracked<'db> {
|
||||
#[id]
|
||||
field: BadEq,
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
//! Test for a tracked struct where the id field has a
|
||||
//! Test for a tracked struct where an untracked field has a
|
||||
//! very poorly chosen hash impl (always returns 0).
|
||||
//! This demonstrates that the `#[id]` fields on a struct
|
||||
//! This demonstrates that the `untracked fields on a struct
|
||||
//! can change values and yet the struct can have the same
|
||||
//! id (because struct ids are based on the *hash* of the
|
||||
//! `#[id]` fields).
|
||||
//! untracked fields).
|
||||
|
||||
use salsa::{Database as Db, Setter};
|
||||
use test_log::test;
|
||||
|
@ -32,7 +32,6 @@ impl std::hash::Hash for BadHash {
|
|||
|
||||
#[salsa::tracked]
|
||||
struct MyTracked<'db> {
|
||||
#[id]
|
||||
field: BadHash,
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ impl From<bool> for BadEq {
|
|||
|
||||
#[salsa::tracked]
|
||||
struct MyTracked<'db> {
|
||||
#[tracked]
|
||||
field: BadEq,
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ impl From<bool> for NotEq {
|
|||
|
||||
#[salsa::tracked]
|
||||
struct MyTracked<'db> {
|
||||
#[tracked]
|
||||
#[no_eq]
|
||||
field: NotEq,
|
||||
}
|
||||
|
|
|
@ -32,21 +32,25 @@ struct File {
|
|||
|
||||
#[salsa::tracked]
|
||||
struct Definition<'db> {
|
||||
#[tracked]
|
||||
file: File,
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
struct Index<'db> {
|
||||
#[tracked]
|
||||
definitions: Definitions<'db>,
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
struct Definitions<'db> {
|
||||
#[tracked]
|
||||
definition: Definition<'db>,
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
struct Inference<'db> {
|
||||
#[tracked]
|
||||
definition: Definition<'db>,
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ struct MyInput {
|
|||
|
||||
#[salsa::tracked]
|
||||
struct MyTracked<'db> {
|
||||
#[tracked]
|
||||
field: MyInterned<'db>,
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,9 @@ struct MyInput {
|
|||
|
||||
#[salsa::tracked]
|
||||
struct MyTracked<'db> {
|
||||
#[tracked]
|
||||
data: MyInput,
|
||||
#[tracked]
|
||||
next: MyList<'db>,
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue