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![]),
73 "A.1" | "A.2" | "A.3" => ProcessResult::Unchanged,
76 }, |_| {}), DoCompleted::Yes);
77 assert_eq!(ok.unwrap(), vec!["C"]);
80 error: "B is for broken",
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, .. } =
92 forest.process_obligations(&mut C(|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,
101 }, |_| {}), DoCompleted::Yes);
102 assert_eq!(ok.unwrap(), Vec::<&'static str>::new());
103 assert_eq!(err, Vec::new());
106 // third round: ok in A.1 but trigger an error in A.2. Check that it
107 // propagates to A, but not D.1 or D.2.
108 // D |-> D.1 |-> D.1.i
110 let Outcome { completed: ok, errors: err, .. } =
111 forest.process_obligations(&mut C(|obligation| {
113 "A.1" => ProcessResult::Changed(vec![]),
114 "A.2" => ProcessResult::Error("A is for apple"),
115 "A.3.i" => ProcessResult::Changed(vec![]),
116 "D.1" => ProcessResult::Changed(vec!["D.1.i"]),
117 "D.2" => ProcessResult::Changed(vec!["D.2.i"]),
118 "D.1.i" | "D.2.i" => ProcessResult::Unchanged,
121 }, |_| {}), DoCompleted::Yes);
122 let mut ok = ok.unwrap();
124 assert_eq!(ok, vec!["A.1", "A.3", "A.3.i"]);
127 error: "A is for apple",
128 backtrace: vec!["A.2", "A"],
131 // fourth round: error in D.1.i
132 let Outcome { completed: ok, errors: err, .. } =
133 forest.process_obligations(&mut C(|obligation| {
135 "D.1.i" => ProcessResult::Error("D is for dumb"),
136 "D.2.i" => ProcessResult::Changed(vec![]),
137 _ => panic!("unexpected obligation {:?}", obligation),
139 }, |_| {}), DoCompleted::Yes);
140 let mut ok = ok.unwrap();
142 assert_eq!(ok, vec!["D.2", "D.2.i"]);
145 error: "D is for dumb",
146 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, .. } =
164 forest.process_obligations(&mut C(|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,
173 }, |_| {}), DoCompleted::Yes);
174 let mut ok = ok.unwrap();
176 assert_eq!(ok, vec!["A.1", "A.3"]);
177 assert!(err.is_empty());
179 let Outcome { completed: ok, errors: err, .. } =
180 forest.process_obligations(&mut C(|obligation| {
182 "A.2.i" => ProcessResult::Unchanged,
183 "A.2.ii" => ProcessResult::Changed(vec![]),
186 }, |_| {}), DoCompleted::Yes);
187 assert_eq!(ok.unwrap(), vec!["A.2.ii"]);
188 assert!(err.is_empty());
190 let Outcome { completed: ok, errors: err, .. } =
191 forest.process_obligations(&mut C(|obligation| {
193 "A.2.i" => ProcessResult::Changed(vec!["A.2.i.a"]),
194 "A.2.i.a" => ProcessResult::Unchanged,
197 }, |_| {}), DoCompleted::Yes);
198 assert!(ok.unwrap().is_empty());
199 assert!(err.is_empty());
201 let Outcome { completed: ok, errors: err, .. } =
202 forest.process_obligations(&mut C(|obligation| {
204 "A.2.i.a" => ProcessResult::Changed(vec![]),
207 }, |_| {}), DoCompleted::Yes);
208 let mut ok = ok.unwrap();
210 assert_eq!(ok, vec!["A", "A.2", "A.2.i", "A.2.i.a"]);
211 assert!(err.is_empty());
213 let Outcome { completed: ok, errors: err, .. } =
214 forest.process_obligations(&mut C(|_| unreachable!(), |_| {}),
217 assert!(ok.unwrap().is_empty());
218 assert!(err.is_empty());
222 fn to_errors_no_throw() {
223 // check that converting multiple children with common parent (A)
224 // yields to correct errors (and does not panic, in particular).
225 let mut forest = ObligationForest::new();
226 forest.register_obligation("A");
227 let Outcome { completed: ok, errors: err, .. } =
228 forest.process_obligations(&mut C(|obligation| {
230 "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
231 "A.1" | "A.2" | "A.3" => ProcessResult::Unchanged,
234 }, |_|{}), DoCompleted::Yes);
235 assert_eq!(ok.unwrap().len(), 0);
236 assert_eq!(err.len(), 0);
237 let errors = forest.to_errors(());
238 assert_eq!(errors[0].backtrace, vec!["A.1", "A"]);
239 assert_eq!(errors[1].backtrace, vec!["A.2", "A"]);
240 assert_eq!(errors[2].backtrace, vec!["A.3", "A"]);
241 assert_eq!(errors.len(), 3);
246 // check that diamond dependencies are handled correctly
247 let mut forest = ObligationForest::new();
248 forest.register_obligation("A");
249 let Outcome { completed: ok, errors: err, .. } =
250 forest.process_obligations(&mut C(|obligation| {
252 "A" => ProcessResult::Changed(vec!["A.1", "A.2"]),
253 "A.1" | "A.2" => ProcessResult::Unchanged,
256 }, |_|{}), DoCompleted::Yes);
257 assert_eq!(ok.unwrap().len(), 0);
258 assert_eq!(err.len(), 0);
260 let Outcome { completed: ok, errors: err, .. } =
261 forest.process_obligations(&mut C(|obligation| {
263 "A.1" => ProcessResult::Changed(vec!["D"]),
264 "A.2" => ProcessResult::Changed(vec!["D"]),
265 "D" => ProcessResult::Unchanged,
268 }, |_|{}), DoCompleted::Yes);
269 assert_eq!(ok.unwrap().len(), 0);
270 assert_eq!(err.len(), 0);
273 let Outcome { completed: ok, errors: err, .. } =
274 forest.process_obligations(&mut C(|obligation| {
276 "D" => { d_count += 1; ProcessResult::Changed(vec![]) },
279 }, |_|{}), DoCompleted::Yes);
280 assert_eq!(d_count, 1);
281 let mut ok = ok.unwrap();
283 assert_eq!(ok, vec!["A", "A.1", "A.2", "D"]);
284 assert_eq!(err.len(), 0);
286 let errors = forest.to_errors(());
287 assert_eq!(errors.len(), 0);
289 forest.register_obligation("A'");
290 let Outcome { completed: ok, errors: err, .. } =
291 forest.process_obligations(&mut C(|obligation| {
293 "A'" => ProcessResult::Changed(vec!["A'.1", "A'.2"]),
294 "A'.1" | "A'.2" => ProcessResult::Unchanged,
297 }, |_|{}), DoCompleted::Yes);
298 assert_eq!(ok.unwrap().len(), 0);
299 assert_eq!(err.len(), 0);
301 let Outcome { completed: ok, errors: err, .. } =
302 forest.process_obligations(&mut C(|obligation| {
304 "A'.1" => ProcessResult::Changed(vec!["D'", "A'"]),
305 "A'.2" => ProcessResult::Changed(vec!["D'"]),
306 "D'" | "A'" => ProcessResult::Unchanged,
309 }, |_|{}), DoCompleted::Yes);
310 assert_eq!(ok.unwrap().len(), 0);
311 assert_eq!(err.len(), 0);
314 let Outcome { completed: ok, errors: err, .. } =
315 forest.process_obligations(&mut C(|obligation| {
317 "D'" => { d_count += 1; ProcessResult::Error("operation failed") },
320 }, |_|{}), DoCompleted::Yes);
321 assert_eq!(d_count, 1);
322 assert_eq!(ok.unwrap().len(), 0);
323 assert_eq!(err, vec![super::Error {
324 error: "operation failed",
325 backtrace: vec!["D'", "A'.1", "A'"]
328 let errors = forest.to_errors(());
329 assert_eq!(errors.len(), 0);
333 fn done_dependency() {
334 // check that the local cache works
335 let mut forest = ObligationForest::new();
336 forest.register_obligation("A: Sized");
337 forest.register_obligation("B: Sized");
338 forest.register_obligation("C: Sized");
340 let Outcome { completed: ok, errors: err, .. } =
341 forest.process_obligations(&mut C(|obligation| {
343 "A: Sized" | "B: Sized" | "C: Sized" => ProcessResult::Changed(vec![]),
346 }, |_|{}), DoCompleted::Yes);
347 let mut ok = ok.unwrap();
349 assert_eq!(ok, vec!["A: Sized", "B: Sized", "C: Sized"]);
350 assert_eq!(err.len(), 0);
352 forest.register_obligation("(A,B,C): Sized");
353 let Outcome { completed: ok, errors: err, .. } =
354 forest.process_obligations(&mut C(|obligation| {
356 "(A,B,C): Sized" => ProcessResult::Changed(vec![
363 }, |_|{}), DoCompleted::Yes);
364 assert_eq!(ok.unwrap(), vec!["(A,B,C): Sized"]);
365 assert_eq!(err.len(), 0);
370 // check that orphaned nodes are handled correctly
371 let mut forest = ObligationForest::new();
372 forest.register_obligation("A");
373 forest.register_obligation("B");
374 forest.register_obligation("C1");
375 forest.register_obligation("C2");
377 let Outcome { completed: ok, errors: err, .. } =
378 forest.process_obligations(&mut C(|obligation| {
380 "A" => ProcessResult::Changed(vec!["D", "E"]),
381 "B" => ProcessResult::Unchanged,
382 "C1" => ProcessResult::Changed(vec![]),
383 "C2" => ProcessResult::Changed(vec![]),
384 "D" | "E" => ProcessResult::Unchanged,
387 }, |_|{}), DoCompleted::Yes);
388 let mut ok = ok.unwrap();
390 assert_eq!(ok, vec!["C1", "C2"]);
391 assert_eq!(err.len(), 0);
393 let Outcome { completed: ok, errors: err, .. } =
394 forest.process_obligations(&mut C(|obligation| {
396 "D" | "E" => ProcessResult::Unchanged,
397 "B" => ProcessResult::Changed(vec!["D"]),
400 }, |_|{}), DoCompleted::Yes);
401 assert_eq!(ok.unwrap().len(), 0);
402 assert_eq!(err.len(), 0);
404 let Outcome { completed: ok, errors: err, .. } =
405 forest.process_obligations(&mut C(|obligation| {
407 "D" => ProcessResult::Unchanged,
408 "E" => ProcessResult::Error("E is for error"),
411 }, |_|{}), DoCompleted::Yes);
412 assert_eq!(ok.unwrap().len(), 0);
413 assert_eq!(err, vec![super::Error {
414 error: "E is for error",
415 backtrace: vec!["E", "A"]
418 let Outcome { completed: ok, errors: err, .. } =
419 forest.process_obligations(&mut C(|obligation| {
421 "D" => ProcessResult::Error("D is dead"),
424 }, |_|{}), DoCompleted::Yes);
425 assert_eq!(ok.unwrap().len(), 0);
426 assert_eq!(err, vec![super::Error {
431 let errors = forest.to_errors(());
432 assert_eq!(errors.len(), 0);
436 fn simultaneous_register_and_error() {
437 // check that registering a failed obligation works correctly
438 let mut forest = ObligationForest::new();
439 forest.register_obligation("A");
440 forest.register_obligation("B");
442 let Outcome { completed: ok, errors: err, .. } =
443 forest.process_obligations(&mut C(|obligation| {
445 "A" => ProcessResult::Error("An error"),
446 "B" => ProcessResult::Changed(vec!["A"]),
449 }, |_|{}), DoCompleted::Yes);
450 assert_eq!(ok.unwrap().len(), 0);
451 assert_eq!(err, vec![super::Error {
456 let mut forest = ObligationForest::new();
457 forest.register_obligation("B");
458 forest.register_obligation("A");
460 let Outcome { completed: ok, errors: err, .. } =
461 forest.process_obligations(&mut C(|obligation| {
463 "A" => ProcessResult::Error("An error"),
464 "B" => ProcessResult::Changed(vec!["A"]),
467 }, |_|{}), DoCompleted::Yes);
468 assert_eq!(ok.unwrap().len(), 0);
469 assert_eq!(err, vec![super::Error {