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