Skip to content

Commit 5e85289

Browse files
Merge ObligationForest's snapshots/undo_log vecs
1 parent ee33517 commit 5e85289

File tree

1 file changed

+68
-27
lines changed
  • src/librustc_data_structures/obligation_forest

1 file changed

+68
-27
lines changed

src/librustc_data_structures/obligation_forest/mod.rs

Lines changed: 68 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -38,25 +38,34 @@ pub struct ObligationForest<O> {
3838
/// at a higher index than its parent. This is needed by the
3939
/// backtrace iterator (which uses `split_at`).
4040
nodes: Vec<Node<O>>,
41-
snapshots: Vec<usize>,
4241

4342
/// List of inversion actions that may be performed to undo mutations
4443
/// while in snapshots.
45-
undo_log: Vec<UndoAction<O>>,
44+
undo_log: Vec<Action<O>>,
4645
}
4746

4847
/// A single inversion of an action on a node in an ObligationForest.
4948
#[derive(Debug)]
50-
enum UndoAction<O> {
49+
enum Action<O> {
5150
// FIXME potential optimization: store push undos as a count in the snapshots vec (because we
5251
// never remove when in a snapshot, and because snapshots are sequenced in a specific way
5352
// w.r.t. what's in the ObligationForest's undo list, it's possible to just keep track of push
5453
// counts instead of sequencing them in the undo list with node state modifications)
55-
UndoPush,
56-
UndoModify {
54+
Push,
55+
Modify {
5756
at: NodeIndex,
5857
undoer: UndoModify<O>,
5958
},
59+
60+
/// An indicator that a snapshot was opened at the actions position; does not have a meaningful
61+
/// 'undo' operation on the tree, as any time we're interested in 'undoing' this we're already
62+
/// doing so by a user having called `ObligationForest::rollback_snapshot`.
63+
OpenSnapshot,
64+
65+
/// An action that we've left sitting in the queue because it's somehow become a no-op but we
66+
/// don't want to deal with O(N) data movement in the log. At present this is always a
67+
/// committed snapshot.
68+
NoOp,
6069
}
6170

6271
/// A single inversion of a node modification action in an ObligationForest.
@@ -146,7 +155,6 @@ impl<O: Clone + Debug> ObligationForest<O> {
146155
pub fn new() -> ObligationForest<O> {
147156
ObligationForest {
148157
nodes: vec![],
149-
snapshots: vec![],
150158
undo_log: vec![],
151159
}
152160
}
@@ -158,34 +166,65 @@ impl<O: Clone + Debug> ObligationForest<O> {
158166
}
159167

160168
pub fn start_snapshot(&mut self) -> Snapshot {
161-
self.snapshots.push(self.undo_log.len());
162-
Snapshot { len: self.snapshots.len() }
169+
let result = Snapshot { len: self.undo_log.len() };
170+
self.undo_log.push(Action::OpenSnapshot);
171+
result
163172
}
164173

165174
pub fn commit_snapshot(&mut self, snapshot: Snapshot) {
166-
// Check that we are obeying stack discipline.
167-
assert_eq!(snapshot.len, self.snapshots.len());
168-
self.snapshots.pop().unwrap();
175+
// Look for the first open snapshot (which MUST be the snapshot passed to us, else
176+
// something went wrong).
177+
let mut commit_at_index = None;
178+
for (index, action) in self.undo_log.iter_mut().enumerate().rev() {
179+
commit_at_index = Some(match action {
180+
&mut Action::OpenSnapshot => index,
181+
_ => continue,
182+
});
183+
break;
184+
}
185+
// We should always have a snapshot to commit unless we've broken stack discipline at the
186+
// base.
187+
let commit_at_index = commit_at_index.unwrap();
188+
// Check that we are obeying stack discipline for anywhere that isn't the base.
189+
assert_eq!(snapshot.len, commit_at_index);
190+
mem::replace(&mut self.undo_log[commit_at_index], Action::NoOp);
169191
if !self.in_snapshot() {
170192
self.undo_log.clear();
171193
}
172194
}
173195

174196
pub fn rollback_snapshot(&mut self, snapshot: Snapshot) {
175-
// Check that we are obeying stack discipline.
176-
assert_eq!(snapshot.len, self.snapshots.len());
177-
let undo_len = self.snapshots.pop().unwrap();
197+
// Look for the first open snapshot (which MUST be the snapshot passed to us, else
198+
// something went wrong).
199+
let mut rollback_at_index = None;
200+
for (index, action) in self.undo_log.iter_mut().enumerate().rev() {
201+
rollback_at_index = Some(match action {
202+
&mut Action::OpenSnapshot => index,
203+
_ => continue,
204+
});
205+
break;
206+
}
207+
// We should always have a snapshot to commit unless we've broken stack discipline at the
208+
// base.
209+
let rollback_at_index = rollback_at_index.unwrap();
210+
// Check that we are obeying stack discipline for anywhere that isn't the base.
211+
assert_eq!(snapshot.len, rollback_at_index);
212+
213+
let undo_len = rollback_at_index;
178214

179-
let undoers: Vec<_> = (undo_len..self.undo_log.len())
215+
let actions: Vec<_> = (undo_len..self.undo_log.len())
180216
.map(|_| self.undo_log.pop().unwrap())
181217
.collect();
182-
for undoer in undoers {
183-
undoer.undo(self);
218+
for action in actions {
219+
action.undo(self);
220+
}
221+
if !self.in_snapshot() {
222+
self.compress();
184223
}
185224
}
186225

187226
pub fn in_snapshot(&self) -> bool {
188-
!self.snapshots.is_empty()
227+
!self.undo_log.is_empty()
189228
}
190229

191230
/// Adds a new tree to the forest.
@@ -195,7 +234,7 @@ impl<O: Clone + Debug> ObligationForest<O> {
195234
let index = NodeIndex::new(self.nodes.len());
196235
self.nodes.push(Node::new(index, None, obligation));
197236
if self.in_snapshot() {
198-
self.undo_log.push(UndoAction::UndoPush);
237+
self.undo_log.push(Action::Push);
199238
}
200239
}
201240

@@ -339,8 +378,8 @@ impl<O: Clone + Debug> ObligationForest<O> {
339378
}
340379

341380
if self.in_snapshot() {
342-
self.undo_log.extend((0..num_incomplete_children).map(|_| UndoAction::UndoPush));
343-
self.undo_log.push(UndoAction::UndoModify {
381+
self.undo_log.extend((0..num_incomplete_children).map(|_| Action::Push));
382+
self.undo_log.push(Action::Modify {
344383
at: NodeIndex::new(index),
345384
undoer: UndoModify::UndoPendingIntoSuccess,
346385
});
@@ -381,7 +420,7 @@ impl<O: Clone + Debug> ObligationForest<O> {
381420
if let NodeState::Error = self.nodes[root].state {
382421
let old_state = mem::replace(&mut self.nodes[child].state, NodeState::Error);
383422
if self.in_snapshot() {
384-
self.undo_log.push(UndoAction::UndoModify {
423+
self.undo_log.push(Action::Modify {
385424
at: NodeIndex::new(child),
386425
undoer: match old_state {
387426
NodeState::Pending { obligation } =>
@@ -410,7 +449,7 @@ impl<O: Clone + Debug> ObligationForest<O> {
410449
let obligation = match state {
411450
NodeState::Pending { obligation } => {
412451
if self.in_snapshot() {
413-
self.undo_log.push(UndoAction::UndoModify {
452+
self.undo_log.push(Action::Modify {
414453
at: NodeIndex::new(p),
415454
undoer: UndoModify::UndoPendingIntoError {
416455
obligation: obligation.clone()
@@ -421,7 +460,7 @@ impl<O: Clone + Debug> ObligationForest<O> {
421460
},
422461
NodeState::Success { obligation, num_incomplete_children } => {
423462
if self.in_snapshot() {
424-
self.undo_log.push(UndoAction::UndoModify {
463+
self.undo_log.push(Action::Modify {
425464
at: NodeIndex::new(p),
426465
undoer: UndoModify::UndoSuccessIntoError {
427466
obligation: obligation.clone(),
@@ -557,13 +596,15 @@ impl<'b, O> Iterator for Backtrace<'b, O> {
557596
}
558597
}
559598

560-
impl<O> UndoAction<O> {
599+
impl<O> Action<O> {
561600
fn undo(self, forest: &mut ObligationForest<O>) {
562601
match self {
563-
UndoAction::UndoPush => {
602+
Action::Push => {
564603
forest.nodes.pop().unwrap();
565604
},
566-
UndoAction::UndoModify { at, undoer } => undoer.undo(forest, at),
605+
Action::Modify { at, undoer } => undoer.undo(forest, at),
606+
Action::OpenSnapshot => {},
607+
Action::NoOp => {},
567608
}
568609
}
569610
}

0 commit comments

Comments
 (0)