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>>,
26 impl<O, E> OutcomeTrait for TestOutcome<O, E>
30 type Error = Error<O, E>;
34 Self { errors: vec![], stalled: false, completed: vec![] }
37 fn mark_not_stalled(&mut self) {
41 fn is_stalled(&self) -> bool {
45 fn record_completed(&mut self, outcome: &Self::Obligation) {
46 self.completed.push(outcome.clone())
49 fn record_error(&mut self, error: Self::Error) {
50 self.errors.push(error)
54 #[allow(non_snake_case)]
55 fn C<OF, BF, O>(of: OF, bf: BF) -> ClosureObligationProcessor<OF, BF, O, &'static str>
57 OF: FnMut(&mut O) -> ProcessResult<O, &'static str>,
60 ClosureObligationProcessor {
61 process_obligation: of,
62 _process_backedge: bf,
67 impl<OF, BF, O, E> ObligationProcessor for ClosureObligationProcessor<OF, BF, O, E>
69 O: super::ForestObligation + fmt::Debug,
71 OF: FnMut(&mut O) -> ProcessResult<O, E>,
77 fn process_obligation(
79 obligation: &mut Self::Obligation,
80 ) -> ProcessResult<Self::Obligation, Self::Error> {
81 (self.process_obligation)(obligation)
84 fn process_backedge<'c, I>(&mut self, _cycle: I, _marker: PhantomData<&'c Self::Obligation>)
86 I: Clone + Iterator<Item = &'c Self::Obligation>,
93 let mut forest = ObligationForest::new();
94 forest.register_obligation("A");
95 forest.register_obligation("B");
96 forest.register_obligation("C");
98 // first round, B errors out, A has subtasks, and C completes, creating this:
102 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
103 |obligation| match *obligation {
104 "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
105 "B" => ProcessResult::Error("B is for broken"),
106 "C" => ProcessResult::Changed(vec![]),
107 "A.1" | "A.2" | "A.3" => ProcessResult::Unchanged,
112 assert_eq!(ok, vec!["C"]);
113 assert_eq!(err, vec![Error { error: "B is for broken", backtrace: vec!["B"] }]);
115 // second round: two delays, one success, creating an uneven set of subtasks:
121 forest.register_obligation("D");
122 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
123 |obligation| match *obligation {
124 "A.1" => ProcessResult::Unchanged,
125 "A.2" => ProcessResult::Unchanged,
126 "A.3" => ProcessResult::Changed(vec!["A.3.i"]),
127 "D" => ProcessResult::Changed(vec!["D.1", "D.2"]),
128 "A.3.i" | "D.1" | "D.2" => ProcessResult::Unchanged,
133 assert_eq!(ok, Vec::<&'static str>::new());
134 assert_eq!(err, Vec::new());
136 // third round: ok in A.1 but trigger an error in A.2. Check that it
137 // propagates to A, but not D.1 or D.2.
138 // D |-> D.1 |-> D.1.i
140 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
141 |obligation| match *obligation {
142 "A.1" => ProcessResult::Changed(vec![]),
143 "A.2" => ProcessResult::Error("A is for apple"),
144 "A.3.i" => ProcessResult::Changed(vec![]),
145 "D.1" => ProcessResult::Changed(vec!["D.1.i"]),
146 "D.2" => ProcessResult::Changed(vec!["D.2.i"]),
147 "D.1.i" | "D.2.i" => ProcessResult::Unchanged,
154 assert_eq!(ok, vec!["A.1", "A.3", "A.3.i"]);
155 assert_eq!(err, vec![Error { error: "A is for apple", backtrace: vec!["A.2", "A"] }]);
157 // fourth round: error in D.1.i
158 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
159 |obligation| match *obligation {
160 "D.1.i" => ProcessResult::Error("D is for dumb"),
161 "D.2.i" => ProcessResult::Changed(vec![]),
162 _ => panic!("unexpected obligation {:?}", obligation),
168 assert_eq!(ok, vec!["D.2", "D.2.i"]);
169 assert_eq!(err, vec![Error { error: "D is for dumb", backtrace: vec!["D.1.i", "D.1", "D"] }]);
172 // Test that if a tree with grandchildren succeeds, everything is
173 // reported as expected:
181 fn success_in_grandchildren() {
182 let mut forest = ObligationForest::new();
183 forest.register_obligation("A");
185 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
186 |obligation| match *obligation {
187 "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
188 "A.1" => ProcessResult::Changed(vec![]),
189 "A.2" => ProcessResult::Changed(vec!["A.2.i", "A.2.ii"]),
190 "A.3" => ProcessResult::Changed(vec![]),
191 "A.2.i" | "A.2.ii" => ProcessResult::Unchanged,
198 assert_eq!(ok, vec!["A.1", "A.3"]);
199 assert!(err.is_empty());
201 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
202 |obligation| match *obligation {
203 "A.2.i" => ProcessResult::Unchanged,
204 "A.2.ii" => ProcessResult::Changed(vec![]),
209 assert_eq!(ok, vec!["A.2.ii"]);
210 assert!(err.is_empty());
212 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
213 |obligation| match *obligation {
214 "A.2.i" => ProcessResult::Changed(vec!["A.2.i.a"]),
215 "A.2.i.a" => ProcessResult::Unchanged,
220 assert!(ok.is_empty());
221 assert!(err.is_empty());
223 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
224 |obligation| match *obligation {
225 "A.2.i.a" => ProcessResult::Changed(vec![]),
232 assert_eq!(ok, vec!["A", "A.2", "A.2.i", "A.2.i.a"]);
233 assert!(err.is_empty());
235 let TestOutcome { completed: ok, errors: err, .. } =
236 forest.process_obligations(&mut C(|_| unreachable!(), |_| {}));
238 assert!(ok.is_empty());
239 assert!(err.is_empty());
243 fn to_errors_no_throw() {
244 // check that converting multiple children with common parent (A)
245 // yields to correct errors (and does not panic, in particular).
246 let mut forest = ObligationForest::new();
247 forest.register_obligation("A");
248 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
249 |obligation| match *obligation {
250 "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
251 "A.1" | "A.2" | "A.3" => ProcessResult::Unchanged,
256 assert_eq!(ok.len(), 0);
257 assert_eq!(err.len(), 0);
258 let errors = forest.to_errors(());
259 assert_eq!(errors[0].backtrace, vec!["A.1", "A"]);
260 assert_eq!(errors[1].backtrace, vec!["A.2", "A"]);
261 assert_eq!(errors[2].backtrace, vec!["A.3", "A"]);
262 assert_eq!(errors.len(), 3);
267 // check that diamond dependencies are handled correctly
268 let mut forest = ObligationForest::new();
269 forest.register_obligation("A");
270 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
271 |obligation| match *obligation {
272 "A" => ProcessResult::Changed(vec!["A.1", "A.2"]),
273 "A.1" | "A.2" => ProcessResult::Unchanged,
278 assert_eq!(ok.len(), 0);
279 assert_eq!(err.len(), 0);
281 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
282 |obligation| match *obligation {
283 "A.1" => ProcessResult::Changed(vec!["D"]),
284 "A.2" => ProcessResult::Changed(vec!["D"]),
285 "D" => ProcessResult::Unchanged,
290 assert_eq!(ok.len(), 0);
291 assert_eq!(err.len(), 0);
294 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
295 |obligation| match *obligation {
298 ProcessResult::Changed(vec![])
304 assert_eq!(d_count, 1);
307 assert_eq!(ok, vec!["A", "A.1", "A.2", "D"]);
308 assert_eq!(err.len(), 0);
310 let errors = forest.to_errors(());
311 assert_eq!(errors.len(), 0);
313 forest.register_obligation("A'");
314 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
315 |obligation| match *obligation {
316 "A'" => ProcessResult::Changed(vec!["A'.1", "A'.2"]),
317 "A'.1" | "A'.2" => ProcessResult::Unchanged,
322 assert_eq!(ok.len(), 0);
323 assert_eq!(err.len(), 0);
325 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
326 |obligation| match *obligation {
327 "A'.1" => ProcessResult::Changed(vec!["D'", "A'"]),
328 "A'.2" => ProcessResult::Changed(vec!["D'"]),
329 "D'" | "A'" => ProcessResult::Unchanged,
334 assert_eq!(ok.len(), 0);
335 assert_eq!(err.len(), 0);
338 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
339 |obligation| match *obligation {
342 ProcessResult::Error("operation failed")
348 assert_eq!(d_count, 1);
349 assert_eq!(ok.len(), 0);
352 vec![super::Error { error: "operation failed", backtrace: vec!["D'", "A'.1", "A'"] }]
355 let errors = forest.to_errors(());
356 assert_eq!(errors.len(), 0);
360 fn done_dependency() {
361 // check that the local cache works
362 let mut forest = ObligationForest::new();
363 forest.register_obligation("A: Sized");
364 forest.register_obligation("B: Sized");
365 forest.register_obligation("C: Sized");
367 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
368 |obligation| match *obligation {
369 "A: Sized" | "B: Sized" | "C: Sized" => ProcessResult::Changed(vec![]),
376 assert_eq!(ok, vec!["A: Sized", "B: Sized", "C: Sized"]);
377 assert_eq!(err.len(), 0);
379 forest.register_obligation("(A,B,C): Sized");
380 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
381 |obligation| match *obligation {
382 "(A,B,C): Sized" => ProcessResult::Changed(vec!["A: Sized", "B: Sized", "C: Sized"]),
387 assert_eq!(ok, vec!["(A,B,C): Sized"]);
388 assert_eq!(err.len(), 0);
393 // check that orphaned nodes are handled correctly
394 let mut forest = ObligationForest::new();
395 forest.register_obligation("A");
396 forest.register_obligation("B");
397 forest.register_obligation("C1");
398 forest.register_obligation("C2");
400 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
401 |obligation| match *obligation {
402 "A" => ProcessResult::Changed(vec!["D", "E"]),
403 "B" => ProcessResult::Unchanged,
404 "C1" => ProcessResult::Changed(vec![]),
405 "C2" => ProcessResult::Changed(vec![]),
406 "D" | "E" => ProcessResult::Unchanged,
413 assert_eq!(ok, vec!["C1", "C2"]);
414 assert_eq!(err.len(), 0);
416 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
417 |obligation| match *obligation {
418 "D" | "E" => ProcessResult::Unchanged,
419 "B" => ProcessResult::Changed(vec!["D"]),
424 assert_eq!(ok.len(), 0);
425 assert_eq!(err.len(), 0);
427 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
428 |obligation| match *obligation {
429 "D" => ProcessResult::Unchanged,
430 "E" => ProcessResult::Error("E is for error"),
435 assert_eq!(ok.len(), 0);
436 assert_eq!(err, vec![super::Error { error: "E is for error", backtrace: vec!["E", "A"] }]);
438 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
439 |obligation| match *obligation {
440 "D" => ProcessResult::Error("D is dead"),
445 assert_eq!(ok.len(), 0);
446 assert_eq!(err, vec![super::Error { error: "D is dead", backtrace: vec!["D"] }]);
448 let errors = forest.to_errors(());
449 assert_eq!(errors.len(), 0);
453 fn simultaneous_register_and_error() {
454 // check that registering a failed obligation works correctly
455 let mut forest = ObligationForest::new();
456 forest.register_obligation("A");
457 forest.register_obligation("B");
459 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
460 |obligation| match *obligation {
461 "A" => ProcessResult::Error("An error"),
462 "B" => ProcessResult::Changed(vec!["A"]),
467 assert_eq!(ok.len(), 0);
468 assert_eq!(err, vec![super::Error { error: "An error", backtrace: vec!["A"] }]);
470 let mut forest = ObligationForest::new();
471 forest.register_obligation("B");
472 forest.register_obligation("A");
474 let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
475 |obligation| match *obligation {
476 "A" => ProcessResult::Error("An error"),
477 "B" => ProcessResult::Changed(vec!["A"]),
482 assert_eq!(ok.len(), 0);
483 assert_eq!(err, vec![super::Error { error: "An error", backtrace: vec!["A"] }]);