This commit is contained in:
Niko Matsakis 2024-07-16 06:04:01 -04:00
parent 612cec6703
commit 8a39bf029b
40 changed files with 194 additions and 378 deletions

View file

@ -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!)),

View file

@ -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! {

View file

@ -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);
}

View file

@ -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 {

View file

@ -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);

View file

@ -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 {

View file

@ -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,
}

View file

@ -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,
}

View file

@ -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);
}
}

View file

@ -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,
}

View file

@ -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)
}

View file

@ -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,
}

View file

@ -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,
}

View file

@ -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)]

View file

@ -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

View file

@ -1,7 +1,7 @@
#[salsa::jar(db = Db)]
struct Jar(Tracked<'_>);
#[salsa::tracked(jar = Jar)]
#[salsa::tracked]
struct Tracked<'db> {
field: u32,
}

View file

@ -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() });
}

View file

@ -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);

View file

@ -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));
})
}

View file

@ -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)
}

View file

@ -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

View file

@ -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,

View file

@ -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

View file

@ -11,7 +11,7 @@ struct Jar(MyInput);
trait Db: salsa::DbWithJar<Jar> + HasLogger {}
#[salsa::input(jar = Jar)]
#[salsa::input]
struct MyInput {
field: String,
}

View file

@ -6,7 +6,7 @@ struct Jar(MyTracked<'_>);
trait Db: salsa::DbWithJar<Jar> {}
#[salsa::tracked(jar = Jar)]
#[salsa::tracked]
struct MyTracked<'db> {
field: u32,
}

View file

@ -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,
}

View file

@ -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);

View file

@ -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);

View file

@ -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)
}

View file

@ -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 {

View file

@ -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);

View file

@ -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)
}

View file

@ -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
}

View file

@ -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)
}

View file

@ -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 {

View file

@ -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);

View file

@ -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,
}

View file

@ -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>,

View file

@ -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> {

View file

@ -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> {}