mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-02 07:22:42 +00:00
Turn Outcome into an opaque type to remove some runtime checks
This commit is contained in:
parent
5f11e71721
commit
8c7a8a62dd
@ -251,12 +251,22 @@ enum NodeState {
|
||||
Error,
|
||||
}
|
||||
|
||||
/// This trait allows us to have two different Outcome types:
|
||||
/// - the normal one that does as little as possible
|
||||
/// - one for tests that does some additional work and checking
|
||||
pub trait OutcomeTrait {
|
||||
type Error;
|
||||
type Obligation;
|
||||
|
||||
fn new() -> Self;
|
||||
fn mark_not_stalled(&mut self);
|
||||
fn is_stalled(&self) -> bool;
|
||||
fn record_completed(&mut self, outcome: &Self::Obligation);
|
||||
fn record_error(&mut self, error: Self::Error);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Outcome<O, E> {
|
||||
/// Obligations that were completely evaluated, including all
|
||||
/// (transitive) subobligations. Only computed if requested.
|
||||
pub completed: Option<Vec<O>>,
|
||||
|
||||
/// Backtrace of obligations that were found to be in error.
|
||||
pub errors: Vec<Error<O, E>>,
|
||||
|
||||
@ -269,12 +279,29 @@ pub struct Outcome<O, E> {
|
||||
pub stalled: bool,
|
||||
}
|
||||
|
||||
/// Should `process_obligations` compute the `Outcome::completed` field of its
|
||||
/// result?
|
||||
#[derive(PartialEq)]
|
||||
pub enum DoCompleted {
|
||||
No,
|
||||
Yes,
|
||||
impl<O, E> OutcomeTrait for Outcome<O, E> {
|
||||
type Error = Error<O, E>;
|
||||
type Obligation = O;
|
||||
|
||||
fn new() -> Self {
|
||||
Self { stalled: true, errors: vec![] }
|
||||
}
|
||||
|
||||
fn mark_not_stalled(&mut self) {
|
||||
self.stalled = false;
|
||||
}
|
||||
|
||||
fn is_stalled(&self) -> bool {
|
||||
self.stalled
|
||||
}
|
||||
|
||||
fn record_completed(&mut self, _outcome: &Self::Obligation) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
fn record_error(&mut self, error: Self::Error) {
|
||||
self.errors.push(error)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
@ -363,8 +390,7 @@ impl<O: ForestObligation> ObligationForest<O> {
|
||||
.map(|(index, _node)| Error { error: error.clone(), backtrace: self.error_at(index) })
|
||||
.collect();
|
||||
|
||||
let successful_obligations = self.compress(DoCompleted::Yes);
|
||||
assert!(successful_obligations.unwrap().is_empty());
|
||||
self.compress(|_| assert!(false));
|
||||
errors
|
||||
}
|
||||
|
||||
@ -392,16 +418,12 @@ impl<O: ForestObligation> ObligationForest<O> {
|
||||
/// be called in a loop until `outcome.stalled` is false.
|
||||
///
|
||||
/// This _cannot_ be unrolled (presently, at least).
|
||||
pub fn process_obligations<P>(
|
||||
&mut self,
|
||||
processor: &mut P,
|
||||
do_completed: DoCompleted,
|
||||
) -> Outcome<O, P::Error>
|
||||
pub fn process_obligations<P, OUT>(&mut self, processor: &mut P) -> OUT
|
||||
where
|
||||
P: ObligationProcessor<Obligation = O>,
|
||||
OUT: OutcomeTrait<Obligation = O, Error = Error<O, P::Error>>,
|
||||
{
|
||||
let mut errors = vec![];
|
||||
let mut stalled = true;
|
||||
let mut outcome = OUT::new();
|
||||
|
||||
// Note that the loop body can append new nodes, and those new nodes
|
||||
// will then be processed by subsequent iterations of the loop.
|
||||
@ -429,7 +451,7 @@ impl<O: ForestObligation> ObligationForest<O> {
|
||||
}
|
||||
ProcessResult::Changed(children) => {
|
||||
// We are not (yet) stalled.
|
||||
stalled = false;
|
||||
outcome.mark_not_stalled();
|
||||
node.state.set(NodeState::Success);
|
||||
|
||||
for child in children {
|
||||
@ -442,28 +464,22 @@ impl<O: ForestObligation> ObligationForest<O> {
|
||||
}
|
||||
}
|
||||
ProcessResult::Error(err) => {
|
||||
stalled = false;
|
||||
errors.push(Error { error: err, backtrace: self.error_at(index) });
|
||||
outcome.mark_not_stalled();
|
||||
outcome.record_error(Error { error: err, backtrace: self.error_at(index) });
|
||||
}
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
|
||||
if stalled {
|
||||
// There's no need to perform marking, cycle processing and compression when nothing
|
||||
// changed.
|
||||
return Outcome {
|
||||
completed: if do_completed == DoCompleted::Yes { Some(vec![]) } else { None },
|
||||
errors,
|
||||
stalled,
|
||||
};
|
||||
// There's no need to perform marking, cycle processing and compression when nothing
|
||||
// changed.
|
||||
if !outcome.is_stalled() {
|
||||
self.mark_successes();
|
||||
self.process_cycles(processor);
|
||||
self.compress(|obl| outcome.record_completed(obl));
|
||||
}
|
||||
|
||||
self.mark_successes();
|
||||
self.process_cycles(processor);
|
||||
let completed = self.compress(do_completed);
|
||||
|
||||
Outcome { completed, errors, stalled }
|
||||
outcome
|
||||
}
|
||||
|
||||
/// Returns a vector of obligations for `p` and all of its
|
||||
@ -592,13 +608,12 @@ impl<O: ForestObligation> ObligationForest<O> {
|
||||
/// indices and hence invalidates any outstanding indices. `process_cycles`
|
||||
/// must be run beforehand to remove any cycles on `Success` nodes.
|
||||
#[inline(never)]
|
||||
fn compress(&mut self, do_completed: DoCompleted) -> Option<Vec<O>> {
|
||||
fn compress(&mut self, mut outcome_cb: impl FnMut(&O)) {
|
||||
let orig_nodes_len = self.nodes.len();
|
||||
let mut node_rewrites: Vec<_> = std::mem::take(&mut self.reused_node_vec);
|
||||
debug_assert!(node_rewrites.is_empty());
|
||||
node_rewrites.extend(0..orig_nodes_len);
|
||||
let mut dead_nodes = 0;
|
||||
let mut removed_done_obligations: Vec<O> = vec![];
|
||||
|
||||
// Move removable nodes to the end, preserving the order of the
|
||||
// remaining nodes.
|
||||
@ -628,10 +643,8 @@ impl<O: ForestObligation> ObligationForest<O> {
|
||||
} else {
|
||||
self.done_cache.insert(node.obligation.as_cache_key().clone());
|
||||
}
|
||||
if do_completed == DoCompleted::Yes {
|
||||
// Extract the success stories.
|
||||
removed_done_obligations.push(node.obligation.clone());
|
||||
}
|
||||
// Extract the success stories.
|
||||
outcome_cb(&node.obligation);
|
||||
node_rewrites[index] = orig_nodes_len;
|
||||
dead_nodes += 1;
|
||||
}
|
||||
@ -656,8 +669,6 @@ impl<O: ForestObligation> ObligationForest<O> {
|
||||
|
||||
node_rewrites.truncate(0);
|
||||
self.reused_node_vec = node_rewrites;
|
||||
|
||||
if do_completed == DoCompleted::Yes { Some(removed_done_obligations) } else { None }
|
||||
}
|
||||
|
||||
fn apply_rewrites(&mut self, node_rewrites: &[usize]) {
|
||||
|
@ -17,6 +17,40 @@ struct ClosureObligationProcessor<OF, BF, O, E> {
|
||||
marker: PhantomData<(O, E)>,
|
||||
}
|
||||
|
||||
struct TestOutcome<O, E> {
|
||||
pub completed: Vec<O>,
|
||||
pub errors: Vec<Error<O, E>>,
|
||||
pub stalled: bool,
|
||||
}
|
||||
|
||||
impl<O, E> OutcomeTrait for TestOutcome<O, E>
|
||||
where
|
||||
O: Clone,
|
||||
{
|
||||
type Error = Error<O, E>;
|
||||
type Obligation = O;
|
||||
|
||||
fn new() -> Self {
|
||||
Self { errors: vec![], stalled: false, completed: vec![] }
|
||||
}
|
||||
|
||||
fn mark_not_stalled(&mut self) {
|
||||
self.stalled = false;
|
||||
}
|
||||
|
||||
fn is_stalled(&self) -> bool {
|
||||
self.stalled
|
||||
}
|
||||
|
||||
fn record_completed(&mut self, outcome: &Self::Obligation) {
|
||||
self.completed.push(outcome.clone())
|
||||
}
|
||||
|
||||
fn record_error(&mut self, error: Self::Error) {
|
||||
self.errors.push(error)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn C<OF, BF, O>(of: OF, bf: BF) -> ClosureObligationProcessor<OF, BF, O, &'static str>
|
||||
where
|
||||
@ -65,20 +99,17 @@ fn push_pop() {
|
||||
// A |-> A.1
|
||||
// |-> A.2
|
||||
// |-> A.3
|
||||
let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
|
||||
&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
|
||||
"B" => ProcessResult::Error("B is for broken"),
|
||||
"C" => ProcessResult::Changed(vec![]),
|
||||
"A.1" | "A.2" | "A.3" => ProcessResult::Unchanged,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
),
|
||||
DoCompleted::Yes,
|
||||
);
|
||||
assert_eq!(ok.unwrap(), vec!["C"]);
|
||||
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
|
||||
"B" => ProcessResult::Error("B is for broken"),
|
||||
"C" => ProcessResult::Changed(vec![]),
|
||||
"A.1" | "A.2" | "A.3" => ProcessResult::Unchanged,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
));
|
||||
assert_eq!(ok, vec!["C"]);
|
||||
assert_eq!(err, vec![Error { error: "B is for broken", backtrace: vec!["B"] }]);
|
||||
|
||||
// second round: two delays, one success, creating an uneven set of subtasks:
|
||||
@ -88,60 +119,51 @@ fn push_pop() {
|
||||
// D |-> D.1
|
||||
// |-> D.2
|
||||
forest.register_obligation("D");
|
||||
let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
|
||||
&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A.1" => ProcessResult::Unchanged,
|
||||
"A.2" => ProcessResult::Unchanged,
|
||||
"A.3" => ProcessResult::Changed(vec!["A.3.i"]),
|
||||
"D" => ProcessResult::Changed(vec!["D.1", "D.2"]),
|
||||
"A.3.i" | "D.1" | "D.2" => ProcessResult::Unchanged,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
),
|
||||
DoCompleted::Yes,
|
||||
);
|
||||
assert_eq!(ok.unwrap(), Vec::<&'static str>::new());
|
||||
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A.1" => ProcessResult::Unchanged,
|
||||
"A.2" => ProcessResult::Unchanged,
|
||||
"A.3" => ProcessResult::Changed(vec!["A.3.i"]),
|
||||
"D" => ProcessResult::Changed(vec!["D.1", "D.2"]),
|
||||
"A.3.i" | "D.1" | "D.2" => ProcessResult::Unchanged,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
));
|
||||
assert_eq!(ok, Vec::<&'static str>::new());
|
||||
assert_eq!(err, Vec::new());
|
||||
|
||||
// third round: ok in A.1 but trigger an error in A.2. Check that it
|
||||
// propagates to A, but not D.1 or D.2.
|
||||
// D |-> D.1 |-> D.1.i
|
||||
// |-> D.2 |-> D.2.i
|
||||
let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
|
||||
&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A.1" => ProcessResult::Changed(vec![]),
|
||||
"A.2" => ProcessResult::Error("A is for apple"),
|
||||
"A.3.i" => ProcessResult::Changed(vec![]),
|
||||
"D.1" => ProcessResult::Changed(vec!["D.1.i"]),
|
||||
"D.2" => ProcessResult::Changed(vec!["D.2.i"]),
|
||||
"D.1.i" | "D.2.i" => ProcessResult::Unchanged,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
),
|
||||
DoCompleted::Yes,
|
||||
);
|
||||
let mut ok = ok.unwrap();
|
||||
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A.1" => ProcessResult::Changed(vec![]),
|
||||
"A.2" => ProcessResult::Error("A is for apple"),
|
||||
"A.3.i" => ProcessResult::Changed(vec![]),
|
||||
"D.1" => ProcessResult::Changed(vec!["D.1.i"]),
|
||||
"D.2" => ProcessResult::Changed(vec!["D.2.i"]),
|
||||
"D.1.i" | "D.2.i" => ProcessResult::Unchanged,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
));
|
||||
let mut ok = ok;
|
||||
ok.sort();
|
||||
assert_eq!(ok, vec!["A.1", "A.3", "A.3.i"]);
|
||||
assert_eq!(err, vec![Error { error: "A is for apple", backtrace: vec!["A.2", "A"] }]);
|
||||
|
||||
// fourth round: error in D.1.i
|
||||
let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
|
||||
&mut C(
|
||||
|obligation| match *obligation {
|
||||
"D.1.i" => ProcessResult::Error("D is for dumb"),
|
||||
"D.2.i" => ProcessResult::Changed(vec![]),
|
||||
_ => panic!("unexpected obligation {:?}", obligation),
|
||||
},
|
||||
|_| {},
|
||||
),
|
||||
DoCompleted::Yes,
|
||||
);
|
||||
let mut ok = ok.unwrap();
|
||||
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|
||||
|obligation| match *obligation {
|
||||
"D.1.i" => ProcessResult::Error("D is for dumb"),
|
||||
"D.2.i" => ProcessResult::Changed(vec![]),
|
||||
_ => panic!("unexpected obligation {:?}", obligation),
|
||||
},
|
||||
|_| {},
|
||||
));
|
||||
let mut ok = ok;
|
||||
ok.sort();
|
||||
assert_eq!(ok, vec!["D.2", "D.2.i"]);
|
||||
assert_eq!(err, vec![Error { error: "D is for dumb", backtrace: vec!["D.1.i", "D.1", "D"] }]);
|
||||
@ -160,72 +182,60 @@ fn success_in_grandchildren() {
|
||||
let mut forest = ObligationForest::new();
|
||||
forest.register_obligation("A");
|
||||
|
||||
let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
|
||||
&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
|
||||
"A.1" => ProcessResult::Changed(vec![]),
|
||||
"A.2" => ProcessResult::Changed(vec!["A.2.i", "A.2.ii"]),
|
||||
"A.3" => ProcessResult::Changed(vec![]),
|
||||
"A.2.i" | "A.2.ii" => ProcessResult::Unchanged,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
),
|
||||
DoCompleted::Yes,
|
||||
);
|
||||
let mut ok = ok.unwrap();
|
||||
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
|
||||
"A.1" => ProcessResult::Changed(vec![]),
|
||||
"A.2" => ProcessResult::Changed(vec!["A.2.i", "A.2.ii"]),
|
||||
"A.3" => ProcessResult::Changed(vec![]),
|
||||
"A.2.i" | "A.2.ii" => ProcessResult::Unchanged,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
));
|
||||
let mut ok = ok;
|
||||
ok.sort();
|
||||
assert_eq!(ok, vec!["A.1", "A.3"]);
|
||||
assert!(err.is_empty());
|
||||
|
||||
let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
|
||||
&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A.2.i" => ProcessResult::Unchanged,
|
||||
"A.2.ii" => ProcessResult::Changed(vec![]),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
),
|
||||
DoCompleted::Yes,
|
||||
);
|
||||
assert_eq!(ok.unwrap(), vec!["A.2.ii"]);
|
||||
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A.2.i" => ProcessResult::Unchanged,
|
||||
"A.2.ii" => ProcessResult::Changed(vec![]),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
));
|
||||
assert_eq!(ok, vec!["A.2.ii"]);
|
||||
assert!(err.is_empty());
|
||||
|
||||
let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
|
||||
&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A.2.i" => ProcessResult::Changed(vec!["A.2.i.a"]),
|
||||
"A.2.i.a" => ProcessResult::Unchanged,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
),
|
||||
DoCompleted::Yes,
|
||||
);
|
||||
assert!(ok.unwrap().is_empty());
|
||||
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A.2.i" => ProcessResult::Changed(vec!["A.2.i.a"]),
|
||||
"A.2.i.a" => ProcessResult::Unchanged,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
));
|
||||
assert!(ok.is_empty());
|
||||
assert!(err.is_empty());
|
||||
|
||||
let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
|
||||
&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A.2.i.a" => ProcessResult::Changed(vec![]),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
),
|
||||
DoCompleted::Yes,
|
||||
);
|
||||
let mut ok = ok.unwrap();
|
||||
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A.2.i.a" => ProcessResult::Changed(vec![]),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
));
|
||||
let mut ok = ok;
|
||||
ok.sort();
|
||||
assert_eq!(ok, vec!["A", "A.2", "A.2.i", "A.2.i.a"]);
|
||||
assert!(err.is_empty());
|
||||
|
||||
let Outcome { completed: ok, errors: err, .. } =
|
||||
forest.process_obligations(&mut C(|_| unreachable!(), |_| {}), DoCompleted::Yes);
|
||||
let TestOutcome { completed: ok, errors: err, .. } =
|
||||
forest.process_obligations(&mut C(|_| unreachable!(), |_| {}));
|
||||
|
||||
assert!(ok.unwrap().is_empty());
|
||||
assert!(ok.is_empty());
|
||||
assert!(err.is_empty());
|
||||
}
|
||||
|
||||
@ -235,18 +245,15 @@ fn to_errors_no_throw() {
|
||||
// yields to correct errors (and does not panic, in particular).
|
||||
let mut forest = ObligationForest::new();
|
||||
forest.register_obligation("A");
|
||||
let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
|
||||
&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
|
||||
"A.1" | "A.2" | "A.3" => ProcessResult::Unchanged,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
),
|
||||
DoCompleted::Yes,
|
||||
);
|
||||
assert_eq!(ok.unwrap().len(), 0);
|
||||
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
|
||||
"A.1" | "A.2" | "A.3" => ProcessResult::Unchanged,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
));
|
||||
assert_eq!(ok.len(), 0);
|
||||
assert_eq!(err.len(), 0);
|
||||
let errors = forest.to_errors(());
|
||||
assert_eq!(errors[0].backtrace, vec!["A.1", "A"]);
|
||||
@ -260,51 +267,42 @@ fn diamond() {
|
||||
// check that diamond dependencies are handled correctly
|
||||
let mut forest = ObligationForest::new();
|
||||
forest.register_obligation("A");
|
||||
let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
|
||||
&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A" => ProcessResult::Changed(vec!["A.1", "A.2"]),
|
||||
"A.1" | "A.2" => ProcessResult::Unchanged,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
),
|
||||
DoCompleted::Yes,
|
||||
);
|
||||
assert_eq!(ok.unwrap().len(), 0);
|
||||
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A" => ProcessResult::Changed(vec!["A.1", "A.2"]),
|
||||
"A.1" | "A.2" => ProcessResult::Unchanged,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
));
|
||||
assert_eq!(ok.len(), 0);
|
||||
assert_eq!(err.len(), 0);
|
||||
|
||||
let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
|
||||
&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A.1" => ProcessResult::Changed(vec!["D"]),
|
||||
"A.2" => ProcessResult::Changed(vec!["D"]),
|
||||
"D" => ProcessResult::Unchanged,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
),
|
||||
DoCompleted::Yes,
|
||||
);
|
||||
assert_eq!(ok.unwrap().len(), 0);
|
||||
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A.1" => ProcessResult::Changed(vec!["D"]),
|
||||
"A.2" => ProcessResult::Changed(vec!["D"]),
|
||||
"D" => ProcessResult::Unchanged,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
));
|
||||
assert_eq!(ok.len(), 0);
|
||||
assert_eq!(err.len(), 0);
|
||||
|
||||
let mut d_count = 0;
|
||||
let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
|
||||
&mut C(
|
||||
|obligation| match *obligation {
|
||||
"D" => {
|
||||
d_count += 1;
|
||||
ProcessResult::Changed(vec![])
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
),
|
||||
DoCompleted::Yes,
|
||||
);
|
||||
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|
||||
|obligation| match *obligation {
|
||||
"D" => {
|
||||
d_count += 1;
|
||||
ProcessResult::Changed(vec![])
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
));
|
||||
assert_eq!(d_count, 1);
|
||||
let mut ok = ok.unwrap();
|
||||
let mut ok = ok;
|
||||
ok.sort();
|
||||
assert_eq!(ok, vec!["A", "A.1", "A.2", "D"]);
|
||||
assert_eq!(err.len(), 0);
|
||||
@ -313,51 +311,42 @@ fn diamond() {
|
||||
assert_eq!(errors.len(), 0);
|
||||
|
||||
forest.register_obligation("A'");
|
||||
let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
|
||||
&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A'" => ProcessResult::Changed(vec!["A'.1", "A'.2"]),
|
||||
"A'.1" | "A'.2" => ProcessResult::Unchanged,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
),
|
||||
DoCompleted::Yes,
|
||||
);
|
||||
assert_eq!(ok.unwrap().len(), 0);
|
||||
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A'" => ProcessResult::Changed(vec!["A'.1", "A'.2"]),
|
||||
"A'.1" | "A'.2" => ProcessResult::Unchanged,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
));
|
||||
assert_eq!(ok.len(), 0);
|
||||
assert_eq!(err.len(), 0);
|
||||
|
||||
let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
|
||||
&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A'.1" => ProcessResult::Changed(vec!["D'", "A'"]),
|
||||
"A'.2" => ProcessResult::Changed(vec!["D'"]),
|
||||
"D'" | "A'" => ProcessResult::Unchanged,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
),
|
||||
DoCompleted::Yes,
|
||||
);
|
||||
assert_eq!(ok.unwrap().len(), 0);
|
||||
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A'.1" => ProcessResult::Changed(vec!["D'", "A'"]),
|
||||
"A'.2" => ProcessResult::Changed(vec!["D'"]),
|
||||
"D'" | "A'" => ProcessResult::Unchanged,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
));
|
||||
assert_eq!(ok.len(), 0);
|
||||
assert_eq!(err.len(), 0);
|
||||
|
||||
let mut d_count = 0;
|
||||
let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
|
||||
&mut C(
|
||||
|obligation| match *obligation {
|
||||
"D'" => {
|
||||
d_count += 1;
|
||||
ProcessResult::Error("operation failed")
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
),
|
||||
DoCompleted::Yes,
|
||||
);
|
||||
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|
||||
|obligation| match *obligation {
|
||||
"D'" => {
|
||||
d_count += 1;
|
||||
ProcessResult::Error("operation failed")
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
));
|
||||
assert_eq!(d_count, 1);
|
||||
assert_eq!(ok.unwrap().len(), 0);
|
||||
assert_eq!(ok.len(), 0);
|
||||
assert_eq!(
|
||||
err,
|
||||
vec![super::Error { error: "operation failed", backtrace: vec!["D'", "A'.1", "A'"] }]
|
||||
@ -375,35 +364,27 @@ fn done_dependency() {
|
||||
forest.register_obligation("B: Sized");
|
||||
forest.register_obligation("C: Sized");
|
||||
|
||||
let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
|
||||
&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A: Sized" | "B: Sized" | "C: Sized" => ProcessResult::Changed(vec![]),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
),
|
||||
DoCompleted::Yes,
|
||||
);
|
||||
let mut ok = ok.unwrap();
|
||||
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A: Sized" | "B: Sized" | "C: Sized" => ProcessResult::Changed(vec![]),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
));
|
||||
let mut ok = ok;
|
||||
ok.sort();
|
||||
assert_eq!(ok, vec!["A: Sized", "B: Sized", "C: Sized"]);
|
||||
assert_eq!(err.len(), 0);
|
||||
|
||||
forest.register_obligation("(A,B,C): Sized");
|
||||
let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
|
||||
&mut C(
|
||||
|obligation| match *obligation {
|
||||
"(A,B,C): Sized" => {
|
||||
ProcessResult::Changed(vec!["A: Sized", "B: Sized", "C: Sized"])
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
),
|
||||
DoCompleted::Yes,
|
||||
);
|
||||
assert_eq!(ok.unwrap(), vec!["(A,B,C): Sized"]);
|
||||
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|
||||
|obligation| match *obligation {
|
||||
"(A,B,C): Sized" => ProcessResult::Changed(vec!["A: Sized", "B: Sized", "C: Sized"]),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
));
|
||||
assert_eq!(ok, vec!["(A,B,C): Sized"]);
|
||||
assert_eq!(err.len(), 0);
|
||||
}
|
||||
|
||||
@ -416,64 +397,52 @@ fn orphan() {
|
||||
forest.register_obligation("C1");
|
||||
forest.register_obligation("C2");
|
||||
|
||||
let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
|
||||
&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A" => ProcessResult::Changed(vec!["D", "E"]),
|
||||
"B" => ProcessResult::Unchanged,
|
||||
"C1" => ProcessResult::Changed(vec![]),
|
||||
"C2" => ProcessResult::Changed(vec![]),
|
||||
"D" | "E" => ProcessResult::Unchanged,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
),
|
||||
DoCompleted::Yes,
|
||||
);
|
||||
let mut ok = ok.unwrap();
|
||||
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A" => ProcessResult::Changed(vec!["D", "E"]),
|
||||
"B" => ProcessResult::Unchanged,
|
||||
"C1" => ProcessResult::Changed(vec![]),
|
||||
"C2" => ProcessResult::Changed(vec![]),
|
||||
"D" | "E" => ProcessResult::Unchanged,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
));
|
||||
let mut ok = ok;
|
||||
ok.sort();
|
||||
assert_eq!(ok, vec!["C1", "C2"]);
|
||||
assert_eq!(err.len(), 0);
|
||||
|
||||
let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
|
||||
&mut C(
|
||||
|obligation| match *obligation {
|
||||
"D" | "E" => ProcessResult::Unchanged,
|
||||
"B" => ProcessResult::Changed(vec!["D"]),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
),
|
||||
DoCompleted::Yes,
|
||||
);
|
||||
assert_eq!(ok.unwrap().len(), 0);
|
||||
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|
||||
|obligation| match *obligation {
|
||||
"D" | "E" => ProcessResult::Unchanged,
|
||||
"B" => ProcessResult::Changed(vec!["D"]),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
));
|
||||
assert_eq!(ok.len(), 0);
|
||||
assert_eq!(err.len(), 0);
|
||||
|
||||
let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
|
||||
&mut C(
|
||||
|obligation| match *obligation {
|
||||
"D" => ProcessResult::Unchanged,
|
||||
"E" => ProcessResult::Error("E is for error"),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
),
|
||||
DoCompleted::Yes,
|
||||
);
|
||||
assert_eq!(ok.unwrap().len(), 0);
|
||||
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|
||||
|obligation| match *obligation {
|
||||
"D" => ProcessResult::Unchanged,
|
||||
"E" => ProcessResult::Error("E is for error"),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
));
|
||||
assert_eq!(ok.len(), 0);
|
||||
assert_eq!(err, vec![super::Error { error: "E is for error", backtrace: vec!["E", "A"] }]);
|
||||
|
||||
let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
|
||||
&mut C(
|
||||
|obligation| match *obligation {
|
||||
"D" => ProcessResult::Error("D is dead"),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
),
|
||||
DoCompleted::Yes,
|
||||
);
|
||||
assert_eq!(ok.unwrap().len(), 0);
|
||||
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|
||||
|obligation| match *obligation {
|
||||
"D" => ProcessResult::Error("D is dead"),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
));
|
||||
assert_eq!(ok.len(), 0);
|
||||
assert_eq!(err, vec![super::Error { error: "D is dead", backtrace: vec!["D"] }]);
|
||||
|
||||
let errors = forest.to_errors(());
|
||||
@ -487,35 +456,29 @@ fn simultaneous_register_and_error() {
|
||||
forest.register_obligation("A");
|
||||
forest.register_obligation("B");
|
||||
|
||||
let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
|
||||
&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A" => ProcessResult::Error("An error"),
|
||||
"B" => ProcessResult::Changed(vec!["A"]),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
),
|
||||
DoCompleted::Yes,
|
||||
);
|
||||
assert_eq!(ok.unwrap().len(), 0);
|
||||
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A" => ProcessResult::Error("An error"),
|
||||
"B" => ProcessResult::Changed(vec!["A"]),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
));
|
||||
assert_eq!(ok.len(), 0);
|
||||
assert_eq!(err, vec![super::Error { error: "An error", backtrace: vec!["A"] }]);
|
||||
|
||||
let mut forest = ObligationForest::new();
|
||||
forest.register_obligation("B");
|
||||
forest.register_obligation("A");
|
||||
|
||||
let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(
|
||||
&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A" => ProcessResult::Error("An error"),
|
||||
"B" => ProcessResult::Changed(vec!["A"]),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
),
|
||||
DoCompleted::Yes,
|
||||
);
|
||||
assert_eq!(ok.unwrap().len(), 0);
|
||||
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|
||||
|obligation| match *obligation {
|
||||
"A" => ProcessResult::Error("An error"),
|
||||
"B" => ProcessResult::Changed(vec!["A"]),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|_| {},
|
||||
));
|
||||
assert_eq!(ok.len(), 0);
|
||||
assert_eq!(err, vec![super::Error { error: "An error", backtrace: vec!["A"] }]);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::infer::{InferCtxt, TyOrConstInferVar};
|
||||
use rustc_data_structures::obligation_forest::ProcessResult;
|
||||
use rustc_data_structures::obligation_forest::{DoCompleted, Error, ForestObligation};
|
||||
use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
|
||||
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
|
||||
use rustc_errors::ErrorReported;
|
||||
use rustc_infer::traits::{TraitEngine, TraitEngineExt as _, TraitObligation};
|
||||
@ -129,13 +129,11 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
|
||||
debug!("select: starting another iteration");
|
||||
|
||||
// Process pending obligations.
|
||||
let outcome = self.predicates.process_obligations(
|
||||
&mut FulfillProcessor {
|
||||
let outcome: Outcome<_, _> =
|
||||
self.predicates.process_obligations(&mut FulfillProcessor {
|
||||
selcx,
|
||||
register_region_obligations: self.register_region_obligations,
|
||||
},
|
||||
DoCompleted::No,
|
||||
);
|
||||
});
|
||||
debug!("select: outcome={:#?}", outcome);
|
||||
|
||||
// FIXME: if we kept the original cache key, we could mark projection
|
||||
|
Loading…
Reference in New Issue
Block a user