]> git.lizzy.rs Git - rust.git/blob - src/librustc_data_structures/obligation_forest/tests.rs
Merge pull request #1 from rust-lang/master
[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                 _ => unreachable!(),
74             }
75         }, |_| {}), DoCompleted::Yes);
76     assert_eq!(ok.unwrap(), vec!["C"]);
77     assert_eq!(err,
78                vec![Error {
79                         error: "B is for broken",
80                         backtrace: vec!["B"],
81                     }]);
82
83     // second round: two delays, one success, creating an uneven set of subtasks:
84     //      A |-> A.1
85     //        |-> A.2
86     //        |-> A.3 |-> A.3.i
87     //      D |-> D.1
88     //        |-> D.2
89     forest.register_obligation("D");
90     let Outcome { completed: ok, errors: err, .. } =
91         forest.process_obligations(&mut C(|obligation| {
92             match *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"]),
97                 _ => unreachable!(),
98             }
99         }, |_| {}), DoCompleted::Yes);
100     assert_eq!(ok.unwrap(), Vec::<&'static str>::new());
101     assert_eq!(err, Vec::new());
102
103
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
107     //        |-> D.2 |-> D.2.i
108     let Outcome { completed: ok, errors: err, .. } =
109         forest.process_obligations(&mut C(|obligation| {
110             match *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"]),
116                 _ => unreachable!(),
117             }
118         }, |_| {}), DoCompleted::Yes);
119     assert_eq!(ok.unwrap(), vec!["A.3", "A.1", "A.3.i"]);
120     assert_eq!(err,
121                vec![Error {
122                         error: "A is for apple",
123                         backtrace: vec!["A.2", "A"],
124                     }]);
125
126     // fourth round: error in D.1.i
127     let Outcome { completed: ok, errors: err, .. } =
128         forest.process_obligations(&mut C(|obligation| {
129             match *obligation {
130                 "D.1.i" => ProcessResult::Error("D is for dumb"),
131                 "D.2.i" => ProcessResult::Changed(vec![]),
132                 _ => panic!("unexpected obligation {:?}", obligation),
133             }
134         }, |_| {}), DoCompleted::Yes);
135     assert_eq!(ok.unwrap(), vec!["D.2.i", "D.2"]);
136     assert_eq!(err,
137                vec![Error {
138                         error: "D is for dumb",
139                         backtrace: vec!["D.1.i", "D.1", "D"],
140                     }]);
141 }
142
143 // Test that if a tree with grandchildren succeeds, everything is
144 // reported as expected:
145 // A
146 //   A.1
147 //   A.2
148 //      A.2.i
149 //      A.2.ii
150 //   A.3
151 #[test]
152 fn success_in_grandchildren() {
153     let mut forest = ObligationForest::new();
154     forest.register_obligation("A");
155
156     let Outcome { completed: ok, errors: err, .. } =
157         forest.process_obligations(&mut C(|obligation| {
158             match *obligation {
159                 "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
160                 _ => unreachable!(),
161             }
162         }, |_| {}), DoCompleted::Yes);
163     assert!(ok.unwrap().is_empty());
164     assert!(err.is_empty());
165
166     let Outcome { completed: ok, errors: err, .. } =
167         forest.process_obligations(&mut C(|obligation| {
168             match *obligation {
169                 "A.1" => ProcessResult::Changed(vec![]),
170                 "A.2" => ProcessResult::Changed(vec!["A.2.i", "A.2.ii"]),
171                 "A.3" => ProcessResult::Changed(vec![]),
172                 _ => unreachable!(),
173             }
174         }, |_| {}), DoCompleted::Yes);
175     assert_eq!(ok.unwrap(), vec!["A.3", "A.1"]);
176     assert!(err.is_empty());
177
178     let Outcome { completed: ok, errors: err, .. } =
179         forest.process_obligations(&mut C(|obligation| {
180             match *obligation {
181                 "A.2.i" => ProcessResult::Changed(vec!["A.2.i.a"]),
182                 "A.2.ii" => ProcessResult::Changed(vec![]),
183                 _ => unreachable!(),
184             }
185         }, |_| {}), DoCompleted::Yes);
186     assert_eq!(ok.unwrap(), vec!["A.2.ii"]);
187     assert!(err.is_empty());
188
189     let Outcome { completed: ok, errors: err, .. } =
190         forest.process_obligations(&mut C(|obligation| {
191             match *obligation {
192                 "A.2.i.a" => ProcessResult::Changed(vec![]),
193                 _ => unreachable!(),
194             }
195         }, |_| {}), DoCompleted::Yes);
196     assert_eq!(ok.unwrap(), vec!["A.2.i.a", "A.2.i", "A.2", "A"]);
197     assert!(err.is_empty());
198
199     let Outcome { completed: ok, errors: err, .. } =
200         forest.process_obligations(&mut C(|_| unreachable!(), |_| {}),
201         DoCompleted::Yes);
202
203     assert!(ok.unwrap().is_empty());
204     assert!(err.is_empty());
205 }
206
207 #[test]
208 fn to_errors_no_throw() {
209     // check that converting multiple children with common parent (A)
210     // yields to correct errors (and does not panic, in particular).
211     let mut forest = ObligationForest::new();
212     forest.register_obligation("A");
213     let Outcome { completed: ok, errors: err, .. } =
214         forest.process_obligations(&mut C(|obligation| {
215             match *obligation {
216                 "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
217                 _ => unreachable!(),
218             }
219         }, |_|{}), DoCompleted::Yes);
220     assert_eq!(ok.unwrap().len(), 0);
221     assert_eq!(err.len(), 0);
222     let errors = forest.to_errors(());
223     assert_eq!(errors[0].backtrace, vec!["A.1", "A"]);
224     assert_eq!(errors[1].backtrace, vec!["A.2", "A"]);
225     assert_eq!(errors[2].backtrace, vec!["A.3", "A"]);
226     assert_eq!(errors.len(), 3);
227 }
228
229 #[test]
230 fn diamond() {
231     // check that diamond dependencies are handled correctly
232     let mut forest = ObligationForest::new();
233     forest.register_obligation("A");
234     let Outcome { completed: ok, errors: err, .. } =
235         forest.process_obligations(&mut C(|obligation| {
236             match *obligation {
237                 "A" => ProcessResult::Changed(vec!["A.1", "A.2"]),
238                 _ => unreachable!(),
239             }
240         }, |_|{}), DoCompleted::Yes);
241     assert_eq!(ok.unwrap().len(), 0);
242     assert_eq!(err.len(), 0);
243
244     let Outcome { completed: ok, errors: err, .. } =
245         forest.process_obligations(&mut C(|obligation| {
246             match *obligation {
247                 "A.1" => ProcessResult::Changed(vec!["D"]),
248                 "A.2" => ProcessResult::Changed(vec!["D"]),
249                 _ => unreachable!(),
250             }
251         }, |_|{}), DoCompleted::Yes);
252     assert_eq!(ok.unwrap().len(), 0);
253     assert_eq!(err.len(), 0);
254
255     let mut d_count = 0;
256     let Outcome { completed: ok, errors: err, .. } =
257         forest.process_obligations(&mut C(|obligation| {
258             match *obligation {
259                 "D" => { d_count += 1; ProcessResult::Changed(vec![]) },
260                 _ => unreachable!(),
261             }
262         }, |_|{}), DoCompleted::Yes);
263     assert_eq!(d_count, 1);
264     assert_eq!(ok.unwrap(), vec!["D", "A.2", "A.1", "A"]);
265     assert_eq!(err.len(), 0);
266
267     let errors = forest.to_errors(());
268     assert_eq!(errors.len(), 0);
269
270     forest.register_obligation("A'");
271     let Outcome { completed: ok, errors: err, .. } =
272         forest.process_obligations(&mut C(|obligation| {
273             match *obligation {
274                 "A'" => ProcessResult::Changed(vec!["A'.1", "A'.2"]),
275                 _ => unreachable!(),
276             }
277         }, |_|{}), DoCompleted::Yes);
278     assert_eq!(ok.unwrap().len(), 0);
279     assert_eq!(err.len(), 0);
280
281     let Outcome { completed: ok, errors: err, .. } =
282         forest.process_obligations(&mut C(|obligation| {
283             match *obligation {
284                 "A'.1" => ProcessResult::Changed(vec!["D'", "A'"]),
285                 "A'.2" => ProcessResult::Changed(vec!["D'"]),
286                 _ => unreachable!(),
287             }
288         }, |_|{}), DoCompleted::Yes);
289     assert_eq!(ok.unwrap().len(), 0);
290     assert_eq!(err.len(), 0);
291
292     let mut d_count = 0;
293     let Outcome { completed: ok, errors: err, .. } =
294         forest.process_obligations(&mut C(|obligation| {
295             match *obligation {
296                 "D'" => { d_count += 1; ProcessResult::Error("operation failed") },
297                 _ => unreachable!(),
298             }
299         }, |_|{}), DoCompleted::Yes);
300     assert_eq!(d_count, 1);
301     assert_eq!(ok.unwrap().len(), 0);
302     assert_eq!(err, vec![super::Error {
303         error: "operation failed",
304         backtrace: vec!["D'", "A'.1", "A'"]
305     }]);
306
307     let errors = forest.to_errors(());
308     assert_eq!(errors.len(), 0);
309 }
310
311 #[test]
312 fn done_dependency() {
313     // check that the local cache works
314     let mut forest = ObligationForest::new();
315     forest.register_obligation("A: Sized");
316     forest.register_obligation("B: Sized");
317     forest.register_obligation("C: Sized");
318
319     let Outcome { completed: ok, errors: err, .. } =
320         forest.process_obligations(&mut C(|obligation| {
321             match *obligation {
322                 "A: Sized" | "B: Sized" | "C: Sized" => ProcessResult::Changed(vec![]),
323                 _ => unreachable!(),
324             }
325         }, |_|{}), DoCompleted::Yes);
326     assert_eq!(ok.unwrap(), vec!["C: Sized", "B: Sized", "A: Sized"]);
327     assert_eq!(err.len(), 0);
328
329     forest.register_obligation("(A,B,C): Sized");
330     let Outcome { completed: ok, errors: err, .. } =
331         forest.process_obligations(&mut C(|obligation| {
332             match *obligation {
333                 "(A,B,C): Sized" => ProcessResult::Changed(vec![
334                     "A: Sized",
335                     "B: Sized",
336                     "C: Sized"
337                         ]),
338                 _ => unreachable!(),
339             }
340         }, |_|{}), DoCompleted::Yes);
341     assert_eq!(ok.unwrap(), vec!["(A,B,C): Sized"]);
342     assert_eq!(err.len(), 0);
343 }
344
345 #[test]
346 fn orphan() {
347     // check that orphaned nodes are handled correctly
348     let mut forest = ObligationForest::new();
349     forest.register_obligation("A");
350     forest.register_obligation("B");
351     forest.register_obligation("C1");
352     forest.register_obligation("C2");
353
354     let Outcome { completed: ok, errors: err, .. } =
355         forest.process_obligations(&mut C(|obligation| {
356             match *obligation {
357                 "A" => ProcessResult::Changed(vec!["D", "E"]),
358                 "B" => ProcessResult::Unchanged,
359                 "C1" => ProcessResult::Changed(vec![]),
360                 "C2" => ProcessResult::Changed(vec![]),
361                 _ => unreachable!(),
362             }
363         }, |_|{}), DoCompleted::Yes);
364     assert_eq!(ok.unwrap(), vec!["C2", "C1"]);
365     assert_eq!(err.len(), 0);
366
367     let Outcome { completed: ok, errors: err, .. } =
368         forest.process_obligations(&mut C(|obligation| {
369             match *obligation {
370                 "D" | "E" => ProcessResult::Unchanged,
371                 "B" => ProcessResult::Changed(vec!["D"]),
372                 _ => unreachable!(),
373             }
374         }, |_|{}), DoCompleted::Yes);
375     assert_eq!(ok.unwrap().len(), 0);
376     assert_eq!(err.len(), 0);
377
378     let Outcome { completed: ok, errors: err, .. } =
379         forest.process_obligations(&mut C(|obligation| {
380             match *obligation {
381                 "D" => ProcessResult::Unchanged,
382                 "E" => ProcessResult::Error("E is for error"),
383                 _ => unreachable!(),
384             }
385         }, |_|{}), DoCompleted::Yes);
386     assert_eq!(ok.unwrap().len(), 0);
387     assert_eq!(err, vec![super::Error {
388         error: "E is for error",
389         backtrace: vec!["E", "A"]
390     }]);
391
392     let Outcome { completed: ok, errors: err, .. } =
393         forest.process_obligations(&mut C(|obligation| {
394             match *obligation {
395                 "D" => ProcessResult::Error("D is dead"),
396                 _ => unreachable!(),
397             }
398         }, |_|{}), DoCompleted::Yes);
399     assert_eq!(ok.unwrap().len(), 0);
400     assert_eq!(err, vec![super::Error {
401         error: "D is dead",
402         backtrace: vec!["D"]
403     }]);
404
405     let errors = forest.to_errors(());
406     assert_eq!(errors.len(), 0);
407 }
408
409 #[test]
410 fn simultaneous_register_and_error() {
411     // check that registering a failed obligation works correctly
412     let mut forest = ObligationForest::new();
413     forest.register_obligation("A");
414     forest.register_obligation("B");
415
416     let Outcome { completed: ok, errors: err, .. } =
417         forest.process_obligations(&mut C(|obligation| {
418             match *obligation {
419                 "A" => ProcessResult::Error("An error"),
420                 "B" => ProcessResult::Changed(vec!["A"]),
421                 _ => unreachable!(),
422             }
423         }, |_|{}), DoCompleted::Yes);
424     assert_eq!(ok.unwrap().len(), 0);
425     assert_eq!(err, vec![super::Error {
426         error: "An error",
427         backtrace: vec!["A"]
428     }]);
429
430     let mut forest = ObligationForest::new();
431     forest.register_obligation("B");
432     forest.register_obligation("A");
433
434     let Outcome { completed: ok, errors: err, .. } =
435         forest.process_obligations(&mut C(|obligation| {
436             match *obligation {
437                 "A" => ProcessResult::Error("An error"),
438                 "B" => ProcessResult::Changed(vec!["A"]),
439                 _ => unreachable!(),
440             }
441         }, |_|{}), DoCompleted::Yes);
442     assert_eq!(ok.unwrap().len(), 0);
443     assert_eq!(err, vec![super::Error {
444         error: "An error",
445         backtrace: vec!["A"]
446     }]);
447 }