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 let mut ok = ok.unwrap();
121 assert_eq!(ok, vec!["A.1", "A.3", "A.3.i"]);
124 error: "A is for apple",
125 backtrace: vec!["A.2", "A"],
128 // fourth round: error in D.1.i
129 let Outcome { completed: ok, errors: err, .. } =
130 forest.process_obligations(&mut C(|obligation| {
132 "D.1.i" => ProcessResult::Error("D is for dumb"),
133 "D.2.i" => ProcessResult::Changed(vec![]),
134 _ => panic!("unexpected obligation {:?}", obligation),
136 }, |_| {}), DoCompleted::Yes);
137 let mut ok = ok.unwrap();
139 assert_eq!(ok, vec!["D.2", "D.2.i"]);
142 error: "D is for dumb",
143 backtrace: vec!["D.1.i", "D.1", "D"],
147 // Test that if a tree with grandchildren succeeds, everything is
148 // reported as expected:
156 fn success_in_grandchildren() {
157 let mut forest = ObligationForest::new();
158 forest.register_obligation("A");
160 let Outcome { completed: ok, errors: err, .. } =
161 forest.process_obligations(&mut C(|obligation| {
163 "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
166 }, |_| {}), DoCompleted::Yes);
167 assert!(ok.unwrap().is_empty());
168 assert!(err.is_empty());
170 let Outcome { completed: ok, errors: err, .. } =
171 forest.process_obligations(&mut C(|obligation| {
173 "A.1" => ProcessResult::Changed(vec![]),
174 "A.2" => ProcessResult::Changed(vec!["A.2.i", "A.2.ii"]),
175 "A.3" => ProcessResult::Changed(vec![]),
178 }, |_| {}), DoCompleted::Yes);
179 let mut ok = ok.unwrap();
181 assert_eq!(ok, vec!["A.1", "A.3"]);
182 assert!(err.is_empty());
184 let Outcome { completed: ok, errors: err, .. } =
185 forest.process_obligations(&mut C(|obligation| {
187 "A.2.i" => ProcessResult::Changed(vec!["A.2.i.a"]),
188 "A.2.ii" => ProcessResult::Changed(vec![]),
191 }, |_| {}), DoCompleted::Yes);
192 assert_eq!(ok.unwrap(), vec!["A.2.ii"]);
193 assert!(err.is_empty());
195 let Outcome { completed: ok, errors: err, .. } =
196 forest.process_obligations(&mut C(|obligation| {
198 "A.2.i.a" => ProcessResult::Changed(vec![]),
201 }, |_| {}), DoCompleted::Yes);
202 let mut ok = ok.unwrap();
204 assert_eq!(ok, vec!["A", "A.2", "A.2.i", "A.2.i.a"]);
205 assert!(err.is_empty());
207 let Outcome { completed: ok, errors: err, .. } =
208 forest.process_obligations(&mut C(|_| unreachable!(), |_| {}),
211 assert!(ok.unwrap().is_empty());
212 assert!(err.is_empty());
216 fn to_errors_no_throw() {
217 // check that converting multiple children with common parent (A)
218 // yields to correct errors (and does not panic, in particular).
219 let mut forest = ObligationForest::new();
220 forest.register_obligation("A");
221 let Outcome { completed: ok, errors: err, .. } =
222 forest.process_obligations(&mut C(|obligation| {
224 "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
227 }, |_|{}), DoCompleted::Yes);
228 assert_eq!(ok.unwrap().len(), 0);
229 assert_eq!(err.len(), 0);
230 let errors = forest.to_errors(());
231 assert_eq!(errors[0].backtrace, vec!["A.1", "A"]);
232 assert_eq!(errors[1].backtrace, vec!["A.2", "A"]);
233 assert_eq!(errors[2].backtrace, vec!["A.3", "A"]);
234 assert_eq!(errors.len(), 3);
239 // check that diamond dependencies are handled correctly
240 let mut forest = ObligationForest::new();
241 forest.register_obligation("A");
242 let Outcome { completed: ok, errors: err, .. } =
243 forest.process_obligations(&mut C(|obligation| {
245 "A" => ProcessResult::Changed(vec!["A.1", "A.2"]),
248 }, |_|{}), DoCompleted::Yes);
249 assert_eq!(ok.unwrap().len(), 0);
250 assert_eq!(err.len(), 0);
252 let Outcome { completed: ok, errors: err, .. } =
253 forest.process_obligations(&mut C(|obligation| {
255 "A.1" => ProcessResult::Changed(vec!["D"]),
256 "A.2" => ProcessResult::Changed(vec!["D"]),
259 }, |_|{}), DoCompleted::Yes);
260 assert_eq!(ok.unwrap().len(), 0);
261 assert_eq!(err.len(), 0);
264 let Outcome { completed: ok, errors: err, .. } =
265 forest.process_obligations(&mut C(|obligation| {
267 "D" => { d_count += 1; ProcessResult::Changed(vec![]) },
270 }, |_|{}), DoCompleted::Yes);
271 assert_eq!(d_count, 1);
272 let mut ok = ok.unwrap();
274 assert_eq!(ok, vec!["A", "A.1", "A.2", "D"]);
275 assert_eq!(err.len(), 0);
277 let errors = forest.to_errors(());
278 assert_eq!(errors.len(), 0);
280 forest.register_obligation("A'");
281 let Outcome { completed: ok, errors: err, .. } =
282 forest.process_obligations(&mut C(|obligation| {
284 "A'" => ProcessResult::Changed(vec!["A'.1", "A'.2"]),
287 }, |_|{}), DoCompleted::Yes);
288 assert_eq!(ok.unwrap().len(), 0);
289 assert_eq!(err.len(), 0);
291 let Outcome { completed: ok, errors: err, .. } =
292 forest.process_obligations(&mut C(|obligation| {
294 "A'.1" => ProcessResult::Changed(vec!["D'", "A'"]),
295 "A'.2" => ProcessResult::Changed(vec!["D'"]),
298 }, |_|{}), DoCompleted::Yes);
299 assert_eq!(ok.unwrap().len(), 0);
300 assert_eq!(err.len(), 0);
303 let Outcome { completed: ok, errors: err, .. } =
304 forest.process_obligations(&mut C(|obligation| {
306 "D'" => { d_count += 1; ProcessResult::Error("operation failed") },
309 }, |_|{}), DoCompleted::Yes);
310 assert_eq!(d_count, 1);
311 assert_eq!(ok.unwrap().len(), 0);
312 assert_eq!(err, vec![super::Error {
313 error: "operation failed",
314 backtrace: vec!["D'", "A'.1", "A'"]
317 let errors = forest.to_errors(());
318 assert_eq!(errors.len(), 0);
322 fn done_dependency() {
323 // check that the local cache works
324 let mut forest = ObligationForest::new();
325 forest.register_obligation("A: Sized");
326 forest.register_obligation("B: Sized");
327 forest.register_obligation("C: Sized");
329 let Outcome { completed: ok, errors: err, .. } =
330 forest.process_obligations(&mut C(|obligation| {
332 "A: Sized" | "B: Sized" | "C: Sized" => ProcessResult::Changed(vec![]),
335 }, |_|{}), DoCompleted::Yes);
336 let mut ok = ok.unwrap();
338 assert_eq!(ok, vec!["A: Sized", "B: Sized", "C: Sized"]);
339 assert_eq!(err.len(), 0);
341 forest.register_obligation("(A,B,C): Sized");
342 let Outcome { completed: ok, errors: err, .. } =
343 forest.process_obligations(&mut C(|obligation| {
345 "(A,B,C): Sized" => ProcessResult::Changed(vec![
352 }, |_|{}), DoCompleted::Yes);
353 assert_eq!(ok.unwrap(), vec!["(A,B,C): Sized"]);
354 assert_eq!(err.len(), 0);
359 // check that orphaned nodes are handled correctly
360 let mut forest = ObligationForest::new();
361 forest.register_obligation("A");
362 forest.register_obligation("B");
363 forest.register_obligation("C1");
364 forest.register_obligation("C2");
366 let Outcome { completed: ok, errors: err, .. } =
367 forest.process_obligations(&mut C(|obligation| {
369 "A" => ProcessResult::Changed(vec!["D", "E"]),
370 "B" => ProcessResult::Unchanged,
371 "C1" => ProcessResult::Changed(vec![]),
372 "C2" => ProcessResult::Changed(vec![]),
375 }, |_|{}), DoCompleted::Yes);
376 let mut ok = ok.unwrap();
378 assert_eq!(ok, vec!["C1", "C2"]);
379 assert_eq!(err.len(), 0);
381 let Outcome { completed: ok, errors: err, .. } =
382 forest.process_obligations(&mut C(|obligation| {
384 "D" | "E" => ProcessResult::Unchanged,
385 "B" => ProcessResult::Changed(vec!["D"]),
388 }, |_|{}), DoCompleted::Yes);
389 assert_eq!(ok.unwrap().len(), 0);
390 assert_eq!(err.len(), 0);
392 let Outcome { completed: ok, errors: err, .. } =
393 forest.process_obligations(&mut C(|obligation| {
395 "D" => ProcessResult::Unchanged,
396 "E" => ProcessResult::Error("E is for error"),
399 }, |_|{}), DoCompleted::Yes);
400 assert_eq!(ok.unwrap().len(), 0);
401 assert_eq!(err, vec![super::Error {
402 error: "E is for error",
403 backtrace: vec!["E", "A"]
406 let Outcome { completed: ok, errors: err, .. } =
407 forest.process_obligations(&mut C(|obligation| {
409 "D" => ProcessResult::Error("D is dead"),
412 }, |_|{}), DoCompleted::Yes);
413 assert_eq!(ok.unwrap().len(), 0);
414 assert_eq!(err, vec![super::Error {
419 let errors = forest.to_errors(());
420 assert_eq!(errors.len(), 0);
424 fn simultaneous_register_and_error() {
425 // check that registering a failed obligation works correctly
426 let mut forest = ObligationForest::new();
427 forest.register_obligation("A");
428 forest.register_obligation("B");
430 let Outcome { completed: ok, errors: err, .. } =
431 forest.process_obligations(&mut C(|obligation| {
433 "A" => ProcessResult::Error("An error"),
434 "B" => ProcessResult::Changed(vec!["A"]),
437 }, |_|{}), DoCompleted::Yes);
438 assert_eq!(ok.unwrap().len(), 0);
439 assert_eq!(err, vec![super::Error {
444 let mut forest = ObligationForest::new();
445 forest.register_obligation("B");
446 forest.register_obligation("A");
448 let Outcome { completed: ok, errors: err, .. } =
449 forest.process_obligations(&mut C(|obligation| {
451 "A" => ProcessResult::Error("An error"),
452 "B" => ProcessResult::Changed(vec!["A"]),
455 }, |_|{}), DoCompleted::Yes);
456 assert_eq!(ok.unwrap().len(), 0);
457 assert_eq!(err, vec![super::Error {