diff --git a/components/salsa-2022-macros/src/accumulator.rs b/components/salsa-2022-macros/src/accumulator.rs index e3323a00..7bb6d157 100644 --- a/components/salsa-2022-macros/src/accumulator.rs +++ b/components/salsa-2022-macros/src/accumulator.rs @@ -40,15 +40,6 @@ impl crate::options::AllowedOptions for Accumulator { const CONSTRUCTOR_NAME: bool = false; } -impl crate::modes::AllowedModes for Accumulator { - const TRACKED: bool = false; - - const INPUT: bool = false; - - const INTERNED: bool = false; - - const ACCUMULATOR: bool = true; -} fn accumulator_contents( args: &Args, diff --git a/components/salsa-2022-macros/src/input.rs b/components/salsa-2022-macros/src/input.rs index 9ff8b195..6e214f0c 100644 --- a/components/salsa-2022-macros/src/input.rs +++ b/components/salsa-2022-macros/src/input.rs @@ -1,4 +1,3 @@ -use crate::modes::Mode; use crate::salsa_struct::{SalsaField, SalsaStruct}; use proc_macro2::{Literal, TokenStream}; @@ -11,19 +10,16 @@ pub(crate) fn input( args: proc_macro::TokenStream, input: proc_macro::TokenStream, ) -> proc_macro::TokenStream { - let mode = Mode { - ..Default::default() - }; - match SalsaStruct::new(args, input, mode).and_then(|el| InputStruct(el).generate_input()) { + match SalsaStruct::new(args, input).and_then(|el| InputStruct(el).generate_input()) { Ok(s) => s.into(), Err(err) => err.into_compile_error().into(), } } -struct InputStruct(SalsaStruct); +struct InputStruct(SalsaStruct); impl std::ops::Deref for InputStruct { - type Target = SalsaStruct; + type Target = SalsaStruct; fn deref(&self) -> &Self::Target { &self.0 @@ -51,15 +47,7 @@ impl crate::options::AllowedOptions for InputStruct { const CONSTRUCTOR_NAME: bool = true; } -impl crate::modes::AllowedModes for InputStruct { - const TRACKED: bool = false; - const INPUT: bool = true; - - const INTERNED: bool = false; - - const ACCUMULATOR: bool = false; -} impl InputStruct { fn generate_input(&self) -> syn::Result { @@ -89,14 +77,6 @@ impl InputStruct { fn validate_input(&self) -> syn::Result<()> { // check for dissalowed fields self.disallow_id_fields("input")?; - - // check if an input struct labeled singleton truly has one field - if self.0.is_isingleton() && self.0.num_fields() != 1 { - return Err(syn::Error::new( - self.0.struct_span(), - format!("`Singleton` input mut have only one field"), - )); - } Ok(()) } diff --git a/components/salsa-2022-macros/src/interned.rs b/components/salsa-2022-macros/src/interned.rs index 3a820f0d..8fd4ce58 100644 --- a/components/salsa-2022-macros/src/interned.rs +++ b/components/salsa-2022-macros/src/interned.rs @@ -1,4 +1,3 @@ -use crate::modes::Mode; use crate::salsa_struct::SalsaStruct; use proc_macro2::TokenStream; @@ -14,20 +13,17 @@ pub(crate) fn interned( args: proc_macro::TokenStream, input: proc_macro::TokenStream, ) -> proc_macro::TokenStream { - let mode = Mode { - ..Default::default() - }; - match SalsaStruct::new(args, input, mode).and_then(|el| InternedStruct(el).generate_interned()) + match SalsaStruct::new(args, input).and_then(|el| InternedStruct(el).generate_interned()) { Ok(s) => s.into(), Err(err) => err.into_compile_error().into(), } } -struct InternedStruct(SalsaStruct); +struct InternedStruct(SalsaStruct); impl std::ops::Deref for InternedStruct { - type Target = SalsaStruct; + type Target = SalsaStruct; fn deref(&self) -> &Self::Target { &self.0 @@ -56,15 +52,6 @@ impl crate::options::AllowedOptions for InternedStruct { const CONSTRUCTOR_NAME: bool = true; } -impl crate::modes::AllowedModes for InternedStruct { - const TRACKED: bool = false; - - const INPUT: bool = true; - - const INTERNED: bool = false; - - const ACCUMULATOR: bool = false; -} impl InternedStruct { fn generate_interned(&self) -> syn::Result { diff --git a/components/salsa-2022-macros/src/lib.rs b/components/salsa-2022-macros/src/lib.rs index 61388b68..45b31e67 100644 --- a/components/salsa-2022-macros/src/lib.rs +++ b/components/salsa-2022-macros/src/lib.rs @@ -36,7 +36,6 @@ mod db; mod input; mod interned; mod jar; -mod modes; mod options; mod salsa_struct; mod tracked; diff --git a/components/salsa-2022-macros/src/modes.rs b/components/salsa-2022-macros/src/modes.rs deleted file mode 100644 index bb8c2ce1..00000000 --- a/components/salsa-2022-macros/src/modes.rs +++ /dev/null @@ -1,29 +0,0 @@ -use std::marker::PhantomData; - -/// The four possible modes of Salsa structs -/// Salsa structs asre generic over AllowedModes. -pub(crate) trait AllowedModes { - const TRACKED: bool; - const INPUT: bool; - const INTERNED: bool; - const ACCUMULATOR: bool; -} - -/// -pub(crate) struct Mode { - pub(super) phantom: PhantomData, -} - -impl Default for Mode { - fn default() -> Self { - Self { - phantom: Default::default(), - } - } -} - -impl Mode { - pub(crate) fn singleton_allowed(&self) -> bool { - M::INPUT - } -} diff --git a/components/salsa-2022-macros/src/options.rs b/components/salsa-2022-macros/src/options.rs index 38a8fb7e..96c9fd46 100644 --- a/components/salsa-2022-macros/src/options.rs +++ b/components/salsa-2022-macros/src/options.rs @@ -2,12 +2,13 @@ use std::marker::PhantomData; use syn::{ext::IdentExt, spanned::Spanned}; + /// "Options" are flags that can be supplied to the various salsa related /// macros. They are listed like `(ref, no_eq, foo=bar)` etc. The commas /// are required and trailing commas are permitted. The options accepted /// for any particular location are configured via the `AllowedOptions` /// trait. -pub(crate) struct Options { +pub(crate) struct Options { /// The `return_ref` option is used to signal that field/return type is "by ref" /// /// If this is `Some`, the value is the `ref` identifier. @@ -116,7 +117,7 @@ impl Options { } } -impl syn::parse::Parse for Options { +impl syn::parse::Parse for Options { fn parse(input: syn::parse::ParseStream) -> syn::Result { let mut options = Options::default(); diff --git a/components/salsa-2022-macros/src/salsa_struct.rs b/components/salsa-2022-macros/src/salsa_struct.rs index 0e74e020..526c7613 100644 --- a/components/salsa-2022-macros/src/salsa_struct.rs +++ b/components/salsa-2022-macros/src/salsa_struct.rs @@ -25,46 +25,39 @@ //! * data method `impl Foo { fn data(&self, db: &dyn crate::Db) -> FooData { FooData { f: self.f(db), ... } } }` //! * this could be optimized, particularly for interned fields -use crate::modes::Mode; use crate::{ configuration, - modes::AllowedModes, options::{AllowedOptions, Options}, }; use heck::ToUpperCamelCase; use proc_macro2::{Ident, Literal, Span, TokenStream}; use syn::spanned::Spanned; -pub(crate) struct SalsaStruct { +pub(crate) struct SalsaStruct { args: Options, - _mode: Mode, struct_item: syn::ItemStruct, fields: Vec, } const BANNED_FIELD_NAMES: &[&str] = &["from", "new"]; -impl SalsaStruct { +impl SalsaStruct { pub(crate) fn new( args: proc_macro::TokenStream, input: proc_macro::TokenStream, - mode: Mode, ) -> syn::Result { let struct_item = syn::parse(input)?; - Self::with_struct(args, struct_item, mode) + Self::with_struct(args, struct_item) } pub(crate) fn with_struct( args: proc_macro::TokenStream, struct_item: syn::ItemStruct, - mode: Mode, ) -> syn::Result { let args: Options = syn::parse(args)?; let fields = Self::extract_options(&struct_item)?; - check_singleton(&mode, args.singleton.as_ref(), struct_item.span())?; Ok(Self { args, - _mode: mode, struct_item, fields, }) @@ -133,13 +126,6 @@ impl SalsaStruct { self.args.singleton.is_some() } - pub(crate) fn num_fields(&self) -> usize { - self.fields.len() - } - - pub(crate) fn struct_span(&self) -> Span { - self.struct_item.span() - } pub(crate) fn db_dyn_ty(&self) -> syn::Type { let jar_ty = self.jar_ty(); @@ -450,17 +436,3 @@ impl SalsaField { } } -pub(crate) fn check_singleton( - mode: &Mode, - sing: Option<&syn::Ident>, - s_span: Span, -) -> syn::Result<()> { - if !mode.singleton_allowed() && sing.is_some() { - Err(syn::Error::new( - s_span, - format!("`Singleton` not allowed for this Salsa struct type"), - )) - } else { - Ok(()) - } -} diff --git a/components/salsa-2022-macros/src/tracked_struct.rs b/components/salsa-2022-macros/src/tracked_struct.rs index 87f2a156..7f96abfe 100644 --- a/components/salsa-2022-macros/src/tracked_struct.rs +++ b/components/salsa-2022-macros/src/tracked_struct.rs @@ -1,7 +1,6 @@ use proc_macro2::{Literal, TokenStream}; use crate::{ - modes::Mode, salsa_struct::{SalsaField, SalsaStruct}, }; @@ -14,10 +13,7 @@ pub(crate) fn tracked( args: proc_macro::TokenStream, struct_item: syn::ItemStruct, ) -> proc_macro::TokenStream { - let mode = Mode { - ..Default::default() - }; - match SalsaStruct::with_struct(args, struct_item, mode) + match SalsaStruct::with_struct(args, struct_item) .and_then(|el| TrackedStruct(el).generate_tracked()) { Ok(s) => s.into(), @@ -25,10 +21,10 @@ pub(crate) fn tracked( } } -struct TrackedStruct(SalsaStruct); +struct TrackedStruct(SalsaStruct); impl std::ops::Deref for TrackedStruct { - type Target = SalsaStruct; + type Target = SalsaStruct; fn deref(&self) -> &Self::Target { &self.0 @@ -57,15 +53,7 @@ impl crate::options::AllowedOptions for TrackedStruct { const CONSTRUCTOR_NAME: bool = true; } -impl crate::modes::AllowedModes for TrackedStruct { - const TRACKED: bool = true; - const INPUT: bool = false; - - const INTERNED: bool = false; - - const ACCUMULATOR: bool = false; -} impl TrackedStruct { fn generate_tracked(&self) -> syn::Result { diff --git a/salsa-2022-tests/tests/compile-fail/singleton_only_for_input.rs b/salsa-2022-tests/tests/compile-fail/singleton_only_for_input.rs new file mode 100644 index 00000000..ff0c2d05 --- /dev/null +++ b/salsa-2022-tests/tests/compile-fail/singleton_only_for_input.rs @@ -0,0 +1,55 @@ +//! Compile Singleton struct test: +//! +//! Singleton flags are only allowed for input structs. If applied on any other Salsa struct compilation must fail + +use salsa_2022_tests::{HasLogger, Logger}; + +use test_log::test; + +#[salsa::jar(db = Db)] +struct Jar(MyInput, MyTracked, Integers, create_tracked_structs ); + +trait Db: salsa::DbWithJar + HasLogger {} + +#[salsa::input(singleton)] +struct MyInput { + field: u32, +} + + +#[salsa::tracked(singleton)] +struct MyTracked { + field: u32, +} + + +#[salsa::tracked(singleton)] +fn create_tracked_structs(db: &dyn Db, input: MyInput) -> Vec { + (0..input.field(db)) + .map(|i| MyTracked::new(db, i)) + .collect() +} + +#[salsa::accumulator(singleton)] +struct Integers(u32); + + +#[salsa::db(Jar)] +#[derive(Default)] +struct Database { + storage: salsa::Storage, + logger: Logger, +} + +impl salsa::Database for Database {} + +impl Db for Database {} + +impl HasLogger for Database { + fn logger(&self) -> &Logger { + &self.logger + } +} + + +fn main() {} \ No newline at end of file diff --git a/salsa-2022-tests/tests/compile-fail/singleton_only_for_input.stderr b/salsa-2022-tests/tests/compile-fail/singleton_only_for_input.stderr new file mode 100644 index 00000000..1069544a --- /dev/null +++ b/salsa-2022-tests/tests/compile-fail/singleton_only_for_input.stderr @@ -0,0 +1,43 @@ +error: `singleton` option not allowed here + --> tests/compile-fail/singleton_only_for_input.rs:20:18 + | +20 | #[salsa::tracked(singleton)] + | ^^^^^^^^^ + +error: `singleton` option not allowed here + --> tests/compile-fail/singleton_only_for_input.rs:26:18 + | +26 | #[salsa::tracked(singleton)] + | ^^^^^^^^^ + +error: `singleton` option not allowed here + --> tests/compile-fail/singleton_only_for_input.rs:33:22 + | +33 | #[salsa::accumulator(singleton)] + | ^^^^^^^^^ + +error[E0412]: cannot find type `MyTracked` in this scope + --> tests/compile-fail/singleton_only_for_input.rs:10:21 + | +10 | struct Jar(MyInput, MyTracked, Integers, create_tracked_structs ); + | ^^^^^^^^^ not found in this scope + +error[E0412]: cannot find type `Integers` in this scope + --> tests/compile-fail/singleton_only_for_input.rs:10:32 + | +10 | struct Jar(MyInput, MyTracked, Integers, create_tracked_structs ); + | ^^^^^^^^ not found in this scope + +error[E0412]: cannot find type `create_tracked_structs` in this scope + --> tests/compile-fail/singleton_only_for_input.rs:10:42 + | +10 | struct Jar(MyInput, MyTracked, Integers, create_tracked_structs ); + | ^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + +warning: unused import: `test_log::test` + --> tests/compile-fail/singleton_only_for_input.rs:7:5 + | +7 | use test_log::test; + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(unused_imports)]` on by default diff --git a/salsa-2022-tests/tests/compile-fail/specify-does-not-work-if-the-key-is-a-salsa-interned.rs b/salsa-2022-tests/tests/compile-fail/specify-does-not-work-if-the-key-is-a-salsa-interned.rs index 8c4cca31..a40e8c58 100644 --- a/salsa-2022-tests/tests/compile-fail/specify-does-not-work-if-the-key-is-a-salsa-interned.rs +++ b/salsa-2022-tests/tests/compile-fail/specify-does-not-work-if-the-key-is-a-salsa-interned.rs @@ -17,6 +17,7 @@ struct MyTracked { field: u32, } + #[salsa::tracked(jar = Jar, specify)] fn tracked_fn(db: &dyn Db, input: MyInterned) -> MyTracked { MyTracked::new(db, input.field(db) * 2) diff --git a/salsa-2022-tests/tests/compile-fail/specify-does-not-work-if-the-key-is-a-salsa-interned.stderr b/salsa-2022-tests/tests/compile-fail/specify-does-not-work-if-the-key-is-a-salsa-interned.stderr index e00f9b92..771ae492 100644 --- a/salsa-2022-tests/tests/compile-fail/specify-does-not-work-if-the-key-is-a-salsa-interned.stderr +++ b/salsa-2022-tests/tests/compile-fail/specify-does-not-work-if-the-key-is-a-salsa-interned.stderr @@ -1,9 +1,9 @@ error[E0277]: the trait bound `MyInterned: TrackedStructInDb` is not satisfied - --> tests/compile-fail/specify-does-not-work-if-the-key-is-a-salsa-interned.rs:21:28 + --> tests/compile-fail/specify-does-not-work-if-the-key-is-a-salsa-interned.rs:22:28 | -20 | #[salsa::tracked(jar = Jar, specify)] +21 | #[salsa::tracked(jar = Jar, specify)] | ------------------------------------- required by a bound introduced by this call -21 | fn tracked_fn(db: &dyn Db, input: MyInterned) -> MyTracked { +22 | fn tracked_fn(db: &dyn Db, input: MyInterned) -> MyTracked { | ^^^^^ the trait `TrackedStructInDb` is not implemented for `MyInterned` | = help: the trait `TrackedStructInDb` is implemented for `MyTracked` diff --git a/salsa-2022-tests/tests/singleton.rs b/salsa-2022-tests/tests/singleton.rs index 03dff331..f850d21b 100644 --- a/salsa-2022-tests/tests/singleton.rs +++ b/salsa-2022-tests/tests/singleton.rs @@ -1,6 +1,6 @@ -//! Basic deletion test: +//! Basic Singleton struct test: //! -//! * entities not created in a revision are deleted, as is any memoized data keyed on them. +//! Singleton structs are created only once. Subsequent `get`s and `new`s after creation return the same `Id`. use salsa_2022_tests::{HasLogger, Logger};