]> git.proxmox.com Git - rustc.git/blob - vendor/salsa/tests/cycles.rs
New upstream version 1.46.0~beta.2+dfsg1
[rustc.git] / vendor / salsa / tests / cycles.rs
1 use salsa::{ParallelDatabase, Snapshot};
2
3 #[derive(PartialEq, Eq, Hash, Clone, Debug)]
4 struct Error {
5 cycle: Vec<String>,
6 }
7
8 #[salsa::database(GroupStruct)]
9 #[derive(Default)]
10 struct DatabaseImpl {
11 runtime: salsa::Runtime<DatabaseImpl>,
12 }
13
14 impl salsa::Database for DatabaseImpl {
15 fn salsa_runtime(&self) -> &salsa::Runtime<Self> {
16 &self.runtime
17 }
18
19 fn salsa_runtime_mut(&mut self) -> &mut salsa::Runtime<Self> {
20 &mut self.runtime
21 }
22 }
23
24 impl ParallelDatabase for DatabaseImpl {
25 fn snapshot(&self) -> Snapshot<Self> {
26 Snapshot::new(DatabaseImpl {
27 runtime: self.runtime.snapshot(self),
28 })
29 }
30 }
31
32 #[salsa::query_group(GroupStruct)]
33 trait Database: salsa::Database {
34 // `a` and `b` depend on each other and form a cycle
35 fn memoized_a(&self) -> ();
36 fn memoized_b(&self) -> ();
37 fn volatile_a(&self) -> ();
38 fn volatile_b(&self) -> ();
39
40 fn cycle_leaf(&self) -> ();
41
42 #[salsa::cycle(recover_a)]
43 fn cycle_a(&self) -> Result<(), Error>;
44 #[salsa::cycle(recover_b)]
45 fn cycle_b(&self) -> Result<(), Error>;
46
47 fn cycle_c(&self) -> Result<(), Error>;
48 }
49
50 fn recover_a(_db: &impl Database, cycle: &[String]) -> Result<(), Error> {
51 Err(Error {
52 cycle: cycle.to_owned(),
53 })
54 }
55
56 fn recover_b(_db: &impl Database, cycle: &[String]) -> Result<(), Error> {
57 Err(Error {
58 cycle: cycle.to_owned(),
59 })
60 }
61
62 fn memoized_a(db: &impl Database) -> () {
63 db.memoized_b()
64 }
65
66 fn memoized_b(db: &impl Database) -> () {
67 db.memoized_a()
68 }
69
70 fn volatile_a(db: &impl Database) -> () {
71 db.salsa_runtime().report_untracked_read();
72 db.volatile_b()
73 }
74
75 fn volatile_b(db: &impl Database) -> () {
76 db.salsa_runtime().report_untracked_read();
77 db.volatile_a()
78 }
79
80 fn cycle_leaf(_db: &impl Database) -> () {}
81
82 fn cycle_a(db: &impl Database) -> Result<(), Error> {
83 let _ = db.cycle_b();
84 Ok(())
85 }
86
87 fn cycle_b(db: &impl Database) -> Result<(), Error> {
88 db.cycle_leaf();
89 let _ = db.cycle_a();
90 Ok(())
91 }
92
93 fn cycle_c(db: &impl Database) -> Result<(), Error> {
94 db.cycle_b()
95 }
96
97 #[test]
98 #[should_panic(expected = "cycle detected")]
99 fn cycle_memoized() {
100 let query = DatabaseImpl::default();
101 query.memoized_a();
102 }
103
104 #[test]
105 #[should_panic(expected = "cycle detected")]
106 fn cycle_volatile() {
107 let query = DatabaseImpl::default();
108 query.volatile_a();
109 }
110
111 #[test]
112 fn cycle_cycle() {
113 let query = DatabaseImpl::default();
114 assert!(query.cycle_a().is_err());
115 }
116
117 #[test]
118 fn inner_cycle() {
119 let query = DatabaseImpl::default();
120 let err = query.cycle_c();
121 assert!(err.is_err());
122 let cycle = err.unwrap_err().cycle;
123 assert!(
124 cycle
125 .iter()
126 .zip(&["cycle_b", "cycle_a"])
127 .all(|(l, r)| l.contains(r)),
128 "{:#?}",
129 cycle
130 );
131 }
132
133 #[test]
134 fn parallel_cycle() {
135 let _ = env_logger::try_init();
136
137 let db = DatabaseImpl::default();
138 let thread1 = std::thread::spawn({
139 let db = db.snapshot();
140 move || {
141 let result = db.cycle_a();
142 assert!(result.is_err(), "Expected cycle error");
143 let cycle = result.unwrap_err().cycle;
144 assert!(
145 cycle
146 .iter()
147 .all(|l| ["cycle_b", "cycle_a"].iter().any(|r| l.contains(r))),
148 "{:#?}",
149 cycle
150 );
151 }
152 });
153
154 let thread2 = std::thread::spawn(move || {
155 let result = db.cycle_c();
156 assert!(result.is_err(), "Expected cycle error");
157 let cycle = result.unwrap_err().cycle;
158 assert!(
159 cycle
160 .iter()
161 .all(|l| ["cycle_b", "cycle_a"].iter().any(|r| l.contains(r))),
162 "{:#?}",
163 cycle
164 );
165 });
166
167 thread1.join().unwrap();
168 thread2.join().unwrap();
169 eprintln!("OK");
170 }