1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
13 use super::{Error, ObligationForest, ObligationProcessor, Outcome, ProcessResult}
;
16 use std
::marker
::PhantomData
;
18 impl<'a
> super::ForestObligation
for &'a
str {
19 type Predicate
= &'a
str;
21 fn as_predicate(&self) -> &Self::Predicate
{
26 struct ClosureObligationProcessor
<OF
, BF
, O
, E
> {
27 process_obligation
: OF
,
28 _process_backedge
: BF
,
29 marker
: PhantomData
<(O
, E
)>,
32 #[allow(non_snake_case)]
33 fn C
<OF
, BF
, O
>(of
: OF
, bf
: BF
) -> ClosureObligationProcessor
<OF
, BF
, O
, &'
static str>
34 where OF
: FnMut(&mut O
) -> ProcessResult
<O
, &'
static str>,
37 ClosureObligationProcessor
{
38 process_obligation
: of
,
39 _process_backedge
: bf
,
44 impl<OF
, BF
, O
, E
> ObligationProcessor
for ClosureObligationProcessor
<OF
, BF
, O
, E
>
45 where O
: super::ForestObligation
+ fmt
::Debug
,
47 OF
: FnMut(&mut O
) -> ProcessResult
<O
, E
>,
53 fn process_obligation(&mut self,
54 obligation
: &mut Self::Obligation
)
55 -> ProcessResult
<Self::Obligation
, Self::Error
>
57 (self.process_obligation
)(obligation
)
60 fn process_backedge
<'c
, I
>(&mut self, _cycle
: I
,
61 _marker
: PhantomData
<&'c
Self::Obligation
>)
62 where I
: Clone
+ Iterator
<Item
=&'c
Self::Obligation
> {
69 let mut forest
= ObligationForest
::new();
70 forest
.register_obligation("A");
71 forest
.register_obligation("B");
72 forest
.register_obligation("C");
74 // first round, B errors out, A has subtasks, and C completes, creating this:
78 let Outcome { completed: ok, errors: err, .. }
=
79 forest
.process_obligations(&mut C(|obligation
| {
81 "A" => ProcessResult
::Changed(vec
!["A.1", "A.2", "A.3"]),
82 "B" => ProcessResult
::Error("B is for broken"),
83 "C" => ProcessResult
::Changed(vec
![]),
87 assert_eq
!(ok
, vec
!["C"]);
90 error
: "B is for broken",
94 // second round: two delays, one success, creating an uneven set of subtasks:
100 forest
.register_obligation("D");
101 let Outcome { completed: ok, errors: err, .. }
=
102 forest
.process_obligations(&mut C(|obligation
| {
104 "A.1" => ProcessResult
::Unchanged
,
105 "A.2" => ProcessResult
::Unchanged
,
106 "A.3" => ProcessResult
::Changed(vec
!["A.3.i"]),
107 "D" => ProcessResult
::Changed(vec
!["D.1", "D.2"]),
111 assert_eq
!(ok
, Vec
::<&'
static str>::new());
112 assert_eq
!(err
, Vec
::new());
115 // third round: ok in A.1 but trigger an error in A.2. Check that it
116 // propagates to A, but not D.1 or D.2.
117 // D |-> D.1 |-> D.1.i
119 let Outcome { completed: ok, errors: err, .. }
=
120 forest
.process_obligations(&mut C(|obligation
| {
122 "A.1" => ProcessResult
::Changed(vec
![]),
123 "A.2" => ProcessResult
::Error("A is for apple"),
124 "A.3.i" => ProcessResult
::Changed(vec
![]),
125 "D.1" => ProcessResult
::Changed(vec
!["D.1.i"]),
126 "D.2" => ProcessResult
::Changed(vec
!["D.2.i"]),
130 assert_eq
!(ok
, vec
!["A.3", "A.1", "A.3.i"]);
133 error
: "A is for apple",
134 backtrace
: vec
!["A.2", "A"],
137 // fourth round: error in D.1.i
138 let Outcome { completed: ok, errors: err, .. }
=
139 forest
.process_obligations(&mut C(|obligation
| {
141 "D.1.i" => ProcessResult
::Error("D is for dumb"),
142 "D.2.i" => ProcessResult
::Changed(vec
![]),
143 _
=> panic
!("unexpected obligation {:?}", obligation
),
146 assert_eq
!(ok
, vec
!["D.2.i", "D.2"]);
149 error
: "D is for dumb",
150 backtrace
: vec
!["D.1.i", "D.1", "D"],
154 // Test that if a tree with grandchildren succeeds, everything is
155 // reported as expected:
163 fn success_in_grandchildren() {
164 let mut forest
= ObligationForest
::new();
165 forest
.register_obligation("A");
167 let Outcome { completed: ok, errors: err, .. }
=
168 forest
.process_obligations(&mut C(|obligation
| {
170 "A" => ProcessResult
::Changed(vec
!["A.1", "A.2", "A.3"]),
174 assert
!(ok
.is_empty());
175 assert
!(err
.is_empty());
177 let Outcome { completed: ok, errors: err, .. }
=
178 forest
.process_obligations(&mut C(|obligation
| {
180 "A.1" => ProcessResult
::Changed(vec
![]),
181 "A.2" => ProcessResult
::Changed(vec
!["A.2.i", "A.2.ii"]),
182 "A.3" => ProcessResult
::Changed(vec
![]),
186 assert_eq
!(ok
, vec
!["A.3", "A.1"]);
187 assert
!(err
.is_empty());
189 let Outcome { completed: ok, errors: err, .. }
=
190 forest
.process_obligations(&mut C(|obligation
| {
192 "A.2.i" => ProcessResult
::Changed(vec
!["A.2.i.a"]),
193 "A.2.ii" => ProcessResult
::Changed(vec
![]),
197 assert_eq
!(ok
, vec
!["A.2.ii"]);
198 assert
!(err
.is_empty());
200 let Outcome { completed: ok, errors: err, .. }
=
201 forest
.process_obligations(&mut C(|obligation
| {
203 "A.2.i.a" => ProcessResult
::Changed(vec
![]),
207 assert_eq
!(ok
, vec
!["A.2.i.a", "A.2.i", "A.2", "A"]);
208 assert
!(err
.is_empty());
210 let Outcome { completed: ok, errors: err, .. }
=
211 forest
.process_obligations(&mut C(|_
| unreachable
!(), |_
| {}
));
213 assert
!(ok
.is_empty());
214 assert
!(err
.is_empty());
218 fn to_errors_no_throw() {
219 // check that converting multiple children with common parent (A)
220 // yields to correct errors (and does not panic, in particular).
221 let mut forest
= ObligationForest
::new();
222 forest
.register_obligation("A");
223 let Outcome { completed: ok, errors: err, .. }
=
224 forest
.process_obligations(&mut C(|obligation
| {
226 "A" => ProcessResult
::Changed(vec
!["A.1", "A.2", "A.3"]),
230 assert_eq
!(ok
.len(), 0);
231 assert_eq
!(err
.len(), 0);
232 let errors
= forest
.to_errors(());
233 assert_eq
!(errors
[0].backtrace
, vec
!["A.1", "A"]);
234 assert_eq
!(errors
[1].backtrace
, vec
!["A.2", "A"]);
235 assert_eq
!(errors
[2].backtrace
, vec
!["A.3", "A"]);
236 assert_eq
!(errors
.len(), 3);
241 // check that diamond dependencies are handled correctly
242 let mut forest
= ObligationForest
::new();
243 forest
.register_obligation("A");
244 let Outcome { completed: ok, errors: err, .. }
=
245 forest
.process_obligations(&mut C(|obligation
| {
247 "A" => ProcessResult
::Changed(vec
!["A.1", "A.2"]),
251 assert_eq
!(ok
.len(), 0);
252 assert_eq
!(err
.len(), 0);
254 let Outcome { completed: ok, errors: err, .. }
=
255 forest
.process_obligations(&mut C(|obligation
| {
257 "A.1" => ProcessResult
::Changed(vec
!["D"]),
258 "A.2" => ProcessResult
::Changed(vec
!["D"]),
262 assert_eq
!(ok
.len(), 0);
263 assert_eq
!(err
.len(), 0);
266 let Outcome { completed: ok, errors: err, .. }
=
267 forest
.process_obligations(&mut C(|obligation
| {
269 "D" => { d_count += 1; ProcessResult::Changed(vec![]) }
,
273 assert_eq
!(d_count
, 1);
274 assert_eq
!(ok
, vec
!["D", "A.2", "A.1", "A"]);
275 assert_eq
!(err
.len(), 0);
277 let errors
= forest
.to_errors(());
278 assert_eq
!(errors
.len(), 0);
280 forest
.register_obligation("A'");
281 let Outcome { completed: ok, errors: err, .. }
=
282 forest
.process_obligations(&mut C(|obligation
| {
284 "A'" => ProcessResult
::Changed(vec
!["A'.1", "A'.2"]),
288 assert_eq
!(ok
.len(), 0);
289 assert_eq
!(err
.len(), 0);
291 let Outcome { completed: ok, errors: err, .. }
=
292 forest
.process_obligations(&mut C(|obligation
| {
294 "A'.1" => ProcessResult
::Changed(vec
!["D'", "A'"]),
295 "A'.2" => ProcessResult
::Changed(vec
!["D'"]),
299 assert_eq
!(ok
.len(), 0);
300 assert_eq
!(err
.len(), 0);
303 let Outcome { completed: ok, errors: err, .. }
=
304 forest
.process_obligations(&mut C(|obligation
| {
306 "D'" => { d_count += 1; ProcessResult::Error("operation failed") }
,
310 assert_eq
!(d_count
, 1);
311 assert_eq
!(ok
.len(), 0);
312 assert_eq
!(err
, vec
![super::Error
{
313 error
: "operation failed",
314 backtrace
: vec
!["D'", "A'.1", "A'"]
317 let errors
= forest
.to_errors(());
318 assert_eq
!(errors
.len(), 0);
322 fn done_dependency() {
323 // check that the local cache works
324 let mut forest
= ObligationForest
::new();
325 forest
.register_obligation("A: Sized");
326 forest
.register_obligation("B: Sized");
327 forest
.register_obligation("C: Sized");
329 let Outcome { completed: ok, errors: err, .. }
=
330 forest
.process_obligations(&mut C(|obligation
| {
332 "A: Sized" | "B: Sized" | "C: Sized" => ProcessResult
::Changed(vec
![]),
336 assert_eq
!(ok
, vec
!["C: Sized", "B: Sized", "A: Sized"]);
337 assert_eq
!(err
.len(), 0);
339 forest
.register_obligation("(A,B,C): Sized");
340 let Outcome { completed: ok, errors: err, .. }
=
341 forest
.process_obligations(&mut C(|obligation
| {
343 "(A,B,C): Sized" => ProcessResult
::Changed(vec
![
351 assert_eq
!(ok
, vec
!["(A,B,C): Sized"]);
352 assert_eq
!(err
.len(), 0);
360 // check that orphaned nodes are handled correctly
361 let mut forest
= ObligationForest
::new();
362 forest
.register_obligation("A");
363 forest
.register_obligation("B");
364 forest
.register_obligation("C1");
365 forest
.register_obligation("C2");
367 let Outcome { completed: ok, errors: err, .. }
=
368 forest
.process_obligations(&mut C(|obligation
| {
370 "A" => ProcessResult
::Changed(vec
!["D", "E"]),
371 "B" => ProcessResult
::Unchanged
,
372 "C1" => ProcessResult
::Changed(vec
![]),
373 "C2" => ProcessResult
::Changed(vec
![]),
377 assert_eq
!(ok
, vec
!["C2", "C1"]);
378 assert_eq
!(err
.len(), 0);
380 let Outcome { completed: ok, errors: err, .. }
=
381 forest
.process_obligations(&mut C(|obligation
| {
383 "D" | "E" => ProcessResult
::Unchanged
,
384 "B" => ProcessResult
::Changed(vec
!["D"]),
388 assert_eq
!(ok
.len(), 0);
389 assert_eq
!(err
.len(), 0);
391 let Outcome { completed: ok, errors: err, .. }
=
392 forest
.process_obligations(&mut C(|obligation
| {
394 "D" => ProcessResult
::Unchanged
,
395 "E" => ProcessResult
::Error("E is for error"),
399 assert_eq
!(ok
.len(), 0);
400 assert_eq
!(err
, vec
![super::Error
{
401 error
: "E is for error",
402 backtrace
: vec
!["E", "A"]
405 let Outcome { completed: ok, errors: err, .. }
=
406 forest
.process_obligations(&mut C(|obligation
| {
408 "D" => ProcessResult
::Error("D is dead"),
412 assert_eq
!(ok
.len(), 0);
413 assert_eq
!(err
, vec
![super::Error
{
418 let errors
= forest
.to_errors(());
419 assert_eq
!(errors
.len(), 0);
423 fn simultaneous_register_and_error() {
424 // check that registering a failed obligation works correctly
425 let mut forest
= ObligationForest
::new();
426 forest
.register_obligation("A");
427 forest
.register_obligation("B");
429 let Outcome { completed: ok, errors: err, .. }
=
430 forest
.process_obligations(&mut C(|obligation
| {
432 "A" => ProcessResult
::Error("An error"),
433 "B" => ProcessResult
::Changed(vec
!["A"]),
437 assert_eq
!(ok
.len(), 0);
438 assert_eq
!(err
, vec
![super::Error
{
443 let mut forest
= ObligationForest
::new();
444 forest
.register_obligation("B");
445 forest
.register_obligation("A");
447 let Outcome { completed: ok, errors: err, .. }
=
448 forest
.process_obligations(&mut C(|obligation
| {
450 "A" => ProcessResult
::Error("An error"),
451 "B" => ProcessResult
::Changed(vec
!["A"]),
455 assert_eq
!(ok
.len(), 0);
456 assert_eq
!(err
, vec
![super::Error
{