mirror of
https://github.com/salsa-rs/salsa.git
synced 2025-01-23 05:07:27 +00:00
removed AllowedMode trait and added compile-fail tests
This commit is contained in:
parent
3ca70e6b04
commit
25809151dd
13 changed files with 119 additions and 131 deletions
|
@ -40,15 +40,6 @@ impl crate::options::AllowedOptions for Accumulator {
|
||||||
const CONSTRUCTOR_NAME: bool = false;
|
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(
|
fn accumulator_contents(
|
||||||
args: &Args,
|
args: &Args,
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use crate::modes::Mode;
|
|
||||||
use crate::salsa_struct::{SalsaField, SalsaStruct};
|
use crate::salsa_struct::{SalsaField, SalsaStruct};
|
||||||
use proc_macro2::{Literal, TokenStream};
|
use proc_macro2::{Literal, TokenStream};
|
||||||
|
|
||||||
|
@ -11,19 +10,16 @@ pub(crate) fn input(
|
||||||
args: proc_macro::TokenStream,
|
args: proc_macro::TokenStream,
|
||||||
input: proc_macro::TokenStream,
|
input: proc_macro::TokenStream,
|
||||||
) -> proc_macro::TokenStream {
|
) -> proc_macro::TokenStream {
|
||||||
let mode = Mode {
|
match SalsaStruct::new(args, input).and_then(|el| InputStruct(el).generate_input()) {
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
match SalsaStruct::new(args, input, mode).and_then(|el| InputStruct(el).generate_input()) {
|
|
||||||
Ok(s) => s.into(),
|
Ok(s) => s.into(),
|
||||||
Err(err) => err.into_compile_error().into(),
|
Err(err) => err.into_compile_error().into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct InputStruct(SalsaStruct<Self, Self>);
|
struct InputStruct(SalsaStruct<Self>);
|
||||||
|
|
||||||
impl std::ops::Deref for InputStruct {
|
impl std::ops::Deref for InputStruct {
|
||||||
type Target = SalsaStruct<Self, Self>;
|
type Target = SalsaStruct<Self>;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.0
|
&self.0
|
||||||
|
@ -51,15 +47,7 @@ impl crate::options::AllowedOptions for InputStruct {
|
||||||
const CONSTRUCTOR_NAME: bool = true;
|
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 {
|
impl InputStruct {
|
||||||
fn generate_input(&self) -> syn::Result<TokenStream> {
|
fn generate_input(&self) -> syn::Result<TokenStream> {
|
||||||
|
@ -89,14 +77,6 @@ impl InputStruct {
|
||||||
fn validate_input(&self) -> syn::Result<()> {
|
fn validate_input(&self) -> syn::Result<()> {
|
||||||
// check for dissalowed fields
|
// check for dissalowed fields
|
||||||
self.disallow_id_fields("input")?;
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use crate::modes::Mode;
|
|
||||||
use crate::salsa_struct::SalsaStruct;
|
use crate::salsa_struct::SalsaStruct;
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
|
|
||||||
|
@ -14,20 +13,17 @@ pub(crate) fn interned(
|
||||||
args: proc_macro::TokenStream,
|
args: proc_macro::TokenStream,
|
||||||
input: proc_macro::TokenStream,
|
input: proc_macro::TokenStream,
|
||||||
) -> proc_macro::TokenStream {
|
) -> proc_macro::TokenStream {
|
||||||
let mode = Mode {
|
match SalsaStruct::new(args, input).and_then(|el| InternedStruct(el).generate_interned())
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
match SalsaStruct::new(args, input, mode).and_then(|el| InternedStruct(el).generate_interned())
|
|
||||||
{
|
{
|
||||||
Ok(s) => s.into(),
|
Ok(s) => s.into(),
|
||||||
Err(err) => err.into_compile_error().into(),
|
Err(err) => err.into_compile_error().into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct InternedStruct(SalsaStruct<Self, Self>);
|
struct InternedStruct(SalsaStruct<Self>);
|
||||||
|
|
||||||
impl std::ops::Deref for InternedStruct {
|
impl std::ops::Deref for InternedStruct {
|
||||||
type Target = SalsaStruct<Self, Self>;
|
type Target = SalsaStruct<Self>;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.0
|
&self.0
|
||||||
|
@ -56,15 +52,6 @@ impl crate::options::AllowedOptions for InternedStruct {
|
||||||
const CONSTRUCTOR_NAME: bool = true;
|
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 {
|
impl InternedStruct {
|
||||||
fn generate_interned(&self) -> syn::Result<TokenStream> {
|
fn generate_interned(&self) -> syn::Result<TokenStream> {
|
||||||
|
|
|
@ -36,7 +36,6 @@ mod db;
|
||||||
mod input;
|
mod input;
|
||||||
mod interned;
|
mod interned;
|
||||||
mod jar;
|
mod jar;
|
||||||
mod modes;
|
|
||||||
mod options;
|
mod options;
|
||||||
mod salsa_struct;
|
mod salsa_struct;
|
||||||
mod tracked;
|
mod tracked;
|
||||||
|
|
|
@ -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<M: AllowedModes> {
|
|
||||||
pub(super) phantom: PhantomData<M>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<M: AllowedModes> Default for Mode<M> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
phantom: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<M: AllowedModes> Mode<M> {
|
|
||||||
pub(crate) fn singleton_allowed(&self) -> bool {
|
|
||||||
M::INPUT
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,12 +2,13 @@ use std::marker::PhantomData;
|
||||||
|
|
||||||
use syn::{ext::IdentExt, spanned::Spanned};
|
use syn::{ext::IdentExt, spanned::Spanned};
|
||||||
|
|
||||||
|
|
||||||
/// "Options" are flags that can be supplied to the various salsa related
|
/// "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
|
/// macros. They are listed like `(ref, no_eq, foo=bar)` etc. The commas
|
||||||
/// are required and trailing commas are permitted. The options accepted
|
/// are required and trailing commas are permitted. The options accepted
|
||||||
/// for any particular location are configured via the `AllowedOptions`
|
/// for any particular location are configured via the `AllowedOptions`
|
||||||
/// trait.
|
/// trait.
|
||||||
pub(crate) struct Options<A: AllowedOptions> {
|
pub(crate) struct Options<A: AllowedOptions > {
|
||||||
/// The `return_ref` option is used to signal that field/return type is "by ref"
|
/// 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.
|
/// If this is `Some`, the value is the `ref` identifier.
|
||||||
|
@ -116,7 +117,7 @@ impl<A: AllowedOptions> Options<A> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: AllowedOptions> syn::parse::Parse for Options<A> {
|
impl<A: AllowedOptions > syn::parse::Parse for Options<A> {
|
||||||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||||
let mut options = Options::default();
|
let mut options = Options::default();
|
||||||
|
|
||||||
|
|
|
@ -25,46 +25,39 @@
|
||||||
//! * data method `impl Foo { fn data(&self, db: &dyn crate::Db) -> FooData { FooData { f: self.f(db), ... } } }`
|
//! * 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
|
//! * this could be optimized, particularly for interned fields
|
||||||
|
|
||||||
use crate::modes::Mode;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
configuration,
|
configuration,
|
||||||
modes::AllowedModes,
|
|
||||||
options::{AllowedOptions, Options},
|
options::{AllowedOptions, Options},
|
||||||
};
|
};
|
||||||
use heck::ToUpperCamelCase;
|
use heck::ToUpperCamelCase;
|
||||||
use proc_macro2::{Ident, Literal, Span, TokenStream};
|
use proc_macro2::{Ident, Literal, Span, TokenStream};
|
||||||
use syn::spanned::Spanned;
|
use syn::spanned::Spanned;
|
||||||
|
|
||||||
pub(crate) struct SalsaStruct<A: AllowedOptions, M: AllowedModes> {
|
pub(crate) struct SalsaStruct<A: AllowedOptions> {
|
||||||
args: Options<A>,
|
args: Options<A>,
|
||||||
_mode: Mode<M>,
|
|
||||||
struct_item: syn::ItemStruct,
|
struct_item: syn::ItemStruct,
|
||||||
fields: Vec<SalsaField>,
|
fields: Vec<SalsaField>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const BANNED_FIELD_NAMES: &[&str] = &["from", "new"];
|
const BANNED_FIELD_NAMES: &[&str] = &["from", "new"];
|
||||||
|
|
||||||
impl<A: AllowedOptions, M: AllowedModes> SalsaStruct<A, M> {
|
impl<A: AllowedOptions> SalsaStruct<A> {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
args: proc_macro::TokenStream,
|
args: proc_macro::TokenStream,
|
||||||
input: proc_macro::TokenStream,
|
input: proc_macro::TokenStream,
|
||||||
mode: Mode<M>,
|
|
||||||
) -> syn::Result<Self> {
|
) -> syn::Result<Self> {
|
||||||
let struct_item = syn::parse(input)?;
|
let struct_item = syn::parse(input)?;
|
||||||
Self::with_struct(args, struct_item, mode)
|
Self::with_struct(args, struct_item)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn with_struct(
|
pub(crate) fn with_struct(
|
||||||
args: proc_macro::TokenStream,
|
args: proc_macro::TokenStream,
|
||||||
struct_item: syn::ItemStruct,
|
struct_item: syn::ItemStruct,
|
||||||
mode: Mode<M>,
|
|
||||||
) -> syn::Result<Self> {
|
) -> syn::Result<Self> {
|
||||||
let args: Options<A> = syn::parse(args)?;
|
let args: Options<A> = syn::parse(args)?;
|
||||||
let fields = Self::extract_options(&struct_item)?;
|
let fields = Self::extract_options(&struct_item)?;
|
||||||
check_singleton(&mode, args.singleton.as_ref(), struct_item.span())?;
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
args,
|
args,
|
||||||
_mode: mode,
|
|
||||||
struct_item,
|
struct_item,
|
||||||
fields,
|
fields,
|
||||||
})
|
})
|
||||||
|
@ -133,13 +126,6 @@ impl<A: AllowedOptions, M: AllowedModes> SalsaStruct<A, M> {
|
||||||
self.args.singleton.is_some()
|
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 {
|
pub(crate) fn db_dyn_ty(&self) -> syn::Type {
|
||||||
let jar_ty = self.jar_ty();
|
let jar_ty = self.jar_ty();
|
||||||
|
@ -450,17 +436,3 @@ impl SalsaField {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn check_singleton<M: AllowedModes>(
|
|
||||||
mode: &Mode<M>,
|
|
||||||
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(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use proc_macro2::{Literal, TokenStream};
|
use proc_macro2::{Literal, TokenStream};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
modes::Mode,
|
|
||||||
salsa_struct::{SalsaField, SalsaStruct},
|
salsa_struct::{SalsaField, SalsaStruct},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -14,10 +13,7 @@ pub(crate) fn tracked(
|
||||||
args: proc_macro::TokenStream,
|
args: proc_macro::TokenStream,
|
||||||
struct_item: syn::ItemStruct,
|
struct_item: syn::ItemStruct,
|
||||||
) -> proc_macro::TokenStream {
|
) -> proc_macro::TokenStream {
|
||||||
let mode = Mode {
|
match SalsaStruct::with_struct(args, struct_item)
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
match SalsaStruct::with_struct(args, struct_item, mode)
|
|
||||||
.and_then(|el| TrackedStruct(el).generate_tracked())
|
.and_then(|el| TrackedStruct(el).generate_tracked())
|
||||||
{
|
{
|
||||||
Ok(s) => s.into(),
|
Ok(s) => s.into(),
|
||||||
|
@ -25,10 +21,10 @@ pub(crate) fn tracked(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TrackedStruct(SalsaStruct<Self, Self>);
|
struct TrackedStruct(SalsaStruct<Self>);
|
||||||
|
|
||||||
impl std::ops::Deref for TrackedStruct {
|
impl std::ops::Deref for TrackedStruct {
|
||||||
type Target = SalsaStruct<Self, Self>;
|
type Target = SalsaStruct<Self>;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.0
|
&self.0
|
||||||
|
@ -57,15 +53,7 @@ impl crate::options::AllowedOptions for TrackedStruct {
|
||||||
const CONSTRUCTOR_NAME: bool = true;
|
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 {
|
impl TrackedStruct {
|
||||||
fn generate_tracked(&self) -> syn::Result<TokenStream> {
|
fn generate_tracked(&self) -> syn::Result<TokenStream> {
|
||||||
|
|
|
@ -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<Jar> + 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<MyTracked> {
|
||||||
|
(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<Self>,
|
||||||
|
logger: Logger,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl salsa::Database for Database {}
|
||||||
|
|
||||||
|
impl Db for Database {}
|
||||||
|
|
||||||
|
impl HasLogger for Database {
|
||||||
|
fn logger(&self) -> &Logger {
|
||||||
|
&self.logger
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -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
|
|
@ -17,6 +17,7 @@ struct MyTracked {
|
||||||
field: u32,
|
field: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[salsa::tracked(jar = Jar, specify)]
|
#[salsa::tracked(jar = Jar, specify)]
|
||||||
fn tracked_fn(db: &dyn Db, input: MyInterned) -> MyTracked {
|
fn tracked_fn(db: &dyn Db, input: MyInterned) -> MyTracked {
|
||||||
MyTracked::new(db, input.field(db) * 2)
|
MyTracked::new(db, input.field(db) * 2)
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
error[E0277]: the trait bound `MyInterned: TrackedStructInDb<dyn Db>` is not satisfied
|
error[E0277]: the trait bound `MyInterned: TrackedStructInDb<dyn Db>` 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
|
| ------------------------------------- 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<dyn Db>` is not implemented for `MyInterned`
|
| ^^^^^ the trait `TrackedStructInDb<dyn Db>` is not implemented for `MyInterned`
|
||||||
|
|
|
|
||||||
= help: the trait `TrackedStructInDb<DB>` is implemented for `MyTracked`
|
= help: the trait `TrackedStructInDb<DB>` is implemented for `MyTracked`
|
||||||
|
|
|
@ -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};
|
use salsa_2022_tests::{HasLogger, Logger};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue