]> git.lizzy.rs Git - rust.git/blob - src/librustc_data_structures/obligation_forest/tests.rs
Don't use ExpnKind::descr to get the name of a bang macro.
[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
23     OF: FnMut(&mut O) -> ProcessResult<O, &'static str>,
24     BF: FnMut(&[O]),
25 {
26     ClosureObligationProcessor {
27         process_obligation: of,
28         _process_backedge: bf,
29         marker: PhantomData,
30     }
31 }
32
33 impl<OF, BF, O, E> ObligationProcessor for ClosureObligationProcessor<OF, BF, O, E>
34 where
35     O: super::ForestObligation + fmt::Debug,
36     E: fmt::Debug,
37     OF: FnMut(&mut O) -> ProcessResult<O, E>,
38     BF: FnMut(&[O]),
39 {
40     type Obligation = O;
41     type Error = E;
42
43     fn process_obligation(
44         &mut self,
45         obligation: &mut Self::Obligation,
46     ) -> ProcessResult<Self::Obligation, Self::Error> {
47         (self.process_obligation)(obligation)
48     }
49
50     fn process_backedge<'c, I>(&mut self, _cycle: I, _marker: PhantomData<&'c Self::Obligation>)
51     where
52         I: Clone + Iterator<Item = &'c Self::Obligation>,
53     {
54     }
55 }
56
57 #[test]
58 fn push_pop() {
59     let mut forest = ObligationForest::new();
60     forest.register_obligation("A");
61     forest.register_obligation("B");
62     forest.register_obligation("C");
63
64     // first round, B errors out, A has subtasks, and C completes, creating this:
65     //      A |-> A.1
66     //        |-> A.2
67     //        |-> A.3
68     let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
69         &mut C(
70             |obligation| match *obligation {
71                 "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
72                 "B" => ProcessResult::Error("B is for broken"),
73                 "C" => ProcessResult::Changed(vec![]),
74                 "A.1" | "A.2" | "A.3" => ProcessResult::Unchanged,
75                 _ => unreachable!(),
76             },
77             |_| {},
78         ),
79         DoCompleted::Yes,
80     );
81     assert_eq!(ok.unwrap(), vec!["C"]);
82     assert_eq!(err, vec![Error { error: "B is for broken", backtrace: vec!["B"] }]);
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, .. } = forest.process_obligations(
92         &mut C(
93             |obligation| 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             |_| {},
102         ),
103         DoCompleted::Yes,
104     );
105     assert_eq!(ok.unwrap(), Vec::<&'static str>::new());
106     assert_eq!(err, Vec::new());
107
108     // third round: ok in A.1 but trigger an error in A.2. Check that it
109     // propagates to A, but not D.1 or D.2.
110     //      D |-> D.1 |-> D.1.i
111     //        |-> D.2 |-> D.2.i
112     let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
113         &mut C(
114             |obligation| match *obligation {
115                 "A.1" => ProcessResult::Changed(vec![]),
116                 "A.2" => ProcessResult::Error("A is for apple"),
117                 "A.3.i" => ProcessResult::Changed(vec![]),
118                 "D.1" => ProcessResult::Changed(vec!["D.1.i"]),
119                 "D.2" => ProcessResult::Changed(vec!["D.2.i"]),
120                 "D.1.i" | "D.2.i" => ProcessResult::Unchanged,
121                 _ => unreachable!(),
122             },
123             |_| {},
124         ),
125         DoCompleted::Yes,
126     );
127     let mut ok = ok.unwrap();
128     ok.sort();
129     assert_eq!(ok, vec!["A.1", "A.3", "A.3.i"]);
130     assert_eq!(err, vec![Error { error: "A is for apple", backtrace: vec!["A.2", "A"] }]);
131
132     // fourth round: error in D.1.i
133     let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
134         &mut C(
135             |obligation| match *obligation {
136                 "D.1.i" => ProcessResult::Error("D is for dumb"),
137                 "D.2.i" => ProcessResult::Changed(vec![]),
138                 _ => panic!("unexpected obligation {:?}", obligation),
139             },
140             |_| {},
141         ),
142         DoCompleted::Yes,
143     );
144     let mut ok = ok.unwrap();
145     ok.sort();
146     assert_eq!(ok, vec!["D.2", "D.2.i"]);
147     assert_eq!(err, vec![Error { error: "D is for dumb", backtrace: vec!["D.1.i", "D.1", "D"] }]);
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, .. } = forest.process_obligations(
164         &mut C(
165             |obligation| 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             |_| {},
174         ),
175         DoCompleted::Yes,
176     );
177     let mut ok = ok.unwrap();
178     ok.sort();
179     assert_eq!(ok, vec!["A.1", "A.3"]);
180     assert!(err.is_empty());
181
182     let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
183         &mut C(
184             |obligation| match *obligation {
185                 "A.2.i" => ProcessResult::Unchanged,
186                 "A.2.ii" => ProcessResult::Changed(vec![]),
187                 _ => unreachable!(),
188             },
189             |_| {},
190         ),
191         DoCompleted::Yes,
192     );
193     assert_eq!(ok.unwrap(), vec!["A.2.ii"]);
194     assert!(err.is_empty());
195
196     let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
197         &mut C(
198             |obligation| match *obligation {
199                 "A.2.i" => ProcessResult::Changed(vec!["A.2.i.a"]),
200                 "A.2.i.a" => ProcessResult::Unchanged,
201                 _ => unreachable!(),
202             },
203             |_| {},
204         ),
205         DoCompleted::Yes,
206     );
207     assert!(ok.unwrap().is_empty());
208     assert!(err.is_empty());
209
210     let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
211         &mut C(
212             |obligation| match *obligation {
213                 "A.2.i.a" => ProcessResult::Changed(vec![]),
214                 _ => unreachable!(),
215             },
216             |_| {},
217         ),
218         DoCompleted::Yes,
219     );
220     let mut ok = ok.unwrap();
221     ok.sort();
222     assert_eq!(ok, vec!["A", "A.2", "A.2.i", "A.2.i.a"]);
223     assert!(err.is_empty());
224
225     let Outcome { completed: ok, errors: err, .. } =
226         forest.process_obligations(&mut C(|_| unreachable!(), |_| {}), DoCompleted::Yes);
227
228     assert!(ok.unwrap().is_empty());
229     assert!(err.is_empty());
230 }
231
232 #[test]
233 fn to_errors_no_throw() {
234     // check that converting multiple children with common parent (A)
235     // yields to correct errors (and does not panic, in particular).
236     let mut forest = ObligationForest::new();
237     forest.register_obligation("A");
238     let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
239         &mut C(
240             |obligation| match *obligation {
241                 "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
242                 "A.1" | "A.2" | "A.3" => ProcessResult::Unchanged,
243                 _ => unreachable!(),
244             },
245             |_| {},
246         ),
247         DoCompleted::Yes,
248     );
249     assert_eq!(ok.unwrap().len(), 0);
250     assert_eq!(err.len(), 0);
251     let errors = forest.to_errors(());
252     assert_eq!(errors[0].backtrace, vec!["A.1", "A"]);
253     assert_eq!(errors[1].backtrace, vec!["A.2", "A"]);
254     assert_eq!(errors[2].backtrace, vec!["A.3", "A"]);
255     assert_eq!(errors.len(), 3);
256 }
257
258 #[test]
259 fn diamond() {
260     // check that diamond dependencies are handled correctly
261     let mut forest = ObligationForest::new();
262     forest.register_obligation("A");
263     let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
264         &mut C(
265             |obligation| match *obligation {
266                 "A" => ProcessResult::Changed(vec!["A.1", "A.2"]),
267                 "A.1" | "A.2" => ProcessResult::Unchanged,
268                 _ => unreachable!(),
269             },
270             |_| {},
271         ),
272         DoCompleted::Yes,
273     );
274     assert_eq!(ok.unwrap().len(), 0);
275     assert_eq!(err.len(), 0);
276
277     let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
278         &mut C(
279             |obligation| match *obligation {
280                 "A.1" => ProcessResult::Changed(vec!["D"]),
281                 "A.2" => ProcessResult::Changed(vec!["D"]),
282                 "D" => ProcessResult::Unchanged,
283                 _ => unreachable!(),
284             },
285             |_| {},
286         ),
287         DoCompleted::Yes,
288     );
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, .. } = forest.process_obligations(
294         &mut C(
295             |obligation| match *obligation {
296                 "D" => {
297                     d_count += 1;
298                     ProcessResult::Changed(vec![])
299                 }
300                 _ => unreachable!(),
301             },
302             |_| {},
303         ),
304         DoCompleted::Yes,
305     );
306     assert_eq!(d_count, 1);
307     let mut ok = ok.unwrap();
308     ok.sort();
309     assert_eq!(ok, vec!["A", "A.1", "A.2", "D"]);
310     assert_eq!(err.len(), 0);
311
312     let errors = forest.to_errors(());
313     assert_eq!(errors.len(), 0);
314
315     forest.register_obligation("A'");
316     let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
317         &mut C(
318             |obligation| match *obligation {
319                 "A'" => ProcessResult::Changed(vec!["A'.1", "A'.2"]),
320                 "A'.1" | "A'.2" => ProcessResult::Unchanged,
321                 _ => unreachable!(),
322             },
323             |_| {},
324         ),
325         DoCompleted::Yes,
326     );
327     assert_eq!(ok.unwrap().len(), 0);
328     assert_eq!(err.len(), 0);
329
330     let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
331         &mut C(
332             |obligation| match *obligation {
333                 "A'.1" => ProcessResult::Changed(vec!["D'", "A'"]),
334                 "A'.2" => ProcessResult::Changed(vec!["D'"]),
335                 "D'" | "A'" => ProcessResult::Unchanged,
336                 _ => unreachable!(),
337             },
338             |_| {},
339         ),
340         DoCompleted::Yes,
341     );
342     assert_eq!(ok.unwrap().len(), 0);
343     assert_eq!(err.len(), 0);
344
345     let mut d_count = 0;
346     let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
347         &mut C(
348             |obligation| match *obligation {
349                 "D'" => {
350                     d_count += 1;
351                     ProcessResult::Error("operation failed")
352                 }
353                 _ => unreachable!(),
354             },
355             |_| {},
356         ),
357         DoCompleted::Yes,
358     );
359     assert_eq!(d_count, 1);
360     assert_eq!(ok.unwrap().len(), 0);
361     assert_eq!(
362         err,
363         vec![super::Error { error: "operation failed", backtrace: vec!["D'", "A'.1", "A'"] }]
364     );
365
366     let errors = forest.to_errors(());
367     assert_eq!(errors.len(), 0);
368 }
369
370 #[test]
371 fn done_dependency() {
372     // check that the local cache works
373     let mut forest = ObligationForest::new();
374     forest.register_obligation("A: Sized");
375     forest.register_obligation("B: Sized");
376     forest.register_obligation("C: Sized");
377
378     let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
379         &mut C(
380             |obligation| match *obligation {
381                 "A: Sized" | "B: Sized" | "C: Sized" => ProcessResult::Changed(vec![]),
382                 _ => unreachable!(),
383             },
384             |_| {},
385         ),
386         DoCompleted::Yes,
387     );
388     let mut ok = ok.unwrap();
389     ok.sort();
390     assert_eq!(ok, vec!["A: Sized", "B: Sized", "C: Sized"]);
391     assert_eq!(err.len(), 0);
392
393     forest.register_obligation("(A,B,C): Sized");
394     let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
395         &mut C(
396             |obligation| match *obligation {
397                 "(A,B,C): Sized" => {
398                     ProcessResult::Changed(vec!["A: Sized", "B: Sized", "C: Sized"])
399                 }
400                 _ => unreachable!(),
401             },
402             |_| {},
403         ),
404         DoCompleted::Yes,
405     );
406     assert_eq!(ok.unwrap(), vec!["(A,B,C): Sized"]);
407     assert_eq!(err.len(), 0);
408 }
409
410 #[test]
411 fn orphan() {
412     // check that orphaned nodes are handled correctly
413     let mut forest = ObligationForest::new();
414     forest.register_obligation("A");
415     forest.register_obligation("B");
416     forest.register_obligation("C1");
417     forest.register_obligation("C2");
418
419     let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
420         &mut C(
421             |obligation| match *obligation {
422                 "A" => ProcessResult::Changed(vec!["D", "E"]),
423                 "B" => ProcessResult::Unchanged,
424                 "C1" => ProcessResult::Changed(vec![]),
425                 "C2" => ProcessResult::Changed(vec![]),
426                 "D" | "E" => ProcessResult::Unchanged,
427                 _ => unreachable!(),
428             },
429             |_| {},
430         ),
431         DoCompleted::Yes,
432     );
433     let mut ok = ok.unwrap();
434     ok.sort();
435     assert_eq!(ok, vec!["C1", "C2"]);
436     assert_eq!(err.len(), 0);
437
438     let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
439         &mut C(
440             |obligation| match *obligation {
441                 "D" | "E" => ProcessResult::Unchanged,
442                 "B" => ProcessResult::Changed(vec!["D"]),
443                 _ => unreachable!(),
444             },
445             |_| {},
446         ),
447         DoCompleted::Yes,
448     );
449     assert_eq!(ok.unwrap().len(), 0);
450     assert_eq!(err.len(), 0);
451
452     let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
453         &mut C(
454             |obligation| match *obligation {
455                 "D" => ProcessResult::Unchanged,
456                 "E" => ProcessResult::Error("E is for error"),
457                 _ => unreachable!(),
458             },
459             |_| {},
460         ),
461         DoCompleted::Yes,
462     );
463     assert_eq!(ok.unwrap().len(), 0);
464     assert_eq!(err, vec![super::Error { error: "E is for error", backtrace: vec!["E", "A"] }]);
465
466     let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
467         &mut C(
468             |obligation| match *obligation {
469                 "D" => ProcessResult::Error("D is dead"),
470                 _ => unreachable!(),
471             },
472             |_| {},
473         ),
474         DoCompleted::Yes,
475     );
476     assert_eq!(ok.unwrap().len(), 0);
477     assert_eq!(err, vec![super::Error { error: "D is dead", backtrace: vec!["D"] }]);
478
479     let errors = forest.to_errors(());
480     assert_eq!(errors.len(), 0);
481 }
482
483 #[test]
484 fn simultaneous_register_and_error() {
485     // check that registering a failed obligation works correctly
486     let mut forest = ObligationForest::new();
487     forest.register_obligation("A");
488     forest.register_obligation("B");
489
490     let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
491         &mut C(
492             |obligation| match *obligation {
493                 "A" => ProcessResult::Error("An error"),
494                 "B" => ProcessResult::Changed(vec!["A"]),
495                 _ => unreachable!(),
496             },
497             |_| {},
498         ),
499         DoCompleted::Yes,
500     );
501     assert_eq!(ok.unwrap().len(), 0);
502     assert_eq!(err, vec![super::Error { error: "An error", backtrace: vec!["A"] }]);
503
504     let mut forest = ObligationForest::new();
505     forest.register_obligation("B");
506     forest.register_obligation("A");
507
508     let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
509         &mut C(
510             |obligation| match *obligation {
511                 "A" => ProcessResult::Error("An error"),
512                 "B" => ProcessResult::Changed(vec!["A"]),
513                 _ => unreachable!(),
514             },
515             |_| {},
516         ),
517         DoCompleted::Yes,
518     );
519     assert_eq!(ok.unwrap().len(), 0);
520     assert_eq!(err, vec![super::Error { error: "An error", backtrace: vec!["A"] }]);
521 }