4 use std::marker::PhantomData;
6 impl<'a> super::ForestObligation for &'a str {
7 type Predicate = &'a str;
9 fn as_predicate(&self) -> &Self::Predicate {
14 struct ClosureObligationProcessor<OF, BF, O, E> {
15 process_obligation: OF,
16 _process_backedge: BF,
17 marker: PhantomData<(O, E)>,
20 #[allow(non_snake_case)]
21 fn C<OF, BF, O>(of: OF, bf: BF) -> ClosureObligationProcessor<OF, BF, O, &'static str>
22 where OF: FnMut(&mut O) -> ProcessResult<O, &'static str>,
25 ClosureObligationProcessor {
26 process_obligation: of,
27 _process_backedge: bf,
32 impl<OF, BF, O, E> ObligationProcessor for ClosureObligationProcessor<OF, BF, O, E>
33 where O: super::ForestObligation + fmt::Debug,
35 OF: FnMut(&mut O) -> ProcessResult<O, E>,
41 fn process_obligation(&mut self,
42 obligation: &mut Self::Obligation)
43 -> ProcessResult<Self::Obligation, Self::Error>
45 (self.process_obligation)(obligation)
48 fn process_backedge<'c, I>(&mut self, _cycle: I,
49 _marker: PhantomData<&'c Self::Obligation>)
50 where I: Clone + Iterator<Item=&'c Self::Obligation>
58 let mut forest = ObligationForest::new();
59 forest.register_obligation("A");
60 forest.register_obligation("B");
61 forest.register_obligation("C");
63 // first round, B errors out, A has subtasks, and C completes, creating this:
67 let Outcome { completed: ok, errors: err, .. } =
68 forest.process_obligations(&mut C(|obligation| {
70 "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
71 "B" => ProcessResult::Error("B is for broken"),
72 "C" => ProcessResult::Changed(vec![]),
75 }, |_| {}), DoCompleted::Yes);
76 assert_eq!(ok.unwrap(), vec!["C"]);
79 error: "B is for broken",
83 // second round: two delays, one success, creating an uneven set of subtasks:
89 forest.register_obligation("D");
90 let Outcome { completed: ok, errors: err, .. } =
91 forest.process_obligations(&mut C(|obligation| {
93 "A.1" => ProcessResult::Unchanged,
94 "A.2" => ProcessResult::Unchanged,
95 "A.3" => ProcessResult::Changed(vec!["A.3.i"]),
96 "D" => ProcessResult::Changed(vec!["D.1", "D.2"]),
99 }, |_| {}), DoCompleted::Yes);
100 assert_eq!(ok.unwrap(), Vec::<&'static str>::new());
101 assert_eq!(err, Vec::new());
104 // third round: ok in A.1 but trigger an error in A.2. Check that it
105 // propagates to A, but not D.1 or D.2.
106 // D |-> D.1 |-> D.1.i
108 let Outcome { completed: ok, errors: err, .. } =
109 forest.process_obligations(&mut C(|obligation| {
111 "A.1" => ProcessResult::Changed(vec![]),
112 "A.2" => ProcessResult::Error("A is for apple"),
113 "A.3.i" => ProcessResult::Changed(vec![]),
114 "D.1" => ProcessResult::Changed(vec!["D.1.i"]),
115 "D.2" => ProcessResult::Changed(vec!["D.2.i"]),
118 }, |_| {}), DoCompleted::Yes);
119 assert_eq!(ok.unwrap(), vec!["A.3", "A.1", "A.3.i"]);
122 error: "A is for apple",
123 backtrace: vec!["A.2", "A"],
126 // fourth round: error in D.1.i
127 let Outcome { completed: ok, errors: err, .. } =
128 forest.process_obligations(&mut C(|obligation| {
130 "D.1.i" => ProcessResult::Error("D is for dumb"),
131 "D.2.i" => ProcessResult::Changed(vec![]),
132 _ => panic!("unexpected obligation {:?}", obligation),
134 }, |_| {}), DoCompleted::Yes);
135 assert_eq!(ok.unwrap(), vec!["D.2.i", "D.2"]);
138 error: "D is for dumb",
139 backtrace: vec!["D.1.i", "D.1", "D"],
143 // Test that if a tree with grandchildren succeeds, everything is
144 // reported as expected:
152 fn success_in_grandchildren() {
153 let mut forest = ObligationForest::new();
154 forest.register_obligation("A");
156 let Outcome { completed: ok, errors: err, .. } =
157 forest.process_obligations(&mut C(|obligation| {
159 "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
162 }, |_| {}), DoCompleted::Yes);
163 assert!(ok.unwrap().is_empty());
164 assert!(err.is_empty());
166 let Outcome { completed: ok, errors: err, .. } =
167 forest.process_obligations(&mut C(|obligation| {
169 "A.1" => ProcessResult::Changed(vec![]),
170 "A.2" => ProcessResult::Changed(vec!["A.2.i", "A.2.ii"]),
171 "A.3" => ProcessResult::Changed(vec![]),
174 }, |_| {}), DoCompleted::Yes);
175 assert_eq!(ok.unwrap(), vec!["A.3", "A.1"]);
176 assert!(err.is_empty());
178 let Outcome { completed: ok, errors: err, .. } =
179 forest.process_obligations(&mut C(|obligation| {
181 "A.2.i" => ProcessResult::Changed(vec!["A.2.i.a"]),
182 "A.2.ii" => ProcessResult::Changed(vec![]),
185 }, |_| {}), DoCompleted::Yes);
186 assert_eq!(ok.unwrap(), vec!["A.2.ii"]);
187 assert!(err.is_empty());
189 let Outcome { completed: ok, errors: err, .. } =
190 forest.process_obligations(&mut C(|obligation| {
192 "A.2.i.a" => ProcessResult::Changed(vec![]),
195 }, |_| {}), DoCompleted::Yes);
196 assert_eq!(ok.unwrap(), vec!["A.2.i.a", "A.2.i", "A.2", "A"]);
197 assert!(err.is_empty());
199 let Outcome { completed: ok, errors: err, .. } =
200 forest.process_obligations(&mut C(|_| unreachable!(), |_| {}),
203 assert!(ok.unwrap().is_empty());
204 assert!(err.is_empty());
208 fn to_errors_no_throw() {
209 // check that converting multiple children with common parent (A)
210 // yields to correct errors (and does not panic, in particular).
211 let mut forest = ObligationForest::new();
212 forest.register_obligation("A");
213 let Outcome { completed: ok, errors: err, .. } =
214 forest.process_obligations(&mut C(|obligation| {
216 "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
219 }, |_|{}), DoCompleted::Yes);
220 assert_eq!(ok.unwrap().len(), 0);
221 assert_eq!(err.len(), 0);
222 let errors = forest.to_errors(());
223 assert_eq!(errors[0].backtrace, vec!["A.1", "A"]);
224 assert_eq!(errors[1].backtrace, vec!["A.2", "A"]);
225 assert_eq!(errors[2].backtrace, vec!["A.3", "A"]);
226 assert_eq!(errors.len(), 3);
231 // check that diamond dependencies are handled correctly
232 let mut forest = ObligationForest::new();
233 forest.register_obligation("A");
234 let Outcome { completed: ok, errors: err, .. } =
235 forest.process_obligations(&mut C(|obligation| {
237 "A" => ProcessResult::Changed(vec!["A.1", "A.2"]),
240 }, |_|{}), DoCompleted::Yes);
241 assert_eq!(ok.unwrap().len(), 0);
242 assert_eq!(err.len(), 0);
244 let Outcome { completed: ok, errors: err, .. } =
245 forest.process_obligations(&mut C(|obligation| {
247 "A.1" => ProcessResult::Changed(vec!["D"]),
248 "A.2" => ProcessResult::Changed(vec!["D"]),
251 }, |_|{}), DoCompleted::Yes);
252 assert_eq!(ok.unwrap().len(), 0);
253 assert_eq!(err.len(), 0);
256 let Outcome { completed: ok, errors: err, .. } =
257 forest.process_obligations(&mut C(|obligation| {
259 "D" => { d_count += 1; ProcessResult::Changed(vec![]) },
262 }, |_|{}), DoCompleted::Yes);
263 assert_eq!(d_count, 1);
264 assert_eq!(ok.unwrap(), vec!["D", "A.2", "A.1", "A"]);
265 assert_eq!(err.len(), 0);
267 let errors = forest.to_errors(());
268 assert_eq!(errors.len(), 0);
270 forest.register_obligation("A'");
271 let Outcome { completed: ok, errors: err, .. } =
272 forest.process_obligations(&mut C(|obligation| {
274 "A'" => ProcessResult::Changed(vec!["A'.1", "A'.2"]),
277 }, |_|{}), DoCompleted::Yes);
278 assert_eq!(ok.unwrap().len(), 0);
279 assert_eq!(err.len(), 0);
281 let Outcome { completed: ok, errors: err, .. } =
282 forest.process_obligations(&mut C(|obligation| {
284 "A'.1" => ProcessResult::Changed(vec!["D'", "A'"]),
285 "A'.2" => ProcessResult::Changed(vec!["D'"]),
288 }, |_|{}), DoCompleted::Yes);
289 assert_eq!(ok.unwrap().len(), 0);
290 assert_eq!(err.len(), 0);
293 let Outcome { completed: ok, errors: err, .. } =
294 forest.process_obligations(&mut C(|obligation| {
296 "D'" => { d_count += 1; ProcessResult::Error("operation failed") },
299 }, |_|{}), DoCompleted::Yes);
300 assert_eq!(d_count, 1);
301 assert_eq!(ok.unwrap().len(), 0);
302 assert_eq!(err, vec![super::Error {
303 error: "operation failed",
304 backtrace: vec!["D'", "A'.1", "A'"]
307 let errors = forest.to_errors(());
308 assert_eq!(errors.len(), 0);
312 fn done_dependency() {
313 // check that the local cache works
314 let mut forest = ObligationForest::new();
315 forest.register_obligation("A: Sized");
316 forest.register_obligation("B: Sized");
317 forest.register_obligation("C: Sized");
319 let Outcome { completed: ok, errors: err, .. } =
320 forest.process_obligations(&mut C(|obligation| {
322 "A: Sized" | "B: Sized" | "C: Sized" => ProcessResult::Changed(vec![]),
325 }, |_|{}), DoCompleted::Yes);
326 assert_eq!(ok.unwrap(), vec!["C: Sized", "B: Sized", "A: Sized"]);
327 assert_eq!(err.len(), 0);
329 forest.register_obligation("(A,B,C): Sized");
330 let Outcome { completed: ok, errors: err, .. } =
331 forest.process_obligations(&mut C(|obligation| {
333 "(A,B,C): Sized" => ProcessResult::Changed(vec![
340 }, |_|{}), DoCompleted::Yes);
341 assert_eq!(ok.unwrap(), vec!["(A,B,C): Sized"]);
342 assert_eq!(err.len(), 0);
347 // check that orphaned nodes are handled correctly
348 let mut forest = ObligationForest::new();
349 forest.register_obligation("A");
350 forest.register_obligation("B");
351 forest.register_obligation("C1");
352 forest.register_obligation("C2");
354 let Outcome { completed: ok, errors: err, .. } =
355 forest.process_obligations(&mut C(|obligation| {
357 "A" => ProcessResult::Changed(vec!["D", "E"]),
358 "B" => ProcessResult::Unchanged,
359 "C1" => ProcessResult::Changed(vec![]),
360 "C2" => ProcessResult::Changed(vec![]),
363 }, |_|{}), DoCompleted::Yes);
364 assert_eq!(ok.unwrap(), vec!["C2", "C1"]);
365 assert_eq!(err.len(), 0);
367 let Outcome { completed: ok, errors: err, .. } =
368 forest.process_obligations(&mut C(|obligation| {
370 "D" | "E" => ProcessResult::Unchanged,
371 "B" => ProcessResult::Changed(vec!["D"]),
374 }, |_|{}), DoCompleted::Yes);
375 assert_eq!(ok.unwrap().len(), 0);
376 assert_eq!(err.len(), 0);
378 let Outcome { completed: ok, errors: err, .. } =
379 forest.process_obligations(&mut C(|obligation| {
381 "D" => ProcessResult::Unchanged,
382 "E" => ProcessResult::Error("E is for error"),
385 }, |_|{}), DoCompleted::Yes);
386 assert_eq!(ok.unwrap().len(), 0);
387 assert_eq!(err, vec![super::Error {
388 error: "E is for error",
389 backtrace: vec!["E", "A"]
392 let Outcome { completed: ok, errors: err, .. } =
393 forest.process_obligations(&mut C(|obligation| {
395 "D" => ProcessResult::Error("D is dead"),
398 }, |_|{}), DoCompleted::Yes);
399 assert_eq!(ok.unwrap().len(), 0);
400 assert_eq!(err, vec![super::Error {
405 let errors = forest.to_errors(());
406 assert_eq!(errors.len(), 0);
410 fn simultaneous_register_and_error() {
411 // check that registering a failed obligation works correctly
412 let mut forest = ObligationForest::new();
413 forest.register_obligation("A");
414 forest.register_obligation("B");
416 let Outcome { completed: ok, errors: err, .. } =
417 forest.process_obligations(&mut C(|obligation| {
419 "A" => ProcessResult::Error("An error"),
420 "B" => ProcessResult::Changed(vec!["A"]),
423 }, |_|{}), DoCompleted::Yes);
424 assert_eq!(ok.unwrap().len(), 0);
425 assert_eq!(err, vec![super::Error {
430 let mut forest = ObligationForest::new();
431 forest.register_obligation("B");
432 forest.register_obligation("A");
434 let Outcome { completed: ok, errors: err, .. } =
435 forest.process_obligations(&mut C(|obligation| {
437 "A" => ProcessResult::Error("An error"),
438 "B" => ProcessResult::Changed(vec!["A"]),
441 }, |_|{}), DoCompleted::Yes);
442 assert_eq!(ok.unwrap().len(), 0);
443 assert_eq!(err, vec![super::Error {