]> git.lizzy.rs Git - rust.git/blob - src/librustc_data_structures/obligation_forest/tests.rs
Make `process_obligations()` greedier.
[rust.git] / src / librustc_data_structures / obligation_forest / tests.rs
1 use super::*;
2
3 use std::fmt;
4 use std::marker::PhantomData;
5
6 impl<'a> super::ForestObligation for &'a str {
7     type Predicate = &'a str;
8
9     fn as_predicate(&self) -> &Self::Predicate {
10         self
11     }
12 }
13
14 struct ClosureObligationProcessor<OF, BF, O, E> {
15     process_obligation: OF,
16     _process_backedge: BF,
17     marker: PhantomData<(O, E)>,
18 }
19
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>,
23           BF: FnMut(&[O])
24 {
25     ClosureObligationProcessor {
26         process_obligation: of,
27         _process_backedge: bf,
28         marker: PhantomData
29     }
30 }
31
32 impl<OF, BF, O, E> ObligationProcessor for ClosureObligationProcessor<OF, BF, O, E>
33     where O: super::ForestObligation + fmt::Debug,
34           E: fmt::Debug,
35           OF: FnMut(&mut O) -> ProcessResult<O, E>,
36           BF: FnMut(&[O])
37 {
38     type Obligation = O;
39     type Error = E;
40
41     fn process_obligation(&mut self,
42                           obligation: &mut Self::Obligation)
43                           -> ProcessResult<Self::Obligation, Self::Error>
44     {
45         (self.process_obligation)(obligation)
46     }
47
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>
51     {
52     }
53 }
54
55
56 #[test]
57 fn push_pop() {
58     let mut forest = ObligationForest::new();
59     forest.register_obligation("A");
60     forest.register_obligation("B");
61     forest.register_obligation("C");
62
63     // first round, B errors out, A has subtasks, and C completes, creating this:
64     //      A |-> A.1
65     //        |-> A.2
66     //        |-> A.3
67     let Outcome { completed: ok, errors: err, .. } =
68         forest.process_obligations(&mut C(|obligation| {
69             match *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,
74                 _ => unreachable!(),
75             }
76         }, |_| {}), DoCompleted::Yes);
77     assert_eq!(ok.unwrap(), vec!["C"]);
78     assert_eq!(err,
79                vec![Error {
80                         error: "B is for broken",
81                         backtrace: vec!["B"],
82                     }]);
83
84     // second round: two delays, one success, creating an uneven set of subtasks:
85     //      A |-> A.1
86     //        |-> A.2
87     //        |-> A.3 |-> A.3.i
88     //      D |-> D.1
89     //        |-> D.2
90     forest.register_obligation("D");
91     let Outcome { completed: ok, errors: err, .. } =
92         forest.process_obligations(&mut C(|obligation| {
93             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,
99                 _ => unreachable!(),
100             }
101         }, |_| {}), DoCompleted::Yes);
102     assert_eq!(ok.unwrap(), Vec::<&'static str>::new());
103     assert_eq!(err, Vec::new());
104
105
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
109     //        |-> D.2 |-> D.2.i
110     let Outcome { completed: ok, errors: err, .. } =
111         forest.process_obligations(&mut C(|obligation| {
112             match *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,
119                 _ => unreachable!(),
120             }
121         }, |_| {}), DoCompleted::Yes);
122     let mut ok = ok.unwrap();
123     ok.sort();
124     assert_eq!(ok, vec!["A.1", "A.3", "A.3.i"]);
125     assert_eq!(err,
126                vec![Error {
127                         error: "A is for apple",
128                         backtrace: vec!["A.2", "A"],
129                     }]);
130
131     // fourth round: error in D.1.i
132     let Outcome { completed: ok, errors: err, .. } =
133         forest.process_obligations(&mut C(|obligation| {
134             match *obligation {
135                 "D.1.i" => ProcessResult::Error("D is for dumb"),
136                 "D.2.i" => ProcessResult::Changed(vec![]),
137                 _ => panic!("unexpected obligation {:?}", obligation),
138             }
139         }, |_| {}), DoCompleted::Yes);
140     let mut ok = ok.unwrap();
141     ok.sort();
142     assert_eq!(ok, vec!["D.2", "D.2.i"]);
143     assert_eq!(err,
144                vec![Error {
145                         error: "D is for dumb",
146                         backtrace: vec!["D.1.i", "D.1", "D"],
147                     }]);
148 }
149
150 // Test that if a tree with grandchildren succeeds, everything is
151 // reported as expected:
152 // A
153 //   A.1
154 //   A.2
155 //      A.2.i
156 //      A.2.ii
157 //   A.3
158 #[test]
159 fn success_in_grandchildren() {
160     let mut forest = ObligationForest::new();
161     forest.register_obligation("A");
162
163     let Outcome { completed: ok, errors: err, .. } =
164         forest.process_obligations(&mut C(|obligation| {
165             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,
171                 _ => unreachable!(),
172             }
173         }, |_| {}), DoCompleted::Yes);
174     let mut ok = ok.unwrap();
175     ok.sort();
176     assert_eq!(ok, vec!["A.1", "A.3"]);
177     assert!(err.is_empty());
178
179     let Outcome { completed: ok, errors: err, .. } =
180         forest.process_obligations(&mut C(|obligation| {
181             match *obligation {
182                 "A.2.i" => ProcessResult::Unchanged,
183                 "A.2.ii" => ProcessResult::Changed(vec![]),
184                 _ => unreachable!(),
185             }
186         }, |_| {}), DoCompleted::Yes);
187     assert_eq!(ok.unwrap(), vec!["A.2.ii"]);
188     assert!(err.is_empty());
189
190     let Outcome { completed: ok, errors: err, .. } =
191         forest.process_obligations(&mut C(|obligation| {
192             match *obligation {
193                 "A.2.i" => ProcessResult::Changed(vec!["A.2.i.a"]),
194                 "A.2.i.a" => ProcessResult::Unchanged,
195                 _ => unreachable!(),
196             }
197         }, |_| {}), DoCompleted::Yes);
198     assert!(ok.unwrap().is_empty());
199     assert!(err.is_empty());
200
201     let Outcome { completed: ok, errors: err, .. } =
202         forest.process_obligations(&mut C(|obligation| {
203             match *obligation {
204                 "A.2.i.a" => ProcessResult::Changed(vec![]),
205                 _ => unreachable!(),
206             }
207         }, |_| {}), DoCompleted::Yes);
208     let mut ok = ok.unwrap();
209     ok.sort();
210     assert_eq!(ok, vec!["A", "A.2", "A.2.i", "A.2.i.a"]);
211     assert!(err.is_empty());
212
213     let Outcome { completed: ok, errors: err, .. } =
214         forest.process_obligations(&mut C(|_| unreachable!(), |_| {}),
215         DoCompleted::Yes);
216
217     assert!(ok.unwrap().is_empty());
218     assert!(err.is_empty());
219 }
220
221 #[test]
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| {
229             match *obligation {
230                 "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
231                 "A.1" | "A.2" | "A.3" => ProcessResult::Unchanged,
232                 _ => unreachable!(),
233             }
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);
242 }
243
244 #[test]
245 fn diamond() {
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| {
251             match *obligation {
252                 "A" => ProcessResult::Changed(vec!["A.1", "A.2"]),
253                 "A.1" | "A.2" => ProcessResult::Unchanged,
254                 _ => unreachable!(),
255             }
256         }, |_|{}), DoCompleted::Yes);
257     assert_eq!(ok.unwrap().len(), 0);
258     assert_eq!(err.len(), 0);
259
260     let Outcome { completed: ok, errors: err, .. } =
261         forest.process_obligations(&mut C(|obligation| {
262             match *obligation {
263                 "A.1" => ProcessResult::Changed(vec!["D"]),
264                 "A.2" => ProcessResult::Changed(vec!["D"]),
265                 "D" => ProcessResult::Unchanged,
266                 _ => unreachable!(),
267             }
268         }, |_|{}), DoCompleted::Yes);
269     assert_eq!(ok.unwrap().len(), 0);
270     assert_eq!(err.len(), 0);
271
272     let mut d_count = 0;
273     let Outcome { completed: ok, errors: err, .. } =
274         forest.process_obligations(&mut C(|obligation| {
275             match *obligation {
276                 "D" => { d_count += 1; ProcessResult::Changed(vec![]) },
277                 _ => unreachable!(),
278             }
279         }, |_|{}), DoCompleted::Yes);
280     assert_eq!(d_count, 1);
281     let mut ok = ok.unwrap();
282     ok.sort();
283     assert_eq!(ok, vec!["A", "A.1", "A.2", "D"]);
284     assert_eq!(err.len(), 0);
285
286     let errors = forest.to_errors(());
287     assert_eq!(errors.len(), 0);
288
289     forest.register_obligation("A'");
290     let Outcome { completed: ok, errors: err, .. } =
291         forest.process_obligations(&mut C(|obligation| {
292             match *obligation {
293                 "A'" => ProcessResult::Changed(vec!["A'.1", "A'.2"]),
294                 "A'.1" | "A'.2" => ProcessResult::Unchanged,
295                 _ => unreachable!(),
296             }
297         }, |_|{}), DoCompleted::Yes);
298     assert_eq!(ok.unwrap().len(), 0);
299     assert_eq!(err.len(), 0);
300
301     let Outcome { completed: ok, errors: err, .. } =
302         forest.process_obligations(&mut C(|obligation| {
303             match *obligation {
304                 "A'.1" => ProcessResult::Changed(vec!["D'", "A'"]),
305                 "A'.2" => ProcessResult::Changed(vec!["D'"]),
306                 "D'" | "A'" => ProcessResult::Unchanged,
307                 _ => unreachable!(),
308             }
309         }, |_|{}), DoCompleted::Yes);
310     assert_eq!(ok.unwrap().len(), 0);
311     assert_eq!(err.len(), 0);
312
313     let mut d_count = 0;
314     let Outcome { completed: ok, errors: err, .. } =
315         forest.process_obligations(&mut C(|obligation| {
316             match *obligation {
317                 "D'" => { d_count += 1; ProcessResult::Error("operation failed") },
318                 _ => unreachable!(),
319             }
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'"]
326     }]);
327
328     let errors = forest.to_errors(());
329     assert_eq!(errors.len(), 0);
330 }
331
332 #[test]
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");
339
340     let Outcome { completed: ok, errors: err, .. } =
341         forest.process_obligations(&mut C(|obligation| {
342             match *obligation {
343                 "A: Sized" | "B: Sized" | "C: Sized" => ProcessResult::Changed(vec![]),
344                 _ => unreachable!(),
345             }
346         }, |_|{}), DoCompleted::Yes);
347     let mut ok = ok.unwrap();
348     ok.sort();
349     assert_eq!(ok, vec!["A: Sized", "B: Sized", "C: Sized"]);
350     assert_eq!(err.len(), 0);
351
352     forest.register_obligation("(A,B,C): Sized");
353     let Outcome { completed: ok, errors: err, .. } =
354         forest.process_obligations(&mut C(|obligation| {
355             match *obligation {
356                 "(A,B,C): Sized" => ProcessResult::Changed(vec![
357                     "A: Sized",
358                     "B: Sized",
359                     "C: Sized"
360                         ]),
361                 _ => unreachable!(),
362             }
363         }, |_|{}), DoCompleted::Yes);
364     assert_eq!(ok.unwrap(), vec!["(A,B,C): Sized"]);
365     assert_eq!(err.len(), 0);
366 }
367
368 #[test]
369 fn orphan() {
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");
376
377     let Outcome { completed: ok, errors: err, .. } =
378         forest.process_obligations(&mut C(|obligation| {
379             match *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,
385                 _ => unreachable!(),
386             }
387         }, |_|{}), DoCompleted::Yes);
388     let mut ok = ok.unwrap();
389     ok.sort();
390     assert_eq!(ok, vec!["C1", "C2"]);
391     assert_eq!(err.len(), 0);
392
393     let Outcome { completed: ok, errors: err, .. } =
394         forest.process_obligations(&mut C(|obligation| {
395             match *obligation {
396                 "D" | "E" => ProcessResult::Unchanged,
397                 "B" => ProcessResult::Changed(vec!["D"]),
398                 _ => unreachable!(),
399             }
400         }, |_|{}), DoCompleted::Yes);
401     assert_eq!(ok.unwrap().len(), 0);
402     assert_eq!(err.len(), 0);
403
404     let Outcome { completed: ok, errors: err, .. } =
405         forest.process_obligations(&mut C(|obligation| {
406             match *obligation {
407                 "D" => ProcessResult::Unchanged,
408                 "E" => ProcessResult::Error("E is for error"),
409                 _ => unreachable!(),
410             }
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"]
416     }]);
417
418     let Outcome { completed: ok, errors: err, .. } =
419         forest.process_obligations(&mut C(|obligation| {
420             match *obligation {
421                 "D" => ProcessResult::Error("D is dead"),
422                 _ => unreachable!(),
423             }
424         }, |_|{}), DoCompleted::Yes);
425     assert_eq!(ok.unwrap().len(), 0);
426     assert_eq!(err, vec![super::Error {
427         error: "D is dead",
428         backtrace: vec!["D"]
429     }]);
430
431     let errors = forest.to_errors(());
432     assert_eq!(errors.len(), 0);
433 }
434
435 #[test]
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");
441
442     let Outcome { completed: ok, errors: err, .. } =
443         forest.process_obligations(&mut C(|obligation| {
444             match *obligation {
445                 "A" => ProcessResult::Error("An error"),
446                 "B" => ProcessResult::Changed(vec!["A"]),
447                 _ => unreachable!(),
448             }
449         }, |_|{}), DoCompleted::Yes);
450     assert_eq!(ok.unwrap().len(), 0);
451     assert_eq!(err, vec![super::Error {
452         error: "An error",
453         backtrace: vec!["A"]
454     }]);
455
456     let mut forest = ObligationForest::new();
457     forest.register_obligation("B");
458     forest.register_obligation("A");
459
460     let Outcome { completed: ok, errors: err, .. } =
461         forest.process_obligations(&mut C(|obligation| {
462             match *obligation {
463                 "A" => ProcessResult::Error("An error"),
464                 "B" => ProcessResult::Changed(vec!["A"]),
465                 _ => unreachable!(),
466             }
467         }, |_|{}), DoCompleted::Yes);
468     assert_eq!(ok.unwrap().len(), 0);
469     assert_eq!(err, vec![super::Error {
470         error: "An error",
471         backtrace: vec!["A"]
472     }]);
473 }