mirror of
https://github.com/salsa-rs/salsa.git
synced 2025-01-12 16:35:21 +00:00
fad97eeb6a
This had two unexpected consequences, one unfortunate, one "medium": * All `salsa::Database` must be `'static`. This falls out from `Q::DynDb` not having access to any lifetimes, but also the defaulting rules for `dyn QueryGroup` that make it `dyn QueryGroup + 'static`. We don't really support generic databases anyway yet so this isn't a big deal, and we can add workarounds later (ideally via GATs). * It is now statically impossible to invoke `snapshot` from a query, and so we don't need to test that it panics. This is because the signature of `snapshot` returns a `Snapshot<Self>` and that is not accessible to a `dyn QueryGroup` type. Similarly, invoking `Runtime::snapshot` directly is not possible becaues it is crate-private. So I removed the test. This seems ok, but eventually I would like to expose ways for queries to do parallel execution (matklad and I had talked about a "speculation" primitive for enabling that). * This commit is 99% boilerplate I did with search-and-replace. I also rolled in a few other changes I might have preferred to factor out, most notably removing the `GetQueryTable` plumbing trait in favor of free-methods, but it was awkward to factor them out and get all the generics right (so much simpler in this version).
148 lines
4.5 KiB
Rust
148 lines
4.5 KiB
Rust
use crate::implementation::{TestContext, TestContextImpl};
|
|
use salsa::debug::DebugQueryTable;
|
|
use salsa::Durability;
|
|
|
|
#[salsa::query_group(Constants)]
|
|
pub(crate) trait ConstantsDatabase: TestContext {
|
|
#[salsa::input]
|
|
fn input(&self, key: char) -> usize;
|
|
|
|
fn add(&self, key1: char, key2: char) -> usize;
|
|
|
|
fn add3(&self, key1: char, key2: char, key3: char) -> usize;
|
|
}
|
|
|
|
fn add(db: &dyn ConstantsDatabase, key1: char, key2: char) -> usize {
|
|
db.log().add(format!("add({}, {})", key1, key2));
|
|
db.input(key1) + db.input(key2)
|
|
}
|
|
|
|
fn add3(db: &dyn ConstantsDatabase, key1: char, key2: char, key3: char) -> usize {
|
|
db.log().add(format!("add3({}, {}, {})", key1, key2, key3));
|
|
db.add(key1, key2) + db.input(key3)
|
|
}
|
|
|
|
// Test we can assign a constant and things will be correctly
|
|
// recomputed afterwards.
|
|
#[test]
|
|
fn invalidate_constant() {
|
|
let db = &mut TestContextImpl::default();
|
|
db.set_input_with_durability('a', 44, Durability::HIGH);
|
|
db.set_input_with_durability('b', 22, Durability::HIGH);
|
|
assert_eq!(db.add('a', 'b'), 66);
|
|
|
|
db.set_input_with_durability('a', 66, Durability::HIGH);
|
|
assert_eq!(db.add('a', 'b'), 88);
|
|
}
|
|
|
|
#[test]
|
|
fn invalidate_constant_1() {
|
|
let db = &mut TestContextImpl::default();
|
|
|
|
// Not constant:
|
|
db.set_input('a', 44);
|
|
assert_eq!(db.add('a', 'a'), 88);
|
|
|
|
// Becomes constant:
|
|
db.set_input_with_durability('a', 44, Durability::HIGH);
|
|
assert_eq!(db.add('a', 'a'), 88);
|
|
|
|
// Invalidates:
|
|
db.set_input_with_durability('a', 33, Durability::HIGH);
|
|
assert_eq!(db.add('a', 'a'), 66);
|
|
}
|
|
|
|
// Test cases where we assign same value to 'a' after declaring it a
|
|
// constant.
|
|
#[test]
|
|
fn set_after_constant_same_value() {
|
|
let db = &mut TestContextImpl::default();
|
|
db.set_input_with_durability('a', 44, Durability::HIGH);
|
|
db.set_input_with_durability('a', 44, Durability::HIGH);
|
|
db.set_input('a', 44);
|
|
}
|
|
|
|
#[test]
|
|
fn not_constant() {
|
|
let mut db = TestContextImpl::default();
|
|
|
|
db.set_input('a', 22);
|
|
db.set_input('b', 44);
|
|
assert_eq!(db.add('a', 'b'), 66);
|
|
assert_eq!(Durability::LOW, AddQuery.in_db(&db).durability(('a', 'b')));
|
|
}
|
|
|
|
#[test]
|
|
fn durability() {
|
|
let mut db = TestContextImpl::default();
|
|
|
|
db.set_input_with_durability('a', 22, Durability::HIGH);
|
|
db.set_input_with_durability('b', 44, Durability::HIGH);
|
|
assert_eq!(db.add('a', 'b'), 66);
|
|
assert_eq!(Durability::HIGH, AddQuery.in_db(&db).durability(('a', 'b')));
|
|
}
|
|
|
|
#[test]
|
|
fn mixed_constant() {
|
|
let mut db = TestContextImpl::default();
|
|
|
|
db.set_input_with_durability('a', 22, Durability::HIGH);
|
|
db.set_input('b', 44);
|
|
assert_eq!(db.add('a', 'b'), 66);
|
|
assert_eq!(Durability::LOW, AddQuery.in_db(&db).durability(('a', 'b')));
|
|
}
|
|
|
|
#[test]
|
|
fn becomes_constant_with_change() {
|
|
let mut db = TestContextImpl::default();
|
|
|
|
db.set_input('a', 22);
|
|
db.set_input('b', 44);
|
|
assert_eq!(db.add('a', 'b'), 66);
|
|
assert_eq!(Durability::LOW, AddQuery.in_db(&db).durability(('a', 'b')));
|
|
|
|
db.set_input_with_durability('a', 23, Durability::HIGH);
|
|
assert_eq!(db.add('a', 'b'), 67);
|
|
assert_eq!(Durability::LOW, AddQuery.in_db(&db).durability(('a', 'b')));
|
|
|
|
db.set_input_with_durability('b', 45, Durability::HIGH);
|
|
assert_eq!(db.add('a', 'b'), 68);
|
|
assert_eq!(Durability::HIGH, AddQuery.in_db(&db).durability(('a', 'b')));
|
|
|
|
db.set_input_with_durability('b', 45, Durability::MEDIUM);
|
|
assert_eq!(db.add('a', 'b'), 68);
|
|
assert_eq!(
|
|
Durability::MEDIUM,
|
|
AddQuery.in_db(&db).durability(('a', 'b'))
|
|
);
|
|
}
|
|
|
|
// Test a subtle case in which an input changes from constant to
|
|
// non-constant, but its value doesn't change. If we're not careful,
|
|
// this can cause us to incorrectly consider derived values as still
|
|
// being constant.
|
|
#[test]
|
|
fn constant_to_non_constant() {
|
|
let mut db = TestContextImpl::default();
|
|
|
|
db.set_input_with_durability('a', 11, Durability::HIGH);
|
|
db.set_input_with_durability('b', 22, Durability::HIGH);
|
|
db.set_input_with_durability('c', 33, Durability::HIGH);
|
|
|
|
// Here, `add3` invokes `add`, which yields 33. Both calls are
|
|
// constant.
|
|
assert_eq!(db.add3('a', 'b', 'c'), 66);
|
|
|
|
db.set_input('a', 11);
|
|
|
|
// Here, `add3` invokes `add`, which *still* yields 33, but which
|
|
// is no longer constant. Since value didn't change, we might
|
|
// preserve `add3` unchanged, not noticing that it is no longer
|
|
// constant.
|
|
assert_eq!(db.add3('a', 'b', 'c'), 66);
|
|
|
|
// In that case, we would not get the correct result here, when
|
|
// 'a' changes *again*.
|
|
db.set_input('a', 22);
|
|
assert_eq!(db.add3('a', 'b', 'c'), 77);
|
|
}
|