Skip to content

Commit 696efd7

Browse files
committed
Add unsafety test for consumers of salsa macros
1 parent c48a9df commit 696efd7

File tree

1 file changed

+89
-0
lines changed

1 file changed

+89
-0
lines changed

tests/downstream_unsafe.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#![forbid(unsafe_code)]
2+
// Below code directly duplicated from hello_world
3+
4+
//! Test that a `tracked` fn on a `salsa::input`
5+
//! compiles and executes successfully.
6+
7+
mod common;
8+
use common::LogDatabase;
9+
10+
use expect_test::expect;
11+
use salsa::Setter;
12+
use test_log::test;
13+
14+
#[salsa::input]
15+
struct MyInput {
16+
field: u32,
17+
}
18+
19+
#[salsa::tracked]
20+
fn final_result(db: &dyn LogDatabase, input: MyInput) -> u32 {
21+
db.push_log(format!("final_result({:?})", input));
22+
intermediate_result(db, input).field(db) * 2
23+
}
24+
25+
#[salsa::tracked]
26+
struct MyTracked<'db> {
27+
field: u32,
28+
}
29+
30+
#[salsa::tracked]
31+
fn intermediate_result(db: &dyn LogDatabase, input: MyInput) -> MyTracked<'_> {
32+
db.push_log(format!("intermediate_result({:?})", input));
33+
MyTracked::new(db, input.field(db) / 2)
34+
}
35+
36+
#[test]
37+
fn execute() {
38+
let mut db = common::LoggerDatabase::default();
39+
40+
let input = MyInput::new(&db, 22);
41+
assert_eq!(final_result(&db, input), 22);
42+
db.assert_logs(expect![[r#"
43+
[
44+
"final_result(MyInput { [salsa id]: Id(0), field: 22 })",
45+
"intermediate_result(MyInput { [salsa id]: Id(0), field: 22 })",
46+
]"#]]);
47+
48+
// Intermediate result is the same, so final result does
49+
// not need to be recomputed:
50+
input.set_field(&mut db).to(23);
51+
assert_eq!(final_result(&db, input), 22);
52+
db.assert_logs(expect![[r#"
53+
[
54+
"intermediate_result(MyInput { [salsa id]: Id(0), field: 23 })",
55+
]"#]]);
56+
57+
input.set_field(&mut db).to(24);
58+
assert_eq!(final_result(&db, input), 24);
59+
db.assert_logs(expect![[r#"
60+
[
61+
"intermediate_result(MyInput { [salsa id]: Id(0), field: 24 })",
62+
"final_result(MyInput { [salsa id]: Id(0), field: 24 })",
63+
]"#]]);
64+
}
65+
66+
/// Create and mutate a distinct input. No re-execution required.
67+
#[test]
68+
fn red_herring() {
69+
let mut db = common::LoggerDatabase::default();
70+
71+
let input = MyInput::new(&db, 22);
72+
assert_eq!(final_result(&db, input), 22);
73+
db.assert_logs(expect![[r#"
74+
[
75+
"final_result(MyInput { [salsa id]: Id(0), field: 22 })",
76+
"intermediate_result(MyInput { [salsa id]: Id(0), field: 22 })",
77+
]"#]]);
78+
79+
// Create a distinct input and mutate it.
80+
// This will trigger a new revision in the database
81+
// but shouldn't actually invalidate our existing ones.
82+
let input2 = MyInput::new(&db, 44);
83+
input2.set_field(&mut db).to(66);
84+
85+
// Re-run the query on the original input. Nothing re-executes!
86+
assert_eq!(final_result(&db, input), 22);
87+
db.assert_logs(expect![[r#"
88+
[]"#]]);
89+
}

0 commit comments

Comments
 (0)