mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-10-25 12:44:42 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			146 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			146 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);
 | |
| }
 | 
