salsa/tests/incremental/memoized_volatile.rs
Niko Matsakis fad97eeb6a remove the DB parameter
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).
2020-07-04 14:17:11 +00:00

77 lines
2.4 KiB
Rust

use crate::implementation::{TestContext, TestContextImpl};
use salsa::{Database, Durability};
#[salsa::query_group(MemoizedVolatile)]
pub(crate) trait MemoizedVolatileContext: TestContext {
// Queries for testing a "volatile" value wrapped by
// memoization.
fn memoized2(&self) -> usize;
fn memoized1(&self) -> usize;
fn volatile(&self) -> usize;
}
fn memoized2(db: &dyn MemoizedVolatileContext) -> usize {
db.log().add("Memoized2 invoked");
db.memoized1()
}
fn memoized1(db: &dyn MemoizedVolatileContext) -> usize {
db.log().add("Memoized1 invoked");
let v = db.volatile();
v / 2
}
fn volatile(db: &dyn MemoizedVolatileContext) -> usize {
db.log().add("Volatile invoked");
db.salsa_runtime().report_untracked_read();
db.clock().increment()
}
#[test]
fn volatile_x2() {
let query = TestContextImpl::default();
// Invoking volatile twice doesn't execute twice, because volatile
// queries are memoized by default.
query.volatile();
query.volatile();
query.assert_log(&["Volatile invoked"]);
}
/// Test that:
///
/// - On the first run of R0, we recompute everything.
/// - On the second run of R1, we recompute nothing.
/// - On the first run of R1, we recompute Memoized1 but not Memoized2 (since Memoized1 result
/// did not change).
/// - On the second run of R1, we recompute nothing.
/// - On the first run of R2, we recompute everything (since Memoized1 result *did* change).
#[test]
fn revalidate() {
let mut query = TestContextImpl::default();
query.memoized2();
query.assert_log(&["Memoized2 invoked", "Memoized1 invoked", "Volatile invoked"]);
query.memoized2();
query.assert_log(&[]);
// Second generation: volatile will change (to 1) but memoized1
// will not (still 0, as 1/2 = 0)
query.salsa_runtime_mut().synthetic_write(Durability::LOW);
query.memoized2();
query.assert_log(&["Memoized1 invoked", "Volatile invoked"]);
query.memoized2();
query.assert_log(&[]);
// Third generation: volatile will change (to 2) and memoized1
// will too (to 1). Therefore, after validating that Memoized1
// changed, we now invoke Memoized2.
query.salsa_runtime_mut().synthetic_write(Durability::LOW);
query.memoized2();
query.assert_log(&["Memoized1 invoked", "Volatile invoked", "Memoized2 invoked"]);
query.memoized2();
query.assert_log(&[]);
}