Skip to content

Commit d6e5797

Browse files
committed
Introduce snapshot_vec abstraction
1 parent 790d9c4 commit d6e5797

File tree

4 files changed

+225
-137
lines changed

4 files changed

+225
-137
lines changed

src/librustc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ pub mod util {
136136
pub mod common;
137137
pub mod ppaux;
138138
pub mod nodemap;
139+
pub mod snapshot_vec;
139140
}
140141

141142
pub mod lib {

src/librustc/middle/typeck/infer/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -555,13 +555,13 @@ impl<'a> InferCtxt<'a> {
555555

556556
self.type_unification_table
557557
.borrow_mut()
558-
.rollback_to(self.tcx, type_snapshot);
558+
.rollback_to(type_snapshot);
559559
self.int_unification_table
560560
.borrow_mut()
561-
.rollback_to(self.tcx, int_snapshot);
561+
.rollback_to(int_snapshot);
562562
self.float_unification_table
563563
.borrow_mut()
564-
.rollback_to(self.tcx, float_snapshot);
564+
.rollback_to(float_snapshot);
565565
self.region_vars
566566
.rollback_to(region_vars_snapshot);
567567
}

src/librustc/middle/typeck/infer/unify.rs

+26-134
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ use middle::typeck::infer::{Bounds, uok, ures};
1616
use middle::typeck::infer::InferCtxt;
1717
use std::cell::RefCell;
1818
use std::fmt::Show;
19-
use std::mem;
2019
use syntax::ast;
2120
use util::ppaux::Repr;
21+
use util::snapshot_vec as sv;
2222

2323
/**
2424
* This trait is implemented by any type that can serve as a type
@@ -82,43 +82,18 @@ pub struct UnificationTable<K,V> {
8282
/**
8383
* Indicates the current value of each key.
8484
*/
85-
values: Vec<VarValue<K,V>>,
8685

87-
/**
88-
* When a snapshot is active, logs each change made to the table
89-
* so that they can be unrolled.
90-
*/
91-
undo_log: Vec<UndoLog<K,V>>,
86+
values: sv::SnapshotVec<VarValue<K,V>,(),Delegate>,
9287
}
9388

9489
/**
9590
* At any time, users may snapshot a unification table. The changes
9691
* made during the snapshot may either be *committed* or *rolled back*.
9792
*/
9893
pub struct Snapshot<K> {
99-
// Ensure that this snapshot is keyed to the table type.
100-
marker1: marker::CovariantType<K>,
101-
102-
// Snapshots are tokens that should be created/consumed linearly.
103-
marker2: marker::NoCopy,
104-
105-
// Length of the undo log at the time the snapshot was taken.
106-
length: uint,
107-
}
108-
109-
#[deriving(PartialEq)]
110-
enum UndoLog<K,V> {
111-
/// Indicates where a snapshot started.
112-
OpenSnapshot,
113-
114-
/// Indicates a snapshot that has been committed.
115-
CommittedSnapshot,
116-
117-
/// New variable with given index was created.
118-
NewVar(uint),
119-
120-
/// Variable with given index was changed *from* the given value.
121-
SetVar(uint, VarValue<K,V>),
94+
// Link snapshot to the key type `K` of the table.
95+
marker: marker::CovariantType<K>,
96+
snapshot: sv::Snapshot,
12297
}
12398

12499
/**
@@ -131,6 +106,8 @@ pub struct Node<K,V> {
131106
pub rank: uint,
132107
}
133108

109+
pub struct Delegate;
110+
134111
// We can't use V:LatticeValue, much as I would like to,
135112
// because frequently the pattern is that V=Bounds<U> for some
136113
// other type parameter U, and we have no way to say
@@ -139,127 +116,46 @@ pub struct Node<K,V> {
139116
impl<V:PartialEq+Clone+Repr,K:UnifyKey<V>> UnificationTable<K,V> {
140117
pub fn new() -> UnificationTable<K,V> {
141118
UnificationTable {
142-
values: Vec::new(),
143-
undo_log: Vec::new()
119+
values: sv::SnapshotVec::new(Delegate),
144120
}
145121
}
146122

147-
pub fn in_snapshot(&self) -> bool {
148-
/*! True if a snapshot has been started. */
149-
150-
self.undo_log.len() > 0
151-
}
152-
153123
/**
154124
* Starts a new snapshot. Each snapshot must be either
155125
* rolled back or committed in a "LIFO" (stack) order.
156126
*/
157127
pub fn snapshot(&mut self) -> Snapshot<K> {
158-
let length = self.undo_log.len();
159-
debug!("{}: snapshot at length {}",
160-
UnifyKey::tag(None::<K>),
161-
length);
162-
self.undo_log.push(OpenSnapshot);
163-
Snapshot { length: length,
164-
marker1: marker::CovariantType,
165-
marker2: marker::NoCopy }
166-
}
167-
168-
fn assert_open_snapshot(&self, snapshot: &Snapshot<K>) {
169-
// Or else there was a failure to follow a stack discipline:
170-
assert!(self.undo_log.len() > snapshot.length);
171-
172-
// Invariant established by start_snapshot():
173-
assert!(*self.undo_log.get(snapshot.length) == OpenSnapshot);
128+
Snapshot { marker: marker::CovariantType::<K>,
129+
snapshot: self.values.start_snapshot() }
174130
}
175131

