mirror of
https://github.com/salsa-rs/salsa.git
synced 2025-01-13 16:58:52 +00:00
wip
This commit is contained in:
parent
612cec6703
commit
8a39bf029b
40 changed files with 194 additions and 378 deletions
|
@ -304,7 +304,7 @@ impl Macro {
|
|||
|
||||
fn cycle_recovery(&self) -> (TokenStream, TokenStream) {
|
||||
if let Some(recovery_fn) = &self.args.recovery_fn {
|
||||
(recovery_fn.to_token_stream(), quote!(Fallback))
|
||||
(quote!((#recovery_fn)), quote!(Fallback))
|
||||
} else {
|
||||
(
|
||||
quote!((salsa::plumbing::unexpected_cycle_recovery!)),
|
||||
|
|
|
@ -33,6 +33,14 @@ pub trait Database: DatabaseGen {
|
|||
fn report_untracked_read(&self) {
|
||||
self.runtime().report_untracked_read();
|
||||
}
|
||||
|
||||
/// Execute `op` with the database in thread-local storage for debug print-outs.
|
||||
fn attach<R>(&self, op: impl FnOnce(&Self) -> R) -> R
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
attach_database(self, || op(self))
|
||||
}
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
|
|
|
@ -6,6 +6,7 @@ mod common;
|
|||
use common::{HasLogger, Logger};
|
||||
|
||||
use expect_test::expect;
|
||||
use salsa::{Accumulator, Setter};
|
||||
use test_log::test;
|
||||
|
||||
#[salsa::db]
|
||||
|
@ -18,6 +19,7 @@ struct List {
|
|||
}
|
||||
|
||||
#[salsa::accumulator]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct Integers(u32);
|
||||
|
||||
#[salsa::tracked]
|
||||
|
@ -31,13 +33,13 @@ fn compute(db: &dyn Db, input: List) {
|
|||
let result = if let Some(next) = input.next(db) {
|
||||
let next_integers = compute::accumulated::<Integers>(db, next);
|
||||
eprintln!("{:?}", next_integers);
|
||||
let v = input.value(db) + next_integers.iter().sum::<u32>();
|
||||
let v = input.value(db) + next_integers.iter().map(|a| a.0).sum::<u32>();
|
||||
eprintln!("input={:?} v={:?}", input.value(db), v);
|
||||
v
|
||||
} else {
|
||||
input.value(db)
|
||||
};
|
||||
Integers::push(db, result);
|
||||
Integers(result).accumulate(db);
|
||||
eprintln!("pushed result {:?}", result);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,12 +6,11 @@ mod common;
|
|||
use common::{HasLogger, Logger};
|
||||
|
||||
use expect_test::expect;
|
||||
use salsa::{Accumulator, Setter};
|
||||
use test_log::test;
|
||||
|
||||
#[salsa::jar(db = Db)]
|
||||
struct Jar(List, Integers, compute, accumulated);
|
||||
|
||||
trait Db: salsa::DbWithJar<Jar> + HasLogger {}
|
||||
#[salsa::db]
|
||||
trait Db: salsa::Database + HasLogger {}
|
||||
|
||||
#[salsa::input]
|
||||
struct List {
|
||||
|
@ -20,6 +19,7 @@ struct List {
|
|||
}
|
||||
|
||||
#[salsa::accumulator]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct Integers(u32);
|
||||
|
||||
#[salsa::tracked]
|
||||
|
@ -27,7 +27,7 @@ fn compute(db: &dyn Db, input: List) -> u32 {
|
|||
db.push_log(format!("compute({:?})", input,));
|
||||
|
||||
// always pushes 0
|
||||
Integers::push(db, 0);
|
||||
Integers(0).accumulate(db);
|
||||
|
||||
let result = if let Some(next) = input.next(db) {
|
||||
let next_integers = accumulated(db, next);
|
||||
|
@ -45,19 +45,24 @@ fn compute(db: &dyn Db, input: List) -> u32 {
|
|||
fn accumulated(db: &dyn Db, input: List) -> Vec<u32> {
|
||||
db.push_log(format!("accumulated({:?})", input,));
|
||||
compute::accumulated::<Integers>(db, input)
|
||||
.into_iter()
|
||||
.map(|a| a.0)
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[salsa::db(Jar)]
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
logger: Logger,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {
|
||||
fn salsa_event(&self, _event: salsa::Event) {}
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl Db for Database {}
|
||||
|
||||
impl HasLogger for Database {
|
||||
|
|
|
@ -79,7 +79,7 @@ fn test1() {
|
|||
|
||||
// When we mutate `l1`, we should re-execute `compute` for `l1`,
|
||||
// but we should not have to re-execute `compute` for `l2`.
|
||||
// The only inpout for `compute(l1)` is the accumulated values from `l1`,
|
||||
// The only input for `compute(l1)` is the accumulated values from `l1`,
|
||||
// which have not changed.
|
||||
l1.set_value(&mut db).to(2);
|
||||
assert_eq!(compute(&db, l2), 2);
|
||||
|
|
|
@ -6,12 +6,11 @@ mod common;
|
|||
use common::{HasLogger, Logger};
|
||||
|
||||
use expect_test::expect;
|
||||
use salsa::{Accumulator, Setter};
|
||||
use test_log::test;
|
||||
|
||||
#[salsa::jar(db = Db)]
|
||||
struct Jar(MyInput, Logs, push_logs, push_a_logs, push_b_logs);
|
||||
|
||||
trait Db: salsa::DbWithJar<Jar> + HasLogger {}
|
||||
#[salsa::db]
|
||||
trait Db: salsa::Database + HasLogger {}
|
||||
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
|
@ -20,6 +19,7 @@ struct MyInput {
|
|||
}
|
||||
|
||||
#[salsa::accumulator]
|
||||
#[derive(Clone, Debug)]
|
||||
struct Logs(String);
|
||||
|
||||
#[salsa::tracked]
|
||||
|
@ -48,7 +48,7 @@ fn push_a_logs(db: &dyn Db, input: MyInput) {
|
|||
db.push_log(format!("push_a_logs({})", field_a));
|
||||
|
||||
for i in 0..field_a {
|
||||
Logs::push(db, format!("log_a({} of {})", i, field_a));
|
||||
Logs(format!("log_a({} of {})", i, field_a)).accumulate(db);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,21 +58,23 @@ fn push_b_logs(db: &dyn Db, input: MyInput) {
|
|||
db.push_log(format!("push_b_logs({})", field_a));
|
||||
|
||||
for i in 0..field_a {
|
||||
Logs::push(db, format!("log_b({} of {})", i, field_a));
|
||||
Logs(format!("log_b({} of {})", i, field_a)).accumulate(db);
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::db(Jar)]
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
logger: Logger,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {
|
||||
fn salsa_event(&self, _event: salsa::Event) {}
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl Db for Database {}
|
||||
|
||||
impl HasLogger for Database {
|
||||
|
|
|
@ -4,12 +4,12 @@ struct Jar(AccTwoUnnamedFields, AccNamedField);
|
|||
trait Db: salsa::DbWithJar<Jar> {}
|
||||
|
||||
// accumulator with more than one unnamed fields
|
||||
#[salsa::accumulator(jar = Jar)]
|
||||
#[salsa::accumulator]
|
||||
struct AccTwoUnnamedFields (u32, u32);
|
||||
|
||||
|
||||
// accumulator with named fields
|
||||
#[salsa::accumulator(jar = Jar)]
|
||||
#[salsa::accumulator]
|
||||
struct AccNamedField {
|
||||
field: u32,
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ pub struct Jar(a::MyInput);
|
|||
mod a {
|
||||
use crate::Jar;
|
||||
|
||||
#[salsa::input(jar = Jar)]
|
||||
#[salsa::input]
|
||||
pub struct MyInput {
|
||||
field: u32,
|
||||
}
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
|
||||
#[salsa::jar(db = Db)]
|
||||
struct Jar(MyInput);
|
||||
|
||||
trait Db: salsa::DbWithJar<Jar> {}
|
||||
|
||||
#[salsa::input(jar = Jar)]
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
field: u32,
|
||||
#[id]
|
||||
|
@ -21,11 +20,10 @@ impl salsa::Database for Database {}
|
|||
|
||||
impl Db for Database {}
|
||||
|
||||
|
||||
fn main() {
|
||||
let mut db = Database::default();
|
||||
let input = MyInput::new(&mut db, 3, 4);
|
||||
// should not compile as `id_one` should not have a setter
|
||||
// compile error: method `set_id_one` not found in scope
|
||||
input.set_id_one(1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ struct Jar(MyInput, lru_can_not_be_used_with_specify);
|
|||
|
||||
trait Db: salsa::DbWithJar<Jar> {}
|
||||
|
||||
#[salsa::input(jar = Jar)]
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
field: u32,
|
||||
}
|
||||
|
|
|
@ -5,17 +5,17 @@ struct Jar(MyInput, MyTracked<'_>, tracked_fn);
|
|||
|
||||
trait Db: salsa::DbWithJar<Jar> {}
|
||||
|
||||
#[salsa::input(jar = Jar)]
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
field: u32,
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
struct MyTracked<'db> {
|
||||
field: u32,
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
fn tracked_fn<'db>(db: &'db dyn Db, input: MyInput) -> MyTracked<'db> {
|
||||
MyTracked::new(db, input.field(db) / 2)
|
||||
}
|
||||
|
|
|
@ -7,12 +7,12 @@ struct Jar(MyInput, MyTracked<'_>, tracked_fn);
|
|||
|
||||
trait Db: salsa::DbWithJar<Jar> {}
|
||||
|
||||
#[salsa::input(jar = Jar)]
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
field: u32,
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
struct MyTracked<'db> {
|
||||
field: u32,
|
||||
}
|
||||
|
|
|
@ -7,12 +7,12 @@ struct Jar(MyInterned<'_>, MyTracked<'_>, tracked_fn);
|
|||
|
||||
trait Db: salsa::DbWithJar<Jar> {}
|
||||
|
||||
#[salsa::interned(jar = Jar)]
|
||||
#[salsa::interned]
|
||||
struct MyInterned<'db> {
|
||||
field: u32,
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
struct MyTracked<'db> {
|
||||
field: u32,
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ struct Jar(
|
|||
|
||||
trait Db: salsa::DbWithJar<Jar> {}
|
||||
|
||||
#[salsa::input(jar = Jar)]
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
field: u32,
|
||||
}
|
||||
|
@ -31,10 +31,10 @@ fn tracked_fn_with_constructor(db: &dyn Db, input: MyInput) -> u32 {
|
|||
input.field(db) * 2
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
fn tracked_fn_with_one_input(db: &dyn Db) -> u32 {}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
fn tracked_fn_with_receiver_not_applied_to_impl_block(&self, db: &dyn Db) -> u32 {}
|
||||
|
||||
#[salsa::tracked(jar = Jar, specify)]
|
||||
|
|
|
@ -46,7 +46,7 @@ error[E0412]: cannot find type `tracked_fn_with_constructor` in this scope
|
|||
6 | tracked_fn_with_constructor,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: a struct with a similar name exists: `tracked_fn_with_one_input`
|
||||
...
|
||||
34 | #[salsa::tracked(jar = Jar)]
|
||||
34 | #[salsa::tracked]
|
||||
| ---------------------------- similarly named struct `tracked_fn_with_one_input` defined here
|
||||
|
||||
error[E0412]: cannot find type `tracked_fn_with_receiver_not_applied_to_impl_block` in this scope
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#[salsa::jar(db = Db)]
|
||||
struct Jar(Tracked<'_>);
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
struct Tracked<'db> {
|
||||
field: u32,
|
||||
}
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
//! Tests that we can create a database of only 0-size jars without invoking UB
|
||||
|
||||
use salsa::storage::HasJars;
|
||||
|
||||
#[salsa::jar(db = Db)]
|
||||
struct Jar();
|
||||
|
||||
trait Db: salsa::DbWithJar<Jar> {}
|
||||
|
||||
#[salsa::db(Jar)]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
}
|
||||
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
impl Db for Database {}
|
||||
|
||||
#[test]
|
||||
fn execute() {
|
||||
let db = Database::default();
|
||||
let jars = db.storage.jars().0;
|
||||
|
||||
ensure_init(jars);
|
||||
}
|
||||
|
||||
fn ensure_init(place: *const <Database as HasJars>::Jars) {
|
||||
use std::mem::forget;
|
||||
use std::ptr::addr_of;
|
||||
|
||||
// SAFETY: Intentionally tries to access potentially uninitialized memory,
|
||||
// so that miri can catch if we accidentally forget to initialize the memory.
|
||||
#[allow(clippy::forget_non_drop)]
|
||||
forget(unsafe { addr_of!((*place).0).read() });
|
||||
}
|
|
@ -1,154 +0,0 @@
|
|||
//! Tests that we can create a database with very large jars without invoking UB
|
||||
|
||||
use salsa::storage::HasJars;
|
||||
|
||||
#[salsa::db(jar1::Jar1, jar2::Jar2, jar3::Jar3, jar4::Jar4)]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
}
|
||||
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
#[test]
|
||||
fn execute() {
|
||||
let db = Database::default();
|
||||
let jars = db.storage.jars().0;
|
||||
|
||||
ensure_init(jars);
|
||||
}
|
||||
|
||||
fn ensure_init(place: *const <Database as HasJars>::Jars) {
|
||||
use std::mem::forget;
|
||||
use std::ptr::addr_of;
|
||||
|
||||
// SAFETY: Intentionally tries to access potentially uninitialized memory,
|
||||
// so that miri can catch if we accidentally forget to initialize the memory.
|
||||
forget(unsafe { addr_of!((*place).0).read() });
|
||||
forget(unsafe { addr_of!((*place).1).read() });
|
||||
forget(unsafe { addr_of!((*place).2).read() });
|
||||
forget(unsafe { addr_of!((*place).3).read() });
|
||||
}
|
||||
|
||||
macro_rules! make_jarX {
|
||||
($jarX:ident, $JarX:ident) => {
|
||||
mod $jarX {
|
||||
#[salsa::jar(db = Db)]
|
||||
pub(crate) struct $JarX(T1<'_>);
|
||||
|
||||
pub(crate) trait Db: salsa::DbWithJar<$JarX> {}
|
||||
|
||||
impl<DB> Db for DB where DB: salsa::DbWithJar<$JarX> {}
|
||||
|
||||
#[salsa::tracked(jar = $JarX)]
|
||||
struct T1<'db> {
|
||||
a0: String,
|
||||
a1: String,
|
||||
a2: String,
|
||||
a3: String,
|
||||
a4: String,
|
||||
a5: String,
|
||||
a6: String,
|
||||
a7: String,
|
||||
a8: String,
|
||||
a9: String,
|
||||
a10: String,
|
||||
a11: String,
|
||||
a12: String,
|
||||
a13: String,
|
||||
a14: String,
|
||||
a15: String,
|
||||
a16: String,
|
||||
a17: String,
|
||||
a18: String,
|
||||
a19: String,
|
||||
a20: String,
|
||||
a21: String,
|
||||
a22: String,
|
||||
a23: String,
|
||||
a24: String,
|
||||
a25: String,
|
||||
a26: String,
|
||||
a27: String,
|
||||
a28: String,
|
||||
a29: String,
|
||||
a30: String,
|
||||
a31: String,
|
||||
a32: String,
|
||||
a33: String,
|
||||
a34: String,
|
||||
a35: String,
|
||||
a36: String,
|
||||
a37: String,
|
||||
a38: String,
|
||||
a39: String,
|
||||
a40: String,
|
||||
a41: String,
|
||||
a42: String,
|
||||
a43: String,
|
||||
a44: String,
|
||||
a45: String,
|
||||
a46: String,
|
||||
a47: String,
|
||||
a48: String,
|
||||
a49: String,
|
||||
a50: String,
|
||||
a51: String,
|
||||
a52: String,
|
||||
a53: String,
|
||||
a54: String,
|
||||
a55: String,
|
||||
a56: String,
|
||||
a57: String,
|
||||
a58: String,
|
||||
a59: String,
|
||||
a60: String,
|
||||
a61: String,
|
||||
a62: String,
|
||||
a63: String,
|
||||
a64: String,
|
||||
a65: String,
|
||||
a66: String,
|
||||
a67: String,
|
||||
a68: String,
|
||||
a69: String,
|
||||
a70: String,
|
||||
a71: String,
|
||||
a72: String,
|
||||
a73: String,
|
||||
a74: String,
|
||||
a75: String,
|
||||
a76: String,
|
||||
a77: String,
|
||||
a78: String,
|
||||
a79: String,
|
||||
a80: String,
|
||||
a81: String,
|
||||
a82: String,
|
||||
a83: String,
|
||||
a84: String,
|
||||
a85: String,
|
||||
a86: String,
|
||||
a87: String,
|
||||
a88: String,
|
||||
a89: String,
|
||||
a90: String,
|
||||
a91: String,
|
||||
a92: String,
|
||||
a93: String,
|
||||
a94: String,
|
||||
a95: String,
|
||||
a96: String,
|
||||
a97: String,
|
||||
a98: String,
|
||||
a99: String,
|
||||
a100: String,
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
make_jarX!(jar1, Jar1);
|
||||
make_jarX!(jar2, Jar2);
|
||||
make_jarX!(jar3, Jar3);
|
||||
make_jarX!(jar4, Jar4);
|
191
tests/cycles.rs
191
tests/cycles.rs
|
@ -56,53 +56,40 @@ struct Error {
|
|||
cycle: Vec<String>,
|
||||
}
|
||||
|
||||
#[salsa::jar(db = Db)]
|
||||
struct Jar(
|
||||
MyInput,
|
||||
memoized_a,
|
||||
memoized_b,
|
||||
volatile_a,
|
||||
volatile_b,
|
||||
ABC,
|
||||
cycle_a,
|
||||
cycle_b,
|
||||
cycle_c,
|
||||
);
|
||||
use salsa::Database as Db;
|
||||
use salsa::Setter;
|
||||
|
||||
trait Db: salsa::DbWithJar<Jar> {}
|
||||
|
||||
#[salsa::db(Jar)]
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
}
|
||||
|
||||
impl Db for Database {}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
impl RefUnwindSafe for Database {}
|
||||
|
||||
#[salsa::input(jar = Jar)]
|
||||
#[salsa::input]
|
||||
struct MyInput {}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
fn memoized_a(db: &dyn Db, input: MyInput) {
|
||||
memoized_b(db, input)
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
fn memoized_b(db: &dyn Db, input: MyInput) {
|
||||
memoized_a(db, input)
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
fn volatile_a(db: &dyn Db, input: MyInput) {
|
||||
db.report_untracked_read();
|
||||
volatile_b(db, input)
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
fn volatile_b(db: &dyn Db, input: MyInput) {
|
||||
db.report_untracked_read();
|
||||
volatile_a(db, input)
|
||||
|
@ -120,7 +107,7 @@ enum CycleQuery {
|
|||
AthenC,
|
||||
}
|
||||
|
||||
#[salsa::input(jar = Jar)]
|
||||
#[salsa::input]
|
||||
struct ABC {
|
||||
a: CycleQuery,
|
||||
b: CycleQuery,
|
||||
|
@ -142,29 +129,29 @@ impl CycleQuery {
|
|||
}
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar, recovery_fn=recover_a)]
|
||||
#[salsa::tracked(recovery_fn=recover_a)]
|
||||
fn cycle_a(db: &dyn Db, abc: ABC) -> Result<(), Error> {
|
||||
abc.a(db).invoke(db, abc)
|
||||
}
|
||||
|
||||
fn recover_a(db: &dyn Db, cycle: &salsa::Cycle, abc: ABC) -> Result<(), Error> {
|
||||
Err(Error {
|
||||
cycle: cycle.all_participants(db),
|
||||
cycle: cycle.participant_keys().map(|k| format!("{k:?}")).collect(),
|
||||
})
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar, recovery_fn=recover_b)]
|
||||
#[salsa::tracked(recovery_fn=recover_b)]
|
||||
fn cycle_b(db: &dyn Db, abc: ABC) -> Result<(), Error> {
|
||||
abc.b(db).invoke(db, abc)
|
||||
}
|
||||
|
||||
fn recover_b(db: &dyn Db, cycle: &salsa::Cycle, abc: ABC) -> Result<(), Error> {
|
||||
Err(Error {
|
||||
cycle: cycle.all_participants(db),
|
||||
cycle: cycle.participant_keys().map(|k| format!("{k:?}")).collect(),
|
||||
})
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
fn cycle_c(db: &dyn Db, abc: ABC) -> Result<(), Error> {
|
||||
abc.c(db).invoke(db, abc)
|
||||
}
|
||||
|
@ -182,30 +169,32 @@ fn extract_cycle(f: impl FnOnce() + UnwindSafe) -> salsa::Cycle {
|
|||
|
||||
#[test]
|
||||
fn cycle_memoized() {
|
||||
let mut db = Database::default();
|
||||
let input = MyInput::new(&db);
|
||||
let cycle = extract_cycle(|| memoized_a(&db, input));
|
||||
let expected = expect![[r#"
|
||||
[
|
||||
"memoized_a(0)",
|
||||
"memoized_b(0)",
|
||||
]
|
||||
"#]];
|
||||
expected.assert_debug_eq(&cycle.all_participants(&db));
|
||||
Database::default().attach(|db| {
|
||||
let input = MyInput::new(db);
|
||||
let cycle = extract_cycle(|| memoized_a(db, input));
|
||||
let expected = expect![[r#"
|
||||
[
|
||||
memoized_a(0),
|
||||
memoized_b(0),
|
||||
]
|
||||
"#]];
|
||||
expected.assert_debug_eq(&cycle.all_participants(db));
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cycle_volatile() {
|
||||
let mut db = Database::default();
|
||||
let input = MyInput::new(&db);
|
||||
let cycle = extract_cycle(|| volatile_a(&db, input));
|
||||
let expected = expect![[r#"
|
||||
[
|
||||
"volatile_a(0)",
|
||||
"volatile_b(0)",
|
||||
]
|
||||
"#]];
|
||||
expected.assert_debug_eq(&cycle.all_participants(&db));
|
||||
Database::default().attach(|db| {
|
||||
let input = MyInput::new(db);
|
||||
let cycle = extract_cycle(|| volatile_a(db, input));
|
||||
let expected = expect![[r#"
|
||||
[
|
||||
volatile_a(0),
|
||||
volatile_b(0),
|
||||
]
|
||||
"#]];
|
||||
expected.assert_debug_eq(&cycle.all_participants(db));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -214,9 +203,10 @@ fn expect_cycle() {
|
|||
// ^ |
|
||||
// +-----+
|
||||
|
||||
let mut db = Database::default();
|
||||
let abc = ABC::new(&db, CycleQuery::B, CycleQuery::A, CycleQuery::None);
|
||||
assert!(cycle_a(&db, abc).is_err());
|
||||
Database::default().attach(|db| {
|
||||
let abc = ABC::new(db, CycleQuery::B, CycleQuery::A, CycleQuery::None);
|
||||
assert!(cycle_a(db, abc).is_err());
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -224,17 +214,18 @@ fn inner_cycle() {
|
|||
// A --> B <-- C
|
||||
// ^ |
|
||||
// +-----+
|
||||
let mut db = Database::default();
|
||||
let abc = ABC::new(&db, CycleQuery::B, CycleQuery::A, CycleQuery::B);
|
||||
let err = cycle_c(&db, abc);
|
||||
assert!(err.is_err());
|
||||
let expected = expect![[r#"
|
||||
[
|
||||
"cycle_a(0)",
|
||||
"cycle_b(0)",
|
||||
]
|
||||
"#]];
|
||||
expected.assert_debug_eq(&err.unwrap_err().cycle);
|
||||
Database::default().attach(|db| {
|
||||
let abc = ABC::new(db, CycleQuery::B, CycleQuery::A, CycleQuery::B);
|
||||
let err = cycle_c(db, abc);
|
||||
assert!(err.is_err());
|
||||
let expected = expect![[r#"
|
||||
[
|
||||
"cycle_b(0)",
|
||||
"cycle_a(0)",
|
||||
]
|
||||
"#]];
|
||||
expected.assert_debug_eq(&err.unwrap_err().cycle);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -329,40 +320,40 @@ fn cycle_disappears_durability() {
|
|||
|
||||
#[test]
|
||||
fn cycle_mixed_1() {
|
||||
let mut db = Database::default();
|
||||
Database::default().attach(|db| {
|
||||
// A --> B <-- C
|
||||
// | ^
|
||||
// +-----+
|
||||
let abc = ABC::new(db, CycleQuery::B, CycleQuery::C, CycleQuery::B);
|
||||
|
||||
// A --> B <-- C
|
||||
// | ^
|
||||
// +-----+
|
||||
let abc = ABC::new(&db, CycleQuery::B, CycleQuery::C, CycleQuery::B);
|
||||
|
||||
let expected = expect![[r#"
|
||||
[
|
||||
"cycle_b(0)",
|
||||
"cycle_c(0)",
|
||||
]
|
||||
"#]];
|
||||
expected.assert_debug_eq(&cycle_c(&db, abc).unwrap_err().cycle);
|
||||
let expected = expect![[r#"
|
||||
[
|
||||
"cycle_c(0)",
|
||||
"cycle_b(0)",
|
||||
]
|
||||
"#]];
|
||||
expected.assert_debug_eq(&cycle_c(db, abc).unwrap_err().cycle);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cycle_mixed_2() {
|
||||
let mut db = Database::default();
|
||||
|
||||
// Configuration:
|
||||
//
|
||||
// A --> B --> C
|
||||
// ^ |
|
||||
// +-----------+
|
||||
let abc = ABC::new(&db, CycleQuery::B, CycleQuery::C, CycleQuery::A);
|
||||
let expected = expect![[r#"
|
||||
Database::default().attach(|db| {
|
||||
// Configuration:
|
||||
//
|
||||
// A --> B --> C
|
||||
// ^ |
|
||||
// +-----------+
|
||||
let abc = ABC::new(db, CycleQuery::B, CycleQuery::C, CycleQuery::A);
|
||||
let expected = expect![[r#"
|
||||
[
|
||||
"cycle_a(0)",
|
||||
"cycle_b(0)",
|
||||
"cycle_c(0)",
|
||||
]
|
||||
"#]];
|
||||
expected.assert_debug_eq(&cycle_a(&db, abc).unwrap_err().cycle);
|
||||
expected.assert_debug_eq(&cycle_a(db, abc).unwrap_err().cycle);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -388,8 +379,8 @@ fn cycle_deterministic_order() {
|
|||
"cycle_b(0)",
|
||||
],
|
||||
[
|
||||
"cycle_a(0)",
|
||||
"cycle_b(0)",
|
||||
"cycle_a(0)",
|
||||
],
|
||||
)
|
||||
"#]];
|
||||
|
@ -441,19 +432,19 @@ fn cycle_multiple() {
|
|||
|
||||
#[test]
|
||||
fn cycle_recovery_set_but_not_participating() {
|
||||
let mut db = Database::default();
|
||||
Database::default().attach(|db| {
|
||||
// A --> C -+
|
||||
// ^ |
|
||||
// +--+
|
||||
let abc = ABC::new(db, CycleQuery::C, CycleQuery::None, CycleQuery::C);
|
||||
|
||||
// A --> C -+
|
||||
// ^ |
|
||||
// +--+
|
||||
let abc = ABC::new(&db, CycleQuery::C, CycleQuery::None, CycleQuery::C);
|
||||
|
||||
// Here we expect C to panic and A not to recover:
|
||||
let r = extract_cycle(|| drop(cycle_a(&db, abc)));
|
||||
let expected = expect![[r#"
|
||||
[
|
||||
"cycle_c(0)",
|
||||
]
|
||||
"#]];
|
||||
expected.assert_debug_eq(&r.all_participants(&db));
|
||||
// Here we expect C to panic and A not to recover:
|
||||
let r = extract_cycle(|| drop(cycle_a(db, abc)));
|
||||
let expected = expect![[r#"
|
||||
[
|
||||
cycle_c(0),
|
||||
]
|
||||
"#]];
|
||||
expected.assert_debug_eq(&r.all_participants(db));
|
||||
})
|
||||
}
|
||||
|
|
|
@ -19,30 +19,30 @@ struct Jar(
|
|||
|
||||
trait Db: salsa::DbWithJar<Jar> + HasLogger {}
|
||||
|
||||
#[salsa::input(jar = Jar)]
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
field: u32,
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
fn final_result_depends_on_x(db: &dyn Db, input: MyInput) -> u32 {
|
||||
db.push_log(format!("final_result_depends_on_x({:?})", input));
|
||||
intermediate_result(db, input).x(db) * 2
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
fn final_result_depends_on_y(db: &dyn Db, input: MyInput) -> u32 {
|
||||
db.push_log(format!("final_result_depends_on_y({:?})", input));
|
||||
intermediate_result(db, input).y(db) * 2
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
struct MyTracked<'db> {
|
||||
x: u32,
|
||||
y: u32,
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
fn intermediate_result<'db>(db: &'db dyn Db, input: MyInput) -> MyTracked<'db> {
|
||||
MyTracked::new(db, (input.field(db) + 1) / 2, input.field(db) / 2)
|
||||
}
|
||||
|
|
|
@ -13,19 +13,19 @@ struct Jar(MyInput, result_depends_on_x, result_depends_on_y);
|
|||
|
||||
trait Db: salsa::DbWithJar<Jar> + HasLogger {}
|
||||
|
||||
#[salsa::input(jar = Jar)]
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
x: u32,
|
||||
y: u32,
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
fn result_depends_on_x(db: &dyn Db, input: MyInput) -> u32 {
|
||||
db.push_log(format!("result_depends_on_x({:?})", input));
|
||||
input.x(db) + 1
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
fn result_depends_on_y(db: &dyn Db, input: MyInput) -> u32 {
|
||||
db.push_log(format!("result_depends_on_y({:?})", input));
|
||||
input.y(db) - 1
|
||||
|
|
|
@ -11,7 +11,7 @@ trait Db: salsa::DbWithJar<Jar> {}
|
|||
#[derive(Clone, Debug)]
|
||||
struct Field {}
|
||||
|
||||
#[salsa::input(jar = Jar)]
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
#[id]
|
||||
id_one: u32,
|
||||
|
|
|
@ -36,7 +36,7 @@ impl Drop for HotPotato {
|
|||
}
|
||||
}
|
||||
|
||||
#[salsa::input(jar = Jar)]
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
field: u32,
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ fn get_hot_potato(db: &dyn Db, input: MyInput) -> Arc<HotPotato> {
|
|||
Arc::new(HotPotato::new(input.field(db)))
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
fn get_hot_potato2(db: &dyn Db, input: MyInput) -> u32 {
|
||||
db.push_log(format!("get_hot_potato2({:?})", input.field(db)));
|
||||
get_hot_potato(db, input).0
|
||||
|
|
|
@ -11,7 +11,7 @@ struct Jar(MyInput);
|
|||
|
||||
trait Db: salsa::DbWithJar<Jar> + HasLogger {}
|
||||
|
||||
#[salsa::input(jar = Jar)]
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
field: String,
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ struct Jar(MyTracked<'_>);
|
|||
|
||||
trait Db: salsa::DbWithJar<Jar> {}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
struct MyTracked<'db> {
|
||||
field: u32,
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ impl<T: salsa::DbWithJar<Jar> + Knobs> Db for T {}
|
|||
#[salsa::jar(db = Db)]
|
||||
pub(crate) struct Jar(MyInput, a1, a2, b1, b2);
|
||||
|
||||
#[salsa::input(jar = Jar)]
|
||||
#[salsa::input]
|
||||
pub(crate) struct MyInput {
|
||||
field: i32,
|
||||
}
|
||||
|
|
|
@ -13,12 +13,12 @@ impl<T: salsa::DbWithJar<Jar> + Knobs> Db for T {}
|
|||
#[salsa::jar(db = Db)]
|
||||
pub(crate) struct Jar(MyInput, a1, a2, b1, b2, b3);
|
||||
|
||||
#[salsa::input(jar = Jar)]
|
||||
#[salsa::input]
|
||||
pub(crate) struct MyInput {
|
||||
field: i32,
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
pub(crate) fn a1(db: &dyn Db, input: MyInput) -> i32 {
|
||||
// tell thread b we have started
|
||||
db.signal(1);
|
||||
|
@ -28,7 +28,7 @@ pub(crate) fn a1(db: &dyn Db, input: MyInput) -> i32 {
|
|||
|
||||
a2(db, input)
|
||||
}
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
pub(crate) fn a2(db: &dyn Db, input: MyInput) -> i32 {
|
||||
// create the cycle
|
||||
b1(db, input)
|
||||
|
@ -46,7 +46,7 @@ fn recover_b1(db: &dyn Db, _cycle: &salsa::Cycle, key: MyInput) -> i32 {
|
|||
key.field(db) * 20 + 2
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
pub(crate) fn b2(db: &dyn Db, input: MyInput) -> i32 {
|
||||
// will encounter a cycle but recover
|
||||
b3(db, input);
|
||||
|
|
|
@ -14,12 +14,12 @@ impl<T: salsa::DbWithJar<Jar> + Knobs> Db for T {}
|
|||
#[salsa::jar(db = Db)]
|
||||
pub(crate) struct Jar(MyInput, a, b);
|
||||
|
||||
#[salsa::input(jar = Jar)]
|
||||
#[salsa::input]
|
||||
pub(crate) struct MyInput {
|
||||
field: i32,
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
pub(crate) fn a(db: &dyn Db, input: MyInput) -> i32 {
|
||||
// Wait to create the cycle until both threads have entered
|
||||
db.signal(1);
|
||||
|
@ -28,7 +28,7 @@ pub(crate) fn a(db: &dyn Db, input: MyInput) -> i32 {
|
|||
b(db, input)
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
pub(crate) fn b(db: &dyn Db, input: MyInput) -> i32 {
|
||||
// Wait to create the cycle until both threads have entered
|
||||
db.wait_for(1);
|
||||
|
|
|
@ -13,12 +13,12 @@ impl<T: salsa::DbWithJar<Jar> + Knobs> Db for T {}
|
|||
#[salsa::jar(db = Db)]
|
||||
pub(crate) struct Jar(MyInput, a1, a2, b1, b2);
|
||||
|
||||
#[salsa::input(jar = Jar)]
|
||||
#[salsa::input]
|
||||
pub(crate) struct MyInput {
|
||||
field: i32,
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
pub(crate) fn a1(db: &dyn Db, input: MyInput) -> i32 {
|
||||
// Wait to create the cycle until both threads have entered
|
||||
db.signal(1);
|
||||
|
@ -36,7 +36,7 @@ fn recover(db: &dyn Db, _cycle: &salsa::Cycle, key: MyInput) -> i32 {
|
|||
key.field(db) * 20 + 2
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
pub(crate) fn b1(db: &dyn Db, input: MyInput) -> i32 {
|
||||
// Wait to create the cycle until both threads have entered
|
||||
db.wait_for(1);
|
||||
|
@ -47,7 +47,7 @@ pub(crate) fn b1(db: &dyn Db, input: MyInput) -> i32 {
|
|||
b2(db, input)
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
pub(crate) fn b2(db: &dyn Db, input: MyInput) -> i32 {
|
||||
a1(db, input)
|
||||
}
|
||||
|
|
|
@ -13,22 +13,22 @@ struct Jar(
|
|||
|
||||
trait Db: salsa::DbWithJar<Jar> {}
|
||||
|
||||
#[salsa::input(jar = Jar)]
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
field: u32,
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
struct MyTracked<'db> {
|
||||
field: u32,
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
fn tracked_struct_created_in_another_query<'db>(db: &'db dyn Db, input: MyInput) -> MyTracked<'db> {
|
||||
MyTracked::new(db, input.field(db) * 2)
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
fn tracked_fn<'db>(db: &'db dyn Db, input: MyInput) -> MyTracked<'db> {
|
||||
let t = tracked_struct_created_in_another_query(db, input);
|
||||
if input.field(db) != 0 {
|
||||
|
|
|
@ -48,7 +48,7 @@ fn read_maybe_specified<'db>(db: &'db dyn Db, tracked: MyTracked<'db>) -> u32 {
|
|||
|
||||
/// Create a tracked value and *maybe* specify a value for
|
||||
/// `maybe_specified`
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
fn create_tracked<'db>(db: &'db dyn Db, input: MyInput) -> MyTracked<'db> {
|
||||
db.push_log(format!("create_tracked({:?})", input));
|
||||
let tracked = MyTracked::new(db, input);
|
||||
|
|
|
@ -5,17 +5,17 @@ struct Jar(MyInput, MyTracked<'_>, tracked_fn);
|
|||
|
||||
trait Db: salsa::DbWithJar<Jar> {}
|
||||
|
||||
#[salsa::input(jar = Jar)]
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
field: u32,
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
struct MyTracked<'db> {
|
||||
field: u32,
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
fn tracked_fn<'db>(db: &'db dyn Db, input: MyInput) -> MyTracked<'db> {
|
||||
MyTracked::new(db, input.field(db) / 2)
|
||||
}
|
||||
|
|
|
@ -7,12 +7,12 @@ struct Jar(MyInput, tracked_fn);
|
|||
|
||||
trait Db: salsa::DbWithJar<Jar> {}
|
||||
|
||||
#[salsa::input(jar = Jar)]
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
field: u32,
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
fn tracked_fn(db: &dyn Db, input: MyInput) -> u32 {
|
||||
input.field(db) * 2
|
||||
}
|
||||
|
|
|
@ -6,17 +6,17 @@ struct Jar(MyInput, MyTracked<'_>, tracked_fn);
|
|||
|
||||
trait Db: salsa::DbWithJar<Jar> {}
|
||||
|
||||
#[salsa::input(jar = Jar)]
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
field: u32,
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
struct MyTracked<'db> {
|
||||
field: u32,
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
fn tracked_fn<'db>(db: &'db dyn Db, input: MyInput) -> MyTracked<'db> {
|
||||
MyTracked::new(db, input.field(db) * 2)
|
||||
}
|
||||
|
|
|
@ -7,17 +7,17 @@ struct Jar(MyInput, MyTracked<'_>, tracked_fn, tracked_fn_extra);
|
|||
|
||||
trait Db: salsa::DbWithJar<Jar> {}
|
||||
|
||||
#[salsa::input(jar = Jar)]
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
field: u32,
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
struct MyTracked<'db> {
|
||||
field: u32,
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
fn tracked_fn<'db>(db: &'db dyn Db, input: MyInput) -> MyTracked<'db> {
|
||||
let t = MyTracked::new(db, input.field(db) * 2);
|
||||
if input.field(db) != 0 {
|
||||
|
|
|
@ -8,17 +8,17 @@ struct Jar(MyInput, MyTracked<'_>, tracked_fn, tracked_fn_extra);
|
|||
|
||||
trait Db: salsa::DbWithJar<Jar> + HasLogger {}
|
||||
|
||||
#[salsa::input(jar = Jar)]
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
field: u32,
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
struct MyTracked<'db> {
|
||||
field: u32,
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
fn tracked_fn<'db>(db: &'db dyn Db, input: MyInput) -> u32 {
|
||||
db.push_log(format!("tracked_fn({:?})", input.debug(db)));
|
||||
let t = MyTracked::new(db, input.field(db) * 2);
|
||||
|
|
|
@ -11,17 +11,17 @@ struct Jar(MyInput, MyTracked1<'_>, MyTracked2<'_>);
|
|||
|
||||
trait Db: salsa::DbWithJar<Jar> + HasLogger {}
|
||||
|
||||
#[salsa::input(jar = Jar)]
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
field: u32,
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
struct MyTracked1<'db1> {
|
||||
field: MyTracked2<'db1>,
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
struct MyTracked2<'db2> {
|
||||
field: u32,
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ impl salsa::DebugWithDb<dyn Db + '_> for Token {
|
|||
}
|
||||
}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
struct TokenTree<'db> {
|
||||
#[return_ref]
|
||||
tokens: Vec<Token>,
|
||||
|
|
|
@ -6,10 +6,10 @@ pub struct Jar(SourceTree<'_>, SourceTree_all_items, use_tree);
|
|||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Item {}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
pub struct SourceTree<'db> {}
|
||||
|
||||
#[salsa::tracked(jar = Jar)]
|
||||
#[salsa::tracked]
|
||||
impl<'db> SourceTree<'db> {
|
||||
#[salsa::tracked(return_ref)]
|
||||
pub fn all_items(self, _db: &'db dyn Db) -> Vec<Item> {
|
||||
|
|
|
@ -3,5 +3,5 @@ trait Db: salsa::DbWithJar<Jar> {}
|
|||
#[salsa::jar(db = Db)]
|
||||
struct Jar(Keywords<'_>);
|
||||
|
||||
#[salsa::interned(jar = Jar)]
|
||||
#[salsa::interned]
|
||||
struct Keywords<'db> {}
|
||||
|
|
Loading…
Reference in a new issue