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
>>,
25 impl<O
, E
> OutcomeTrait
for TestOutcome
<O
, E
>
29 type Error
= Error
<O
, E
>;
33 Self { errors: vec![], completed: vec![] }
36 fn record_completed(&mut self, outcome
: &Self::Obligation
) {
37 self.completed
.push(outcome
.clone())
40 fn record_error(&mut self, error
: Self::Error
) {
41 self.errors
.push(error
)
45 #[allow(non_snake_case)]
46 fn C
<OF
, BF
, O
>(of
: OF
, bf
: BF
) -> ClosureObligationProcessor
<OF
, BF
, O
, &'
static str>
48 OF
: FnMut(&mut O
) -> ProcessResult
<O
, &'
static str>,
51 ClosureObligationProcessor
{
52 process_obligation
: of
,
53 _process_backedge
: bf
,
58 impl<OF
, BF
, O
, E
> ObligationProcessor
for ClosureObligationProcessor
<OF
, BF
, O
, E
>
60 O
: super::ForestObligation
+ fmt
::Debug
,
62 OF
: FnMut(&mut O
) -> ProcessResult
<O
, E
>,
68 fn needs_process_obligation(&self, _obligation
: &Self::Obligation
) -> bool
{
72 fn process_obligation(
74 obligation
: &mut Self::Obligation
,
75 ) -> ProcessResult
<Self::Obligation
, Self::Error
> {
76 (self.process_obligation
)(obligation
)
79 fn process_backedge
<'c
, I
>(&mut self, _cycle
: I
, _marker
: PhantomData
<&'c
Self::Obligation
>)
81 I
: Clone
+ Iterator
<Item
= &'c
Self::Obligation
>,
88 let mut forest
= ObligationForest
::new();
89 forest
.register_obligation("A");
90 forest
.register_obligation("B");
91 forest
.register_obligation("C");
93 // first round, B errors out, A has subtasks, and C completes, creating this:
97 let TestOutcome { completed: ok, errors: err, .. }
= forest
.process_obligations(&mut C(
98 |obligation
| match *obligation
{
99 "A" => ProcessResult
::Changed(vec
!["A.1", "A.2", "A.3"]),
100 "B" => ProcessResult
::Error("B is for broken"),
101 "C" => ProcessResult
::Changed(vec
![]),
102 "A.1" | "A.2" | "A.3" => ProcessResult
::Unchanged
,
107 assert_eq
!(ok
, vec
!["C"]);
108 assert_eq
!(err
, vec
![Error { error: "B is for broken", backtrace: vec!["B"] }
]);
110 // second round: two delays, one success, creating an uneven set of subtasks:
116 forest
.register_obligation("D");
117 let TestOutcome { completed: ok, errors: err, .. }
= forest
.process_obligations(&mut C(
118 |obligation
| match *obligation
{
119 "A.1" => ProcessResult
::Unchanged
,
120 "A.2" => ProcessResult
::Unchanged
,
121 "A.3" => ProcessResult
::Changed(vec
!["A.3.i"]),
122 "D" => ProcessResult
::Changed(vec
!["D.1", "D.2"]),
123 "A.3.i" | "D.1" | "D.2" => ProcessResult
::Unchanged
,
128 assert_eq
!(ok
, Vec
::<&'
static str>::new());
129 assert_eq
!(err
, Vec
::new());
131 // third round: ok in A.1 but trigger an error in A.2. Check that it
132 // propagates to A, but not D.1 or D.2.
133 // D |-> D.1 |-> D.1.i
135 let TestOutcome { completed: ok, errors: err, .. }
= forest
.process_obligations(&mut C(
136 |obligation
| match *obligation
{
137 "A.1" => ProcessResult
::Changed(vec
![]),
138 "A.2" => ProcessResult
::Error("A is for apple"),
139 "A.3.i" => ProcessResult
::Changed(vec
![]),
140 "D.1" => ProcessResult
::Changed(vec
!["D.1.i"]),
141 "D.2" => ProcessResult
::Changed(vec
!["D.2.i"]),
142 "D.1.i" | "D.2.i" => ProcessResult
::Unchanged
,
149 assert_eq
!(ok
, vec
!["A.1", "A.3", "A.3.i"]);
150 assert_eq
!(err
, vec
![Error { error: "A is for apple", backtrace: vec!["A.2", "A"] }
]);
152 // fourth round: error in D.1.i
153 let TestOutcome { completed: ok, errors: err, .. }
= forest
.process_obligations(&mut C(
154 |obligation
| match *obligation
{
155 "D.1.i" => ProcessResult
::Error("D is for dumb"),
156 "D.2.i" => ProcessResult
::Changed(vec
![]),
157 _
=> panic
!("unexpected obligation {:?}", obligation
),
163 assert_eq
!(ok
, vec
!["D.2", "D.2.i"]);
164 assert_eq
!(err
, vec
![Error { error: "D is for dumb", backtrace: vec!["D.1.i", "D.1", "D"] }
]);
167 // Test that if a tree with grandchildren succeeds, everything is
168 // reported as expected:
176 fn success_in_grandchildren() {
177 let mut forest
= ObligationForest
::new();
178 forest
.register_obligation("A");
180 let TestOutcome { completed: ok, errors: err, .. }
= forest
.process_obligations(&mut C(
181 |obligation
| match *obligation
{
182 "A" => ProcessResult
::Changed(vec
!["A.1", "A.2", "A.3"]),
183 "A.1" => ProcessResult
::Changed(vec
![]),
184 "A.2" => ProcessResult
::Changed(vec
!["A.2.i", "A.2.ii"]),
185 "A.3" => ProcessResult
::Changed(vec
![]),
186 "A.2.i" | "A.2.ii" => ProcessResult
::Unchanged
,
193 assert_eq
!(ok
, vec
!["A.1", "A.3"]);
194 assert
!(err
.is_empty());
196 let TestOutcome { completed: ok, errors: err, .. }
= forest
.process_obligations(&mut C(
197 |obligation
| match *obligation
{
198 "A.2.i" => ProcessResult
::Unchanged
,
199 "A.2.ii" => ProcessResult
::Changed(vec
![]),
204 assert_eq
!(ok
, vec
!["A.2.ii"]);
205 assert
!(err
.is_empty());
207 let TestOutcome { completed: ok, errors: err, .. }
= forest
.process_obligations(&mut C(
208 |obligation
| match *obligation
{
209 "A.2.i" => ProcessResult
::Changed(vec
!["A.2.i.a"]),
210 "A.2.i.a" => ProcessResult
::Unchanged
,
215 assert
!(ok
.is_empty());
216 assert
!(err
.is_empty());
218 let TestOutcome { completed: ok, errors: err, .. }
= forest
.process_obligations(&mut C(
219 |obligation
| match *obligation
{
220 "A.2.i.a" => ProcessResult
::Changed(vec
![]),
227 assert_eq
!(ok
, vec
!["A", "A.2", "A.2.i", "A.2.i.a"]);
228 assert
!(err
.is_empty());
230 let TestOutcome { completed: ok, errors: err, .. }
=
231 forest
.process_obligations(&mut C(|_
| unreachable
!(), |_
| {}
));
233 assert
!(ok
.is_empty());
234 assert
!(err
.is_empty());
238 fn to_errors_no_throw() {
239 // check that converting multiple children with common parent (A)
240 // yields to correct errors (and does not panic, in particular).
241 let mut forest
= ObligationForest
::new();
242 forest
.register_obligation("A");
243 let TestOutcome { completed: ok, errors: err, .. }
= forest
.process_obligations(&mut C(
244 |obligation
| match *obligation
{
245 "A" => ProcessResult
::Changed(vec
!["A.1", "A.2", "A.3"]),
246 "A.1" | "A.2" | "A.3" => ProcessResult
::Unchanged
,
251 assert_eq
!(ok
.len(), 0);
252 assert_eq
!(err
.len(), 0);
253 let errors
= forest
.to_errors(());
254 assert_eq
!(errors
[0].backtrace
, vec
!["A.1", "A"]);
255 assert_eq
!(errors
[1].backtrace
, vec
!["A.2", "A"]);
256 assert_eq
!(errors
[2].backtrace
, vec
!["A.3", "A"]);
257 assert_eq
!(errors
.len(), 3);
262 // check that diamond dependencies are handled correctly
263 let mut forest
= ObligationForest
::new();
264 forest
.register_obligation("A");
265 let TestOutcome { completed: ok, errors: err, .. }
= forest
.process_obligations(&mut C(
266 |obligation
| match *obligation
{
267 "A" => ProcessResult
::Changed(vec
!["A.1", "A.2"]),
268 "A.1" | "A.2" => ProcessResult
::Unchanged
,
273 assert_eq
!(ok
.len(), 0);
274 assert_eq
!(err
.len(), 0);
276 let TestOutcome { completed: ok, errors: err, .. }
= forest
.process_obligations(&mut C(
277 |obligation
| match *obligation
{
278 "A.1" => ProcessResult
::Changed(vec
!["D"]),
279 "A.2" => ProcessResult
::Changed(vec
!["D"]),
280 "D" => ProcessResult
::Unchanged
,
285 assert_eq
!(ok
.len(), 0);
286 assert_eq
!(err
.len(), 0);
289 let TestOutcome { completed: ok, errors: err, .. }
= forest
.process_obligations(&mut C(
290 |obligation
| match *obligation
{
293 ProcessResult
::Changed(vec
![])
299 assert_eq
!(d_count
, 1);
302 assert_eq
!(ok
, vec
!["A", "A.1", "A.2", "D"]);
303 assert_eq
!(err
.len(), 0);
305 let errors
= forest
.to_errors(());
306 assert_eq
!(errors
.len(), 0);
308 forest
.register_obligation("A'");
309 let TestOutcome { completed: ok, errors: err, .. }
= forest
.process_obligations(&mut C(
310 |obligation
| match *obligation
{
311 "A'" => ProcessResult
::Changed(vec
!["A'.1", "A'.2"]),
312 "A'.1" | "A'.2" => ProcessResult
::Unchanged
,
317 assert_eq
!(ok
.len(), 0);
318 assert_eq
!(err
.len(), 0);
320 let TestOutcome { completed: ok, errors: err, .. }
= forest
.process_obligations(&mut C(
321 |obligation
| match *obligation
{
322 "A'.1" => ProcessResult
::Changed(vec
!["D'", "A'"]),
323 "A'.2" => ProcessResult
::Changed(vec
!["D'"]),
324 "D'" | "A'" => ProcessResult
::Unchanged
,
329 assert_eq
!(ok
.len(), 0);
330 assert_eq
!(err
.len(), 0);
333 let TestOutcome { completed: ok, errors: err, .. }
= forest
.process_obligations(&mut C(
334 |obligation
| match *obligation
{
337 ProcessResult
::Error("operation failed")
343 assert_eq
!(d_count
, 1);
344 assert_eq
!(ok
.len(), 0);
347 vec
![super::Error { error: "operation failed", backtrace: vec!["D'", "A'.1", "A'"] }
]
350 let errors
= forest
.to_errors(());
351 assert_eq
!(errors
.len(), 0);
355 fn done_dependency() {
356 // check that the local cache works
357 let mut forest
= ObligationForest
::new();
358 forest
.register_obligation("A: Sized");
359 forest
.register_obligation("B: Sized");
360 forest
.register_obligation("C: Sized");
362 let TestOutcome { completed: ok, errors: err, .. }
= forest
.process_obligations(&mut C(
363 |obligation
| match *obligation
{
364 "A: Sized" | "B: Sized" | "C: Sized" => ProcessResult
::Changed(vec
![]),
371 assert_eq
!(ok
, vec
!["A: Sized", "B: Sized", "C: Sized"]);
372 assert_eq
!(err
.len(), 0);
374 forest
.register_obligation("(A,B,C): Sized");
375 let TestOutcome { completed: ok, errors: err, .. }
= forest
.process_obligations(&mut C(
376 |obligation
| match *obligation
{
377 "(A,B,C): Sized" => ProcessResult
::Changed(vec
!["A: Sized", "B: Sized", "C: Sized"]),
382 assert_eq
!(ok
, vec
!["(A,B,C): Sized"]);
383 assert_eq
!(err
.len(), 0);
388 // check that orphaned nodes are handled correctly
389 let mut forest
= ObligationForest
::new();
390 forest
.register_obligation("A");
391 forest
.register_obligation("B");
392 forest
.register_obligation("C1");
393 forest
.register_obligation("C2");
395 let TestOutcome { completed: ok, errors: err, .. }
= forest
.process_obligations(&mut C(
396 |obligation
| match *obligation
{
397 "A" => ProcessResult
::Changed(vec
!["D", "E"]),
398 "B" => ProcessResult
::Unchanged
,
399 "C1" => ProcessResult
::Changed(vec
![]),
400 "C2" => ProcessResult
::Changed(vec
![]),
401 "D" | "E" => ProcessResult
::Unchanged
,
408 assert_eq
!(ok
, vec
!["C1", "C2"]);
409 assert_eq
!(err
.len(), 0);
411 let TestOutcome { completed: ok, errors: err, .. }
= forest
.process_obligations(&mut C(
412 |obligation
| match *obligation
{
413 "D" | "E" => ProcessResult
::Unchanged
,
414 "B" => ProcessResult
::Changed(vec
!["D"]),
419 assert_eq
!(ok
.len(), 0);
420 assert_eq
!(err
.len(), 0);
422 let TestOutcome { completed: ok, errors: err, .. }
= forest
.process_obligations(&mut C(
423 |obligation
| match *obligation
{
424 "D" => ProcessResult
::Unchanged
,
425 "E" => ProcessResult
::Error("E is for error"),
430 assert_eq
!(ok
.len(), 0);
431 assert_eq
!(err
, vec
![super::Error { error: "E is for error", backtrace: vec!["E", "A"] }
]);
433 let TestOutcome { completed: ok, errors: err, .. }
= forest
.process_obligations(&mut C(
434 |obligation
| match *obligation
{
435 "D" => ProcessResult
::Error("D is dead"),
440 assert_eq
!(ok
.len(), 0);
441 assert_eq
!(err
, vec
![super::Error { error: "D is dead", backtrace: vec!["D"] }
]);
443 let errors
= forest
.to_errors(());
444 assert_eq
!(errors
.len(), 0);
448 fn simultaneous_register_and_error() {
449 // check that registering a failed obligation works correctly
450 let mut forest
= ObligationForest
::new();
451 forest
.register_obligation("A");
452 forest
.register_obligation("B");
454 let TestOutcome { completed: ok, errors: err, .. }
= forest
.process_obligations(&mut C(
455 |obligation
| match *obligation
{
456 "A" => ProcessResult
::Error("An error"),
457 "B" => ProcessResult
::Changed(vec
!["A"]),
462 assert_eq
!(ok
.len(), 0);
463 assert_eq
!(err
, vec
![super::Error { error: "An error", backtrace: vec!["A"] }
]);
465 let mut forest
= ObligationForest
::new();
466 forest
.register_obligation("B");
467 forest
.register_obligation("A");
469 let TestOutcome { completed: ok, errors: err, .. }
= forest
.process_obligations(&mut C(
470 |obligation
| match *obligation
{
471 "A" => ProcessResult
::Error("An error"),
472 "B" => ProcessResult
::Changed(vec
!["A"]),
477 assert_eq
!(ok
.len(), 0);
478 assert_eq
!(err
, vec
![super::Error { error: "An error", backtrace: vec!["A"] }
]);