@@ -16,15 +16,11 @@ use std::cmp;
16
16
use std:: marker:: PhantomData ;
17
17
use std:: u32;
18
18
use rustc_data_structures:: fx:: FxHashMap ;
19
+ use rustc_data_structures:: snapshot_vec as sv;
19
20
use rustc_data_structures:: unify as ut;
20
21
21
22
pub struct TypeVariableTable < ' tcx > {
22
- /// Extra data for each type variable, such as the origin. This is
23
- /// not stored in the unification table since, when we inquire
24
- /// after the origin of a variable X, we want the origin of **that
25
- /// variable X**, not the origin of some other variable Y with
26
- /// which X has been unified.
27
- var_data : Vec < TypeVariableData > ,
23
+ values : sv:: SnapshotVec < Delegate > ,
28
24
29
25
/// Two variables are unified in `eq_relations` when we have a
30
26
/// constraint `?X == ?Y`. This table also stores, for each key,
@@ -118,20 +114,21 @@ impl<'tcx> TypeVariableValue<'tcx> {
118
114
}
119
115
120
116
pub struct Snapshot < ' tcx > {
121
- /// number of variables at the time of the snapshot
122
- num_vars : usize ,
123
-
124
- /// snapshot from the `eq_relations` table
117
+ snapshot : sv:: Snapshot ,
125
118
eq_snapshot : ut:: Snapshot < ut:: InPlace < TyVidEqKey < ' tcx > > > ,
126
-
127
- /// snapshot from the `sub_relations` table
128
119
sub_snapshot : ut:: Snapshot < ut:: InPlace < ty:: TyVid > > ,
129
120
}
130
121
122
+ struct Instantiate {
123
+ vid : ty:: TyVid ,
124
+ }
125
+
126
+ struct Delegate ;
127
+
131
128
impl < ' tcx > TypeVariableTable < ' tcx > {
132
129
pub fn new ( ) -> TypeVariableTable < ' tcx > {
133
130
TypeVariableTable {
134
- var_data : Vec :: new ( ) ,
131
+ values : sv :: SnapshotVec :: new ( ) ,
135
132
eq_relations : ut:: UnificationTable :: new ( ) ,
136
133
sub_relations : ut:: UnificationTable :: new ( ) ,
137
134
}
@@ -142,15 +139,15 @@ impl<'tcx> TypeVariableTable<'tcx> {
142
139
/// Note that this function does not return care whether
143
140
/// `vid` has been unified with something else or not.
144
141
pub fn var_diverges < ' a > ( & ' a self , vid : ty:: TyVid ) -> bool {
145
- self . var_data [ vid. index as usize ] . diverging
142
+ self . values . get ( vid. index as usize ) . diverging
146
143
}
147
144
148
145
/// Returns the origin that was given when `vid` was created.
149
146
///
150
147
/// Note that this function does not return care whether
151
148
/// `vid` has been unified with something else or not.
152
149
pub fn var_origin ( & self , vid : ty:: TyVid ) -> & TypeVariableOrigin {
153
- & self . var_data [ vid. index as usize ] . origin
150
+ & self . values . get ( vid. index as usize ) . origin
154
151
}
155
152
156
153
/// Records that `a == b`, depending on `dir`.
@@ -182,6 +179,11 @@ impl<'tcx> TypeVariableTable<'tcx> {
182
179
"instantiating type variable `{:?}` twice: new-value = {:?}, old-value={:?}" ,
183
180
vid, ty, self . eq_relations. probe_value( vid) ) ;
184
181
self . eq_relations . union_value ( vid, TypeVariableValue :: Known { value : ty } ) ;
182
+
183
+ // Hack: we only need this so that `types_escaping_snapshot`
184
+ // can see what has been unified; see the Delegate impl for
185
+ // more details.
186
+ self . values . record ( Instantiate { vid : vid } ) ;
185
187
}
186
188
187
189
/// Creates a new type variable.
@@ -204,8 +206,11 @@ impl<'tcx> TypeVariableTable<'tcx> {
204
206
let sub_key = self . sub_relations . new_key ( ( ) ) ;
205
207
assert_eq ! ( eq_key. vid, sub_key) ;
206
208
207
- assert_eq ! ( self . var_data. len( ) , sub_key. index as usize ) ;
208
- self . var_data . push ( TypeVariableData { origin, diverging } ) ;
209
+ let index = self . values . push ( TypeVariableData {
210
+ origin,
211
+ diverging,
212
+ } ) ;
213
+ assert_eq ! ( eq_key. vid. index, index as u32 ) ;
209
214
210
215
debug ! ( "new_var(index={:?}, diverging={:?}, origin={:?}" , eq_key. vid, diverging, origin) ;
211
216
@@ -214,7 +219,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
214
219
215
220
/// Returns the number of type variables created thus far.
216
221
pub fn num_vars ( & self ) -> usize {
217
- self . var_data . len ( )
222
+ self . values . len ( )
218
223
}
219
224
220
225
/// Returns the "root" variable of `vid` in the `eq_relations`
@@ -270,7 +275,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
270
275
/// be processed in a stack-like fashion.
271
276
pub fn snapshot ( & mut self ) -> Snapshot < ' tcx > {
272
277
Snapshot {
273
- num_vars : self . var_data . len ( ) ,
278
+ snapshot : self . values . start_snapshot ( ) ,
274
279
eq_snapshot : self . eq_relations . snapshot ( ) ,
275
280
sub_snapshot : self . sub_relations . snapshot ( ) ,
276
281
}
@@ -280,21 +285,30 @@ impl<'tcx> TypeVariableTable<'tcx> {
280
285
/// snapshots created since that point must already have been
281
286
/// committed or rolled back.
282
287
pub fn rollback_to ( & mut self , s : Snapshot < ' tcx > ) {
283
- let Snapshot { num_vars, eq_snapshot, sub_snapshot } = s;
284
- debug ! ( "type_variables::rollback_to(num_vars = {})" , num_vars) ;
285
- assert ! ( self . var_data. len( ) >= num_vars) ;
288
+ debug ! ( "rollback_to{:?}" , {
289
+ for action in self . values. actions_since_snapshot( & s. snapshot) {
290
+ match * action {
291
+ sv:: UndoLog :: NewElem ( index) => {
292
+ debug!( "inference variable _#{}t popped" , index)
293
+ }
294
+ _ => { }
295
+ }
296
+ }
297
+ } ) ;
298
+
299
+ let Snapshot { snapshot, eq_snapshot, sub_snapshot } = s;
300
+ self . values . rollback_to ( snapshot) ;
286
301
self . eq_relations . rollback_to ( eq_snapshot) ;
287
302
self . sub_relations . rollback_to ( sub_snapshot) ;
288
- self . var_data . truncate ( num_vars) ;
289
303
}
290
304
291
305
/// Commits all changes since the snapshot was created, making
292
306
/// them permanent (unless this snapshot was created within
293
307
/// another snapshot). Any snapshots created since that point
294
308
/// must already have been committed or rolled back.
295
309
pub fn commit ( & mut self , s : Snapshot < ' tcx > ) {
296
- let Snapshot { num_vars , eq_snapshot, sub_snapshot } = s;
297
- debug ! ( "type_variables:: commit(num_vars = {})" , num_vars ) ;
310
+ let Snapshot { snapshot , eq_snapshot, sub_snapshot } = s;
311
+ self . values . commit ( snapshot ) ;
298
312
self . eq_relations . commit ( eq_snapshot) ;
299
313
self . sub_relations . commit ( sub_snapshot) ;
300
314
}
@@ -303,12 +317,19 @@ impl<'tcx> TypeVariableTable<'tcx> {
303
317
/// ty-variables created during the snapshot, and the values
304
318
/// `{V2}` are the root variables that they were unified with,
305
319
/// along with their origin.
306
- pub fn types_created_since_snapshot ( & mut self , snapshot : & Snapshot < ' tcx > ) -> TypeVariableMap {
307
- self . var_data
320
+ pub fn types_created_since_snapshot ( & mut self , s : & Snapshot < ' tcx > ) -> TypeVariableMap {
321
+ let actions_since_snapshot = self . values . actions_since_snapshot ( & s. snapshot ) ;
322
+
323
+ actions_since_snapshot
308
324
. iter ( )
309
- . enumerate ( )
310
- . skip ( snapshot. num_vars ) // skip those that existed when snapshot was taken
311
- . map ( |( index, data) | ( ty:: TyVid { index : index as u32 } , data. origin ) )
325
+ . filter_map ( |action| match action {
326
+ & sv:: UndoLog :: NewElem ( index) => Some ( ty:: TyVid { index : index as u32 } ) ,
327
+ _ => None ,
328
+ } )
329
+ . map ( |vid| {
330
+ let origin = self . values . get ( vid. index as usize ) . origin . clone ( ) ;
331
+ ( vid, origin)
332
+ } )
312
333
. collect ( )
313
334
}
314
335
@@ -318,42 +339,47 @@ impl<'tcx> TypeVariableTable<'tcx> {
318
339
/// a type variable `V0`, then we started the snapshot, then we
319
340
/// created a type variable `V1`, unifed `V0` with `T0`, and
320
341
/// unified `V1` with `T1`, this function would return `{T0}`.
321
- pub fn types_escaping_snapshot ( & mut self , snapshot : & Snapshot < ' tcx > ) -> Vec < Ty < ' tcx > > {
322
- // We want to select only those instantiations that have
323
- // occurred since the snapshot *and* which affect some
324
- // variable that existed prior to the snapshot. This code just
325
- // affects all instantiatons that ever occurred which affect
326
- // variables prior to the snapshot.
327
- //
328
- // It's hard to do better than this, though, without changing
329
- // the unification table to prefer "lower" vids -- the problem
330
- // is that we may have a variable X (from before the snapshot)
331
- // and Y (from after the snapshot) which get unified, with Y
332
- // chosen as the new root. Now we are "instantiating" Y with a
333
- // value, but it escapes into X, but we wouldn't readily see
334
- // that. (In fact, earlier revisions of this code had this
335
- // bug; it was introduced when we added the `eq_relations`
336
- // table, but it's hard to create rust code that triggers it.)
337
- //
338
- // We could tell the table to prefer lower vids, and then we would
339
- // see the case above, but we would get less-well-balanced trees.
340
- //
341
- // Since I hope to kill the leak-check in this branch, and
342
- // that's the code which uses this logic anyway, I'm going to
343
- // use the less efficient algorithm for now.
344
- let mut escaping_types = Vec :: with_capacity ( snapshot. num_vars ) ;
345
- escaping_types. extend (
346
- ( 0 ..snapshot. num_vars ) // for all variables that pre-exist the snapshot, collect..
347
- . map ( |i| ty:: TyVid { index : i as u32 } )
348
- . filter_map ( |vid| self . probe ( vid) . known ( ) ) ) ; // ..types they are instantiated with.
349
- debug ! ( "types_escaping_snapshot = {:?}" , escaping_types) ;
342
+ pub fn types_escaping_snapshot ( & mut self , s : & Snapshot < ' tcx > ) -> Vec < Ty < ' tcx > > {
343
+ let mut new_elem_threshold = u32:: MAX ;
344
+ let mut escaping_types = Vec :: new ( ) ;
345
+ let actions_since_snapshot = self . values . actions_since_snapshot ( & s. snapshot ) ;
346
+ debug ! ( "actions_since_snapshot.len() = {}" , actions_since_snapshot. len( ) ) ;
347
+ for action in actions_since_snapshot {
348
+ match * action {
349
+ sv:: UndoLog :: NewElem ( index) => {
350
+ // if any new variables were created during the
351
+ // snapshot, remember the lower index (which will
352
+ // always be the first one we see). Note that this
353
+ // action must precede those variables being
354
+ // specified.
355
+ new_elem_threshold = cmp:: min ( new_elem_threshold, index as u32 ) ;
356
+ debug ! ( "NewElem({}) new_elem_threshold={}" , index, new_elem_threshold) ;
357
+ }
358
+
359
+ sv:: UndoLog :: Other ( Instantiate { vid, .. } ) => {
360
+ if vid. index < new_elem_threshold {
361
+ // quick check to see if this variable was
362
+ // created since the snapshot started or not.
363
+ let escaping_type = match self . eq_relations . probe_value ( vid) {
364
+ TypeVariableValue :: Unknown { .. } => bug ! ( ) ,
365
+ TypeVariableValue :: Known { value } => value,
366
+ } ;
367
+ escaping_types. push ( escaping_type) ;
368
+ }
369
+ debug ! ( "SpecifyVar({:?}) new_elem_threshold={}" , vid, new_elem_threshold) ;
370
+ }
371
+
372
+ _ => { }
373
+ }
374
+ }
375
+
350
376
escaping_types
351
377
}
352
378
353
379
/// Returns indices of all variables that are not yet
354
380
/// instantiated.
355
381
pub fn unsolved_variables ( & mut self ) -> Vec < ty:: TyVid > {
356
- ( 0 ..self . var_data . len ( ) )
382
+ ( 0 ..self . values . len ( ) )
357
383
. filter_map ( |i| {
358
384
let vid = ty:: TyVid { index : i as u32 } ;
359
385
match self . probe ( vid) {
@@ -364,6 +390,27 @@ impl<'tcx> TypeVariableTable<'tcx> {
364
390
. collect ( )
365
391
}
366
392
}
393
+
394
+ impl sv:: SnapshotVecDelegate for Delegate {
395
+ type Value = TypeVariableData ;
396
+ type Undo = Instantiate ;
397
+
398
+ fn reverse ( _values : & mut Vec < TypeVariableData > , _action : Instantiate ) {
399
+ // We don't actually have to *do* anything to reverse an
400
+ // instanation; the value for a variable is stored in the
401
+ // `eq_relations` and hence its rollback code will handle
402
+ // it. In fact, we could *almost* just remove the
403
+ // `SnapshotVec` entirely, except that we would have to
404
+ // reproduce *some* of its logic, since we want to know which
405
+ // type variables have been instantiated since the snapshot
406
+ // was started, so we can implement `types_escaping_snapshot`.
407
+ //
408
+ // (If we extended the `UnificationTable` to let us see which
409
+ // values have been unified and so forth, that might also
410
+ // suffice.)
411
+ }
412
+ }
413
+
367
414
///////////////////////////////////////////////////////////////////////////
368
415
369
416
/// These structs (a newtyped TyVid) are used as the unification key
0 commit comments