176132
/**
177133
* Reverses all changes since the last snapshot. Also
178134
* removes any keys that have been created since then.
179135
*/
180-
pub fn rollback_to(&mut self, tcx: &ty::ctxt, snapshot: Snapshot<K>) {
181-
debug!("{}: rollback_to({})",
182-
UnifyKey::tag(None::<K>),
183-
snapshot.length);
184-
185-
self.assert_open_snapshot(&snapshot);
186-
187-
while self.undo_log.len() > snapshot.length + 1 {
188-
match self.undo_log.pop().unwrap() {
189-
OpenSnapshot => {
190-
// This indicates a failure to obey the stack discipline.
191-
tcx.sess.bug("Cannot rollback an uncommitted snapshot");
192-
}
193-
194-
CommittedSnapshot => {
195-
// This occurs when there are nested snapshots and
196-
// the inner is committed but outer is rolled back.
197-
}
198-
199-
NewVar(i) => {
200-
assert!(self.values.len() == i);
201-
self.values.pop();
202-
}
203-
204-
SetVar(i, v) => {
205-
*self.values.get_mut(i) = v;
206-
}
207-
}
208-
}
209-
210-
let v = self.undo_log.pop().unwrap();
211-
assert!(v == OpenSnapshot);
212-
assert!(self.undo_log.len() == snapshot.length);
136+
pub fn rollback_to(&mut self, snapshot: Snapshot<K>) {
137+
debug!("{}: rollback_to()", UnifyKey::tag(None::<K>));
138+
self.values.rollback_to(snapshot.snapshot);
213139
}
214140

215141
/**
216142
* Commits all changes since the last snapshot. Of course, they
217143
* can still be undone if there is a snapshot further out.
218144
*/
219145
pub fn commit(&mut self, snapshot: Snapshot<K>) {
220-
debug!("{}: commit({})",
221-
UnifyKey::tag(None::<K>),
222-
snapshot.length);
223-
224-
self.assert_open_snapshot(&snapshot);
225-
226-
if snapshot.length == 0 {
227-
// The root snapshot.
228-
self.undo_log.truncate(0);
229-
} else {
230-
*self.undo_log.get_mut(snapshot.length) = CommittedSnapshot;
231-
}
146+
debug!("{}: commit()", UnifyKey::tag(None::<K>));
147+
self.values.commit(snapshot.snapshot);
232148
}
233149

234150
pub fn new_key(&mut self, value: V) -> K {
235-
let index = self.values.len();
236-
237-
if self.in_snapshot() {
238-
self.undo_log.push(NewVar(index));
239-
}
240-
241-
self.values.push(Root(value, 0));
151+
let index = self.values.push(Root(value, 0));
242152
let k = UnifyKey::from_index(index);
243153
debug!("{}: created new key: {}",
244154
UnifyKey::tag(None::<K>),
245155
k);
246156
k
247157
}
248158

249-
fn swap_value(&mut self,
250-
index: uint,
251-
new_value: VarValue<K,V>)
252-
-> VarValue<K,V>
253-
{
254-
/*!
255-
* Primitive operation to swap a value in the var array.
256-
* Caller should update the undo log if we are in a snapshot.
257-
*/
258-
259-
let loc = self.values.get_mut(index);
260-
mem::replace(loc, new_value)
261-
}
262-
263159
pub fn get(&mut self, tcx: &ty::ctxt, vid: K) -> Node<K,V> {
264160
/*!
265161
* Find the root node for `vid`. This uses the standard
@@ -274,15 +170,7 @@ impl<V:PartialEq+Clone+Repr,K:UnifyKey<V>> UnificationTable<K,V> {
274170
let node: Node<K,V> = self.get(tcx, redirect.clone());
275171
if node.key != redirect {
276172
// Path compression
277-
let old_value =
278-
self.swap_value(index, Redirect(node.key.clone()));
279-
280-
// If we are in a snapshot, record this compression,
281-
// because it's possible that the unification which
282-
// caused it will be rolled back later.
283-
if self.in_snapshot() {
284-
self.undo_log.push(SetVar(index, old_value));
285-
}
173+
self.values.set(index, Redirect(node.key.clone()));
286174
}
287175
node
288176
}
@@ -310,15 +198,12 @@ impl<V:PartialEq+Clone+Repr,K:UnifyKey<V>> UnificationTable<K,V> {
310198
*/
311199

312200
assert!(self.is_root(&key));
313-
assert!(self.in_snapshot());
314201

315202
debug!("Updating variable {} to {}",
316203
key.repr(tcx),
317204
new_value.repr(tcx));
318205

319-
let index = key.index();
320-
let old_value = self.swap_value(index, new_value);
321-
self.undo_log.push(SetVar(index, old_value));
206+
self.values.set(key.index(), new_value);
322207
}
323208

324209
pub fn unify(&mut self,
@@ -359,6 +244,12 @@ impl<V:PartialEq+Clone+Repr,K:UnifyKey<V>> UnificationTable<K,V> {
359244
}
360245
}
361246

247+
impl<K,V> sv::SnapshotVecDelegate<VarValue<K,V>,()> for Delegate {
248+
fn reverse(&mut self, _: &mut Vec<VarValue<K,V>>, _: ()) {
249+
fail!("Nothing to reverse");
250+
}
251+
}
252+
362253
///////////////////////////////////////////////////////////////////////////
363254
// Code to handle simple keys like ints, floats---anything that
364255
// doesn't have a subtyping relationship we need to worry about.
@@ -373,7 +264,8 @@ pub trait SimplyUnifiable : Clone + PartialEq + Repr {
373264

374265
pub fn err<V:SimplyUnifiable>(a_is_expected: bool,
375266
a_t: V,
376-
b_t: V) -> ures {
267+
b_t: V)
268+
-> ures {
377269
if a_is_expected {
378270
Err(SimplyUnifiable::to_type_err(
379271
ty::expected_found {expected: a_t, found: b_t}))

0 commit comments

Comments
 (0)