rust-analyzer/crates/salsa/tests/incremental/constants.rs
2024-05-30 16:18:49 -07:00

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