@@ -16,9 +16,9 @@ use middle::typeck::infer::{Bounds, uok, ures};
16
16
use middle:: typeck:: infer:: InferCtxt ;
17
17
use std:: cell:: RefCell ;
18
18
use std:: fmt:: Show ;
19
- use std:: mem;
20
19
use syntax:: ast;
21
20
use util:: ppaux:: Repr ;
21
+ use util:: snapshot_vec as sv;
22
22
23
23
/**
24
24
* This trait is implemented by any type that can serve as a type
@@ -82,43 +82,18 @@ pub struct UnificationTable<K,V> {
82
82
/**
83
83
* Indicates the current value of each key.
84
84
*/
85
- values : Vec < VarValue < K , V > > ,
86
85
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 > ,
92
87
}
93
88
94
89
/**
95
90
* At any time, users may snapshot a unification table. The changes
96
91
* made during the snapshot may either be *committed* or *rolled back*.
97
92
*/
98
93
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 ,
122
97
}
123
98
124
99
/**
@@ -131,6 +106,8 @@ pub struct Node<K,V> {
131
106
pub rank : uint ,
132
107
}
133
108
109
+ pub struct Delegate ;
110
+
134
111
// We can't use V:LatticeValue, much as I would like to,
135
112
// because frequently the pattern is that V=Bounds<U> for some
136
113
// other type parameter U, and we have no way to say
@@ -139,127 +116,46 @@ pub struct Node<K,V> {
139
116
impl < V : PartialEq +Clone +Repr , K : UnifyKey < V > > UnificationTable < K , V > {
140
117
pub fn new ( ) -> UnificationTable < K , V > {
141
118
UnificationTable {
142
- values : Vec :: new ( ) ,
143
- undo_log : Vec :: new ( )
119
+ values : sv:: SnapshotVec :: new ( Delegate ) ,
144
120
}
145
121
}
146
122
147
- pub fn in_snapshot ( & self ) -> bool {
148
- /*! True if a snapshot has been started. */
149
-
150
- self . undo_log . len ( ) > 0
151
- }
152
-
153
123
/**
154
124
* Starts a new snapshot. Each snapshot must be either
155
125
* rolled back or committed in a "LIFO" (stack) order.
156
126
*/
157
127
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 ( ) }
174
130
}
175
131
176
132
/**
177
133
* Reverses all changes since the last snapshot. Also
178
134
* removes any keys that have been created since then.
179
135
*/
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 ) ;
213
139
}
214
140
215
141
/**
216
142
* Commits all changes since the last snapshot. Of course, they
217
143
* can still be undone if there is a snapshot further out.
218
144
*/
219
145
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 ) ;
232
148
}
233
149
234
150
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 ) ) ;
242
152
let k = UnifyKey :: from_index ( index) ;
243
153
debug ! ( "{}: created new key: {}" ,
244
154
UnifyKey :: tag( None :: <K >) ,
245
155
k) ;
246
156
k
247
157
}
248
158
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
-
263
159
pub fn get ( & mut self , tcx : & ty:: ctxt , vid : K ) -> Node < K , V > {
264
160
/*!
265
161
* 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> {
274
170
let node: Node < K , V > = self . get ( tcx, redirect. clone ( ) ) ;
275
171
if node. key != redirect {
276
172
// 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 ( ) ) ) ;
286
174
}
287
175
node
288
176
}
@@ -310,15 +198,12 @@ impl<V:PartialEq+Clone+Repr,K:UnifyKey<V>> UnificationTable<K,V> {
310
198
*/
311
199
312
200
assert ! ( self . is_root( & key) ) ;
313
- assert ! ( self . in_snapshot( ) ) ;
314
201
315
202
debug ! ( "Updating variable {} to {}" ,
316
203
key. repr( tcx) ,
317
204
new_value. repr( tcx) ) ;
318
205
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) ;
322
207
}
323
208
324
209
pub fn unify ( & mut self ,
@@ -359,6 +244,12 @@ impl<V:PartialEq+Clone+Repr,K:UnifyKey<V>> UnificationTable<K,V> {
359
244
}
360
245
}
361
246
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
+
362
253
///////////////////////////////////////////////////////////////////////////
363
254
// Code to handle simple keys like ints, floats---anything that
364
255
// doesn't have a subtyping relationship we need to worry about.
@@ -373,7 +264,8 @@ pub trait SimplyUnifiable : Clone + PartialEq + Repr {
373
264
374
265
pub fn err < V : SimplyUnifiable > ( a_is_expected : bool ,
375
266
a_t : V ,
376
- b_t : V ) -> ures {
267
+ b_t : V )
268
+ -> ures {
377
269
if a_is_expected {
378
270
Err ( SimplyUnifiable :: to_type_err (
379
271
ty:: expected_found { expected : a_t, found : b_t} ) )
0 commit comments