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>
23 OF: FnMut(&mut O) -> ProcessResult<O, &'static str>,
26 ClosureObligationProcessor {
27 process_obligation: of,
28 _process_backedge: bf,
33 impl<OF, BF, O, E> ObligationProcessor for ClosureObligationProcessor<OF, BF, O, E>
35 O: super::ForestObligation + fmt::Debug,
37 OF: FnMut(&mut O) -> ProcessResult<O, E>,
43 fn process_obligation(
45 obligation: &mut Self::Obligation,
46 ) -> ProcessResult<Self::Obligation, Self::Error> {
47 (self.process_obligation)(obligation)
50 fn process_backedge<'c, I>(&mut self, _cycle: I, _marker: PhantomData<&'c Self::Obligation>)
52 I: Clone + Iterator<Item = &'c Self::Obligation>,
59 let mut forest = ObligationForest::new();
60 forest.register_obligation("A");
61 forest.register_obligation("B");
62 forest.register_obligation("C");
64 // first round, B errors out, A has subtasks, and C completes, creating this:
68 let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
70 |obligation| match *obligation {
71 "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
72 "B" => ProcessResult::Error("B is for broken"),
73 "C" => ProcessResult::Changed(vec![]),
74 "A.1" | "A.2" | "A.3" => ProcessResult::Unchanged,
81 assert_eq!(ok.unwrap(), vec!["C"]);
82 assert_eq!(err, vec![Error { error: "B is for broken", backtrace: vec!["B"] }]);
84 // second round: two delays, one success, creating an uneven set of subtasks:
90 forest.register_obligation("D");
91 let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
93 |obligation| match *obligation {
94 "A.1" => ProcessResult::Unchanged,
95 "A.2" => ProcessResult::Unchanged,
96 "A.3" => ProcessResult::Changed(vec!["A.3.i"]),
97 "D" => ProcessResult::Changed(vec!["D.1", "D.2"]),
98 "A.3.i" | "D.1" | "D.2" => ProcessResult::Unchanged,
105 assert_eq!(ok.unwrap(), Vec::<&'static str>::new());
106 assert_eq!(err, Vec::new());
108 // third round: ok in A.1 but trigger an error in A.2. Check that it
109 // propagates to A, but not D.1 or D.2.
110 // D |-> D.1 |-> D.1.i
112 let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
114 |obligation| match *obligation {
115 "A.1" => ProcessResult::Changed(vec![]),
116 "A.2" => ProcessResult::Error("A is for apple"),
117 "A.3.i" => ProcessResult::Changed(vec![]),
118 "D.1" => ProcessResult::Changed(vec!["D.1.i"]),
119 "D.2" => ProcessResult::Changed(vec!["D.2.i"]),
120 "D.1.i" | "D.2.i" => ProcessResult::Unchanged,
127 let mut ok = ok.unwrap();
129 assert_eq!(ok, vec!["A.1", "A.3", "A.3.i"]);
130 assert_eq!(err, vec![Error { error: "A is for apple", backtrace: vec!["A.2", "A"] }]);
132 // fourth round: error in D.1.i
133 let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
135 |obligation| match *obligation {
136 "D.1.i" => ProcessResult::Error("D is for dumb"),
137 "D.2.i" => ProcessResult::Changed(vec![]),
138 _ => panic!("unexpected obligation {:?}", obligation),
144 let mut ok = ok.unwrap();
146 assert_eq!(ok, vec!["D.2", "D.2.i"]);
147 assert_eq!(err, vec![Error { error: "D is for dumb", backtrace: vec!["D.1.i", "D.1", "D"] }]);
150 // Test that if a tree with grandchildren succeeds, everything is
151 // reported as expected:
159 fn success_in_grandchildren() {
160 let mut forest = ObligationForest::new();
161 forest.register_obligation("A");
163 let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
165 |obligation| match *obligation {
166 "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
167 "A.1" => ProcessResult::Changed(vec![]),
168 "A.2" => ProcessResult::Changed(vec!["A.2.i", "A.2.ii"]),
169 "A.3" => ProcessResult::Changed(vec![]),
170 "A.2.i" | "A.2.ii" => ProcessResult::Unchanged,
177 let mut ok = ok.unwrap();
179 assert_eq!(ok, vec!["A.1", "A.3"]);
180 assert!(err.is_empty());
182 let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
184 |obligation| match *obligation {
185 "A.2.i" => ProcessResult::Unchanged,
186 "A.2.ii" => ProcessResult::Changed(vec![]),
193 assert_eq!(ok.unwrap(), vec!["A.2.ii"]);
194 assert!(err.is_empty());
196 let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
198 |obligation| match *obligation {
199 "A.2.i" => ProcessResult::Changed(vec!["A.2.i.a"]),
200 "A.2.i.a" => ProcessResult::Unchanged,
207 assert!(ok.unwrap().is_empty());
208 assert!(err.is_empty());
210 let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
212 |obligation| match *obligation {
213 "A.2.i.a" => ProcessResult::Changed(vec![]),
220 let mut ok = ok.unwrap();
222 assert_eq!(ok, vec!["A", "A.2", "A.2.i", "A.2.i.a"]);
223 assert!(err.is_empty());
225 let Outcome { completed: ok, errors: err, .. } =
226 forest.process_obligations(&mut C(|_| unreachable!(), |_| {}), DoCompleted::Yes);
228 assert!(ok.unwrap().is_empty());
229 assert!(err.is_empty());
233 fn to_errors_no_throw() {
234 // check that converting multiple children with common parent (A)
235 // yields to correct errors (and does not panic, in particular).
236 let mut forest = ObligationForest::new();
237 forest.register_obligation("A");
238 let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
240 |obligation| match *obligation {
241 "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
242 "A.1" | "A.2" | "A.3" => ProcessResult::Unchanged,
249 assert_eq!(ok.unwrap().len(), 0);
250 assert_eq!(err.len(), 0);
251 let errors = forest.to_errors(());
252 assert_eq!(errors[0].backtrace, vec!["A.1", "A"]);
253 assert_eq!(errors[1].backtrace, vec!["A.2", "A"]);
254 assert_eq!(errors[2].backtrace, vec!["A.3", "A"]);
255 assert_eq!(errors.len(), 3);
260 // check that diamond dependencies are handled correctly
261 let mut forest = ObligationForest::new();
262 forest.register_obligation("A");
263 let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
265 |obligation| match *obligation {
266 "A" => ProcessResult::Changed(vec!["A.1", "A.2"]),
267 "A.1" | "A.2" => ProcessResult::Unchanged,
274 assert_eq!(ok.unwrap().len(), 0);
275 assert_eq!(err.len(), 0);
277 let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
279 |obligation| match *obligation {
280 "A.1" => ProcessResult::Changed(vec!["D"]),
281 "A.2" => ProcessResult::Changed(vec!["D"]),
282 "D" => ProcessResult::Unchanged,
289 assert_eq!(ok.unwrap().len(), 0);
290 assert_eq!(err.len(), 0);
293 let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
295 |obligation| match *obligation {
298 ProcessResult::Changed(vec![])
306 assert_eq!(d_count, 1);
307 let mut ok = ok.unwrap();
309 assert_eq!(ok, vec!["A", "A.1", "A.2", "D"]);
310 assert_eq!(err.len(), 0);
312 let errors = forest.to_errors(());
313 assert_eq!(errors.len(), 0);
315 forest.register_obligation("A'");
316 let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
318 |obligation| match *obligation {
319 "A'" => ProcessResult::Changed(vec!["A'.1", "A'.2"]),
320 "A'.1" | "A'.2" => ProcessResult::Unchanged,
327 assert_eq!(ok.unwrap().len(), 0);
328 assert_eq!(err.len(), 0);
330 let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
332 |obligation| match *obligation {
333 "A'.1" => ProcessResult::Changed(vec!["D'", "A'"]),
334 "A'.2" => ProcessResult::Changed(vec!["D'"]),
335 "D'" | "A'" => ProcessResult::Unchanged,
342 assert_eq!(ok.unwrap().len(), 0);
343 assert_eq!(err.len(), 0);
346 let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
348 |obligation| match *obligation {
351 ProcessResult::Error("operation failed")
359 assert_eq!(d_count, 1);
360 assert_eq!(ok.unwrap().len(), 0);
363 vec![super::Error { error: "operation failed", backtrace: vec!["D'", "A'.1", "A'"] }]
366 let errors = forest.to_errors(());
367 assert_eq!(errors.len(), 0);
371 fn done_dependency() {
372 // check that the local cache works
373 let mut forest = ObligationForest::new();
374 forest.register_obligation("A: Sized");
375 forest.register_obligation("B: Sized");
376 forest.register_obligation("C: Sized");
378 let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
380 |obligation| match *obligation {
381 "A: Sized" | "B: Sized" | "C: Sized" => ProcessResult::Changed(vec![]),
388 let mut ok = ok.unwrap();
390 assert_eq!(ok, vec!["A: Sized", "B: Sized", "C: Sized"]);
391 assert_eq!(err.len(), 0);
393 forest.register_obligation("(A,B,C): Sized");
394 let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
396 |obligation| match *obligation {
397 "(A,B,C): Sized" => {
398 ProcessResult::Changed(vec!["A: Sized", "B: Sized", "C: Sized"])
406 assert_eq!(ok.unwrap(), vec!["(A,B,C): Sized"]);
407 assert_eq!(err.len(), 0);
412 // check that orphaned nodes are handled correctly
413 let mut forest = ObligationForest::new();
414 forest.register_obligation("A");
415 forest.register_obligation("B");
416 forest.register_obligation("C1");
417 forest.register_obligation("C2");
419 let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
421 |obligation| match *obligation {
422 "A" => ProcessResult::Changed(vec!["D", "E"]),
423 "B" => ProcessResult::Unchanged,
424 "C1" => ProcessResult::Changed(vec![]),
425 "C2" => ProcessResult::Changed(vec![]),
426 "D" | "E" => ProcessResult::Unchanged,
433 let mut ok = ok.unwrap();
435 assert_eq!(ok, vec!["C1", "C2"]);
436 assert_eq!(err.len(), 0);
438 let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
440 |obligation| match *obligation {
441 "D" | "E" => ProcessResult::Unchanged,
442 "B" => ProcessResult::Changed(vec!["D"]),
449 assert_eq!(ok.unwrap().len(), 0);
450 assert_eq!(err.len(), 0);
452 let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
454 |obligation| match *obligation {
455 "D" => ProcessResult::Unchanged,
456 "E" => ProcessResult::Error("E is for error"),
463 assert_eq!(ok.unwrap().len(), 0);
464 assert_eq!(err, vec![super::Error { error: "E is for error", backtrace: vec!["E", "A"] }]);
466 let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
468 |obligation| match *obligation {
469 "D" => ProcessResult::Error("D is dead"),
476 assert_eq!(ok.unwrap().len(), 0);
477 assert_eq!(err, vec![super::Error { error: "D is dead", backtrace: vec!["D"] }]);
479 let errors = forest.to_errors(());
480 assert_eq!(errors.len(), 0);
484 fn simultaneous_register_and_error() {
485 // check that registering a failed obligation works correctly
486 let mut forest = ObligationForest::new();
487 forest.register_obligation("A");
488 forest.register_obligation("B");
490 let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
492 |obligation| match *obligation {
493 "A" => ProcessResult::Error("An error"),
494 "B" => ProcessResult::Changed(vec!["A"]),
501 assert_eq!(ok.unwrap().len(), 0);
502 assert_eq!(err, vec![super::Error { error: "An error", backtrace: vec!["A"] }]);
504 let mut forest = ObligationForest::new();
505 forest.register_obligation("B");
506 forest.register_obligation("A");
508 let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
510 |obligation| match *obligation {
511 "A" => ProcessResult::Error("An error"),
512 "B" => ProcessResult::Changed(vec!["A"]),
519 assert_eq!(ok.unwrap().len(), 0);
520 assert_eq!(err, vec![super::Error { error: "An error", backtrace: vec!["A"] }]);