4 use std::marker::PhantomData;
6 impl<'a> super::ForestObligation for &'a str {
7 type CacheKey = &'a str;
9 fn as_cache_key(&self) -> Self::CacheKey {
14 struct ClosureObligationProcessor<OF, BF, O, E> {
15 process_obligation: OF,
16 _process_backedge: BF,
17 marker: PhantomData<(O, E)>,
20 struct TestOutcome<O, E> {
21 pub completed: Vec<O>,
22 pub errors: Vec<Error<O, E>>,
25 impl<O, E> OutcomeTrait for TestOutcome<O, E>
29 type Error = Error<O, E>;
33 Self { errors: vec![], completed: vec![] }
36 fn record_completed(&mut self, outcome: &Self::Obligation) {
37 self.completed.push(outcome.clone())
40 fn record_error(&mut self, error: Self::Error) {
41 self.errors.push(error)
45 #[allow(non_snake_case)]
46 fn C<OF, BF, O>(of: OF, bf: BF) -> ClosureObligationProcessor<OF, BF, O, &'static str>
48 OF: FnMut(&mut O) -> ProcessResult<O, &'static str>,
51 ClosureObligationProcessor {
52 process_obligation: of,
53 _process_backedge: bf,
58 impl<OF, BF, O, E> ObligationProcessor for ClosureObligationProcessor<OF, BF, O, E>
60 O: super::ForestObligation + fmt::Debug,
62 OF: FnMut(&mut O) -> ProcessResult<O, E>,
67 type OUT = TestOutcome<O, E>;
69 fn needs_process_obligation(&self, _obligation: &Self::Obligation) -> bool {
73 fn process_obligation(
75 obligation: &mut Self::Obligation,
76 ) -> ProcessResult<Self::Obligation, Self::Error> {
77 (self.process_obligation)(obligation)
80 fn process_backedge<'c, I>(
83 _marker: PhantomData<&'c Self::Obligation>,
84 ) -> Result<(), Self::Error>
86 I: Clone + Iterator<Item = &'c Self::Obligation>,
94 let mut forest = ObligationForest::new();
95 forest.register_obligation("A");
96 forest.register_obligation("B");
97 forest.register_obligation("C");
99 // first round, B errors out, A has subtasks, and C completes, creating this:
103 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
104 |obligation| match *obligation {
105 "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
106 "B" => ProcessResult::Error("B is for broken"),
107 "C" => ProcessResult::Changed(vec![]),
108 "A.1" | "A.2" | "A.3" => ProcessResult::Unchanged,
113 assert_eq!(ok, vec!["C"]);
114 assert_eq!(err, vec![Error { error: "B is for broken", backtrace: vec!["B"] }]);
116 // second round: two delays, one success, creating an uneven set of subtasks:
122 forest.register_obligation("D");
123 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
124 |obligation| match *obligation {
125 "A.1" => ProcessResult::Unchanged,
126 "A.2" => ProcessResult::Unchanged,
127 "A.3" => ProcessResult::Changed(vec!["A.3.i"]),
128 "D" => ProcessResult::Changed(vec!["D.1", "D.2"]),
129 "A.3.i" | "D.1" | "D.2" => ProcessResult::Unchanged,
134 assert_eq!(ok, Vec::<&'static str>::new());
135 assert_eq!(err, Vec::new());
137 // third round: ok in A.1 but trigger an error in A.2. Check that it
138 // propagates to A, but not D.1 or D.2.
139 // D |-> D.1 |-> D.1.i
141 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
142 |obligation| match *obligation {
143 "A.1" => ProcessResult::Changed(vec![]),
144 "A.2" => ProcessResult::Error("A is for apple"),
145 "A.3.i" => ProcessResult::Changed(vec![]),
146 "D.1" => ProcessResult::Changed(vec!["D.1.i"]),
147 "D.2" => ProcessResult::Changed(vec!["D.2.i"]),
148 "D.1.i" | "D.2.i" => ProcessResult::Unchanged,
155 assert_eq!(ok, vec!["A.1", "A.3", "A.3.i"]);
156 assert_eq!(err, vec![Error { error: "A is for apple", backtrace: vec!["A.2", "A"] }]);
158 // fourth round: error in D.1.i
159 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
160 |obligation| match *obligation {
161 "D.1.i" => ProcessResult::Error("D is for dumb"),
162 "D.2.i" => ProcessResult::Changed(vec![]),
163 _ => panic!("unexpected obligation {:?}", obligation),
169 assert_eq!(ok, vec!["D.2", "D.2.i"]);
170 assert_eq!(err, vec![Error { error: "D is for dumb", backtrace: vec!["D.1.i", "D.1", "D"] }]);
173 // Test that if a tree with grandchildren succeeds, everything is
174 // reported as expected:
182 fn success_in_grandchildren() {
183 let mut forest = ObligationForest::new();
184 forest.register_obligation("A");
186 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
187 |obligation| match *obligation {
188 "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
189 "A.1" => ProcessResult::Changed(vec![]),
190 "A.2" => ProcessResult::Changed(vec!["A.2.i", "A.2.ii"]),
191 "A.3" => ProcessResult::Changed(vec![]),
192 "A.2.i" | "A.2.ii" => ProcessResult::Unchanged,
199 assert_eq!(ok, vec!["A.1", "A.3"]);
200 assert!(err.is_empty());
202 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
203 |obligation| match *obligation {
204 "A.2.i" => ProcessResult::Unchanged,
205 "A.2.ii" => ProcessResult::Changed(vec![]),
210 assert_eq!(ok, vec!["A.2.ii"]);
211 assert!(err.is_empty());
213 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
214 |obligation| match *obligation {
215 "A.2.i" => ProcessResult::Changed(vec!["A.2.i.a"]),
216 "A.2.i.a" => ProcessResult::Unchanged,
221 assert!(ok.is_empty());
222 assert!(err.is_empty());
224 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
225 |obligation| match *obligation {
226 "A.2.i.a" => ProcessResult::Changed(vec![]),
233 assert_eq!(ok, vec!["A", "A.2", "A.2.i", "A.2.i.a"]);
234 assert!(err.is_empty());
236 let TestOutcome { completed: ok, errors: err, .. } =
237 forest.process_obligations(&mut C(|_| unreachable!(), |_| {}));
239 assert!(ok.is_empty());
240 assert!(err.is_empty());
244 fn to_errors_no_throw() {
245 // check that converting multiple children with common parent (A)
246 // yields to correct errors (and does not panic, in particular).
247 let mut forest = ObligationForest::new();
248 forest.register_obligation("A");
249 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
250 |obligation| match *obligation {
251 "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
252 "A.1" | "A.2" | "A.3" => ProcessResult::Unchanged,
257 assert_eq!(ok.len(), 0);
258 assert_eq!(err.len(), 0);
259 let errors = forest.to_errors(());
260 assert_eq!(errors[0].backtrace, vec!["A.1", "A"]);
261 assert_eq!(errors[1].backtrace, vec!["A.2", "A"]);
262 assert_eq!(errors[2].backtrace, vec!["A.3", "A"]);
263 assert_eq!(errors.len(), 3);
268 // check that diamond dependencies are handled correctly
269 let mut forest = ObligationForest::new();
270 forest.register_obligation("A");
271 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
272 |obligation| match *obligation {
273 "A" => ProcessResult::Changed(vec!["A.1", "A.2"]),
274 "A.1" | "A.2" => ProcessResult::Unchanged,
279 assert_eq!(ok.len(), 0);
280 assert_eq!(err.len(), 0);
282 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
283 |obligation| match *obligation {
284 "A.1" => ProcessResult::Changed(vec!["D"]),
285 "A.2" => ProcessResult::Changed(vec!["D"]),
286 "D" => ProcessResult::Unchanged,
291 assert_eq!(ok.len(), 0);
292 assert_eq!(err.len(), 0);
295 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
296 |obligation| match *obligation {
299 ProcessResult::Changed(vec![])
305 assert_eq!(d_count, 1);
308 assert_eq!(ok, vec!["A", "A.1", "A.2", "D"]);
309 assert_eq!(err.len(), 0);
311 let errors = forest.to_errors(());
312 assert_eq!(errors.len(), 0);
314 forest.register_obligation("A'");
315 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
316 |obligation| match *obligation {
317 "A'" => ProcessResult::Changed(vec!["A'.1", "A'.2"]),
318 "A'.1" | "A'.2" => ProcessResult::Unchanged,
323 assert_eq!(ok.len(), 0);
324 assert_eq!(err.len(), 0);
326 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
327 |obligation| match *obligation {
328 "A'.1" => ProcessResult::Changed(vec!["D'", "A'"]),
329 "A'.2" => ProcessResult::Changed(vec!["D'"]),
330 "D'" | "A'" => ProcessResult::Unchanged,
335 assert_eq!(ok.len(), 0);
336 assert_eq!(err.len(), 0);
339 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
340 |obligation| match *obligation {
343 ProcessResult::Error("operation failed")
349 assert_eq!(d_count, 1);
350 assert_eq!(ok.len(), 0);
353 vec![super::Error { error: "operation failed", backtrace: vec!["D'", "A'.1", "A'"] }]
356 let errors = forest.to_errors(());
357 assert_eq!(errors.len(), 0);
361 fn done_dependency() {
362 // check that the local cache works
363 let mut forest = ObligationForest::new();
364 forest.register_obligation("A: Sized");
365 forest.register_obligation("B: Sized");
366 forest.register_obligation("C: Sized");
368 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
369 |obligation| match *obligation {
370 "A: Sized" | "B: Sized" | "C: Sized" => ProcessResult::Changed(vec![]),
377 assert_eq!(ok, vec!["A: Sized", "B: Sized", "C: Sized"]);
378 assert_eq!(err.len(), 0);
380 forest.register_obligation("(A,B,C): Sized");
381 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
382 |obligation| match *obligation {
383 "(A,B,C): Sized" => ProcessResult::Changed(vec!["A: Sized", "B: Sized", "C: Sized"]),
388 assert_eq!(ok, vec!["(A,B,C): Sized"]);
389 assert_eq!(err.len(), 0);
394 // check that orphaned nodes are handled correctly
395 let mut forest = ObligationForest::new();
396 forest.register_obligation("A");
397 forest.register_obligation("B");
398 forest.register_obligation("C1");
399 forest.register_obligation("C2");
401 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
402 |obligation| match *obligation {
403 "A" => ProcessResult::Changed(vec!["D", "E"]),
404 "B" => ProcessResult::Unchanged,
405 "C1" => ProcessResult::Changed(vec![]),
406 "C2" => ProcessResult::Changed(vec![]),
407 "D" | "E" => ProcessResult::Unchanged,
414 assert_eq!(ok, vec!["C1", "C2"]);
415 assert_eq!(err.len(), 0);
417 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
418 |obligation| match *obligation {
419 "D" | "E" => ProcessResult::Unchanged,
420 "B" => ProcessResult::Changed(vec!["D"]),
425 assert_eq!(ok.len(), 0);
426 assert_eq!(err.len(), 0);
428 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
429 |obligation| match *obligation {
430 "D" => ProcessResult::Unchanged,
431 "E" => ProcessResult::Error("E is for error"),
436 assert_eq!(ok.len(), 0);
437 assert_eq!(err, vec![super::Error { error: "E is for error", backtrace: vec!["E", "A"] }]);
439 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
440 |obligation| match *obligation {
441 "D" => ProcessResult::Error("D is dead"),
446 assert_eq!(ok.len(), 0);
447 assert_eq!(err, vec![super::Error { error: "D is dead", backtrace: vec!["D"] }]);
449 let errors = forest.to_errors(());
450 assert_eq!(errors.len(), 0);
454 fn simultaneous_register_and_error() {
455 // check that registering a failed obligation works correctly
456 let mut forest = ObligationForest::new();
457 forest.register_obligation("A");
458 forest.register_obligation("B");
460 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
461 |obligation| match *obligation {
462 "A" => ProcessResult::Error("An error"),
463 "B" => ProcessResult::Changed(vec!["A"]),
468 assert_eq!(ok.len(), 0);
469 assert_eq!(err, vec![super::Error { error: "An error", backtrace: vec!["A"] }]);
471 let mut forest = ObligationForest::new();
472 forest.register_obligation("B");
473 forest.register_obligation("A");
475 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
476 |obligation| match *obligation {
477 "A" => ProcessResult::Error("An error"),
478 "B" => ProcessResult::Changed(vec!["A"]),
483 assert_eq!(ok.len(), 0);
484 assert_eq!(err, vec![super::Error { error: "An error", backtrace: vec!["A"] }]);