@@ -12,15 +12,18 @@ use syntax::ast;
12
12
use syntax_pos:: Span ;
13
13
use ty:: { self , Ty } ;
14
14
15
- use std:: cmp:: min;
16
15
use std:: marker:: PhantomData ;
17
16
use std:: u32;
18
17
use rustc_data_structures:: fx:: FxHashMap ;
19
- use rustc_data_structures:: snapshot_vec as sv;
20
18
use rustc_data_structures:: unify as ut;
21
19
22
20
pub struct TypeVariableTable < ' tcx > {
23
- values : sv:: SnapshotVec < Delegate > ,
21
+ /// Extra data for each type variable, such as the origin. This is
22
+ /// not stored in the unification table since, when we inquire
23
+ /// after the origin of a variable X, we want the origin of **that
24
+ /// variable X**, not the origin of some other variable Y with
25
+ /// which X has been unified.
26
+ var_data : Vec < TypeVariableData > ,
24
27
25
28
/// Two variables are unified in `eq_relations` when we have a
26
29
/// constraint `?X == ?Y`. This table also stores, for each key,
@@ -79,21 +82,20 @@ enum TypeVariableValue<'tcx> {
79
82
}
80
83
81
84
pub struct Snapshot < ' tcx > {
82
- snapshot : sv:: Snapshot ,
85
+ /// number of variables at the time of the snapshot
86
+ num_vars : usize ,
87
+
88
+ /// snapshot from the `eq_relations` table
83
89
eq_snapshot : ut:: Snapshot < ut:: InPlace < TyVidEqKey < ' tcx > > > ,
84
- sub_snapshot : ut:: Snapshot < ut:: InPlace < ty:: TyVid > > ,
85
- }
86
90
87
- struct Instantiate {
88
- vid : ty:: TyVid ,
91
+ /// snapshot from the `sub_relations` table
92
+ sub_snapshot : ut :: Snapshot < ut :: InPlace < ty:: TyVid > > ,
89
93
}
90
94
91
- struct Delegate ;
92
-
93
95
impl < ' tcx > TypeVariableTable < ' tcx > {
94
96
pub fn new ( ) -> TypeVariableTable < ' tcx > {
95
97
TypeVariableTable {
96
- values : sv :: SnapshotVec :: new ( ) ,
98
+ var_data : Vec :: new ( ) ,
97
99
eq_relations : ut:: UnificationTable :: new ( ) ,
98
100
sub_relations : ut:: UnificationTable :: new ( ) ,
99
101
}
@@ -104,15 +106,15 @@ impl<'tcx> TypeVariableTable<'tcx> {
104
106
/// Note that this function does not return care whether
105
107
/// `vid` has been unified with something else or not.
106
108
pub fn var_diverges < ' a > ( & ' a self , vid : ty:: TyVid ) -> bool {
107
- self . values . get ( vid. index as usize ) . diverging
109
+ self . var_data [ vid. index as usize ] . diverging
108
110
}
109
111
110
112
/// Returns the origin that was given when `vid` was created.
111
113
///
112
114
/// Note that this function does not return care whether
113
115
/// `vid` has been unified with something else or not.
114
116
pub fn var_origin ( & self , vid : ty:: TyVid ) -> & TypeVariableOrigin {
115
- & self . values . get ( vid. index as usize ) . origin
117
+ & self . var_data [ vid. index as usize ] . origin
116
118
}
117
119
118
120
/// Records that `a == b`, depending on `dir`.
@@ -144,11 +146,6 @@ impl<'tcx> TypeVariableTable<'tcx> {
144
146
"instantiating type variable `{:?}` twice: new-value = {:?}, old-value={:?}" ,
145
147
vid, ty, self . eq_relations. probe_value( vid) ) ;
146
148
self . eq_relations . union_value ( vid, TypeVariableValue :: Known { value : ty } ) ;
147
-
148
- // Hack: we only need this so that `types_escaping_snapshot`
149
- // can see what has been unified; see the Delegate impl for
150
- // more details.
151
- self . values . record ( Instantiate { vid : vid } ) ;
152
149
}
153
150
154
151
/// Creates a new type variable.
@@ -170,11 +167,8 @@ impl<'tcx> TypeVariableTable<'tcx> {
170
167
let sub_key = self . sub_relations . new_key ( ( ) ) ;
171
168
assert_eq ! ( eq_key. vid, sub_key) ;
172
169
173
- let index = self . values . push ( TypeVariableData {
174
- origin,
175
- diverging,
176
- } ) ;
177
- assert_eq ! ( eq_key. vid. index, index as u32 ) ;
170
+ assert_eq ! ( self . var_data. len( ) , sub_key. index as usize ) ;
171
+ self . var_data . push ( TypeVariableData { origin, diverging } ) ;
178
172
179
173
debug ! ( "new_var(index={:?}, diverging={:?}, origin={:?}" , eq_key. vid, diverging, origin) ;
180
174
@@ -183,7 +177,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
183
177
184
178
/// Returns the number of type variables created thus far.
185
179
pub fn num_vars ( & self ) -> usize {
186
- self . values . len ( )
180
+ self . var_data . len ( )
187
181
}
188
182
189
183
/// Returns the "root" variable of `vid` in the `eq_relations`
@@ -243,7 +237,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
243
237
/// be processed in a stack-like fashion.
244
238
pub fn snapshot ( & mut self ) -> Snapshot < ' tcx > {
245
239
Snapshot {
246
- snapshot : self . values . start_snapshot ( ) ,
240
+ num_vars : self . var_data . len ( ) ,
247
241
eq_snapshot : self . eq_relations . snapshot ( ) ,
248
242
sub_snapshot : self . sub_relations . snapshot ( ) ,
249
243
}
@@ -253,30 +247,21 @@ impl<'tcx> TypeVariableTable<'tcx> {
253
247
/// snapshots created since that point must already have been
254
248
/// committed or rolled back.
255
249
pub fn rollback_to ( & mut self , s : Snapshot < ' tcx > ) {
256
- debug ! ( "rollback_to{:?}" , {
257
- for action in self . values. actions_since_snapshot( & s. snapshot) {
258
- match * action {
259
- sv:: UndoLog :: NewElem ( index) => {
260
- debug!( "inference variable _#{}t popped" , index)
261
- }
262
- _ => { }
263
- }
264
- }
265
- } ) ;
266
-
267
- let Snapshot { snapshot, eq_snapshot, sub_snapshot } = s;
268
- self . values . rollback_to ( snapshot) ;
250
+ let Snapshot { num_vars, eq_snapshot, sub_snapshot } = s;
251
+ debug ! ( "type_variables::rollback_to(num_vars = {})" , num_vars) ;
252
+ assert ! ( self . var_data. len( ) >= num_vars) ;
269
253
self . eq_relations . rollback_to ( eq_snapshot) ;
270
254
self . sub_relations . rollback_to ( sub_snapshot) ;
255
+ self . var_data . truncate ( num_vars) ;
271
256
}
272
257
273
258
/// Commits all changes since the snapshot was created, making
274
259
/// them permanent (unless this snapshot was created within
275
260
/// another snapshot). Any snapshots created since that point
276
261
/// must already have been committed or rolled back.
277
262
pub fn commit ( & mut self , s : Snapshot < ' tcx > ) {
278
- let Snapshot { snapshot , eq_snapshot, sub_snapshot } = s;
279
- self . values . commit ( snapshot ) ;
263
+ let Snapshot { num_vars , eq_snapshot, sub_snapshot } = s;
264
+ debug ! ( "type_variables:: commit(num_vars = {})" , num_vars ) ;
280
265
self . eq_relations . commit ( eq_snapshot) ;
281
266
self . sub_relations . commit ( sub_snapshot) ;
282
267
}
@@ -285,19 +270,12 @@ impl<'tcx> TypeVariableTable<'tcx> {
285
270
/// ty-variables created during the snapshot, and the values
286
271
/// `{V2}` are the root variables that they were unified with,
287
272
/// along with their origin.
288
- pub fn types_created_since_snapshot ( & mut self , s : & Snapshot < ' tcx > ) -> TypeVariableMap {
289
- let actions_since_snapshot = self . values . actions_since_snapshot ( & s. snapshot ) ;
290
-
291
- actions_since_snapshot
273
+ pub fn types_created_since_snapshot ( & mut self , snapshot : & Snapshot < ' tcx > ) -> TypeVariableMap {
274
+ self . var_data
292
275
. iter ( )
293
- . filter_map ( |action| match action {
294
- & sv:: UndoLog :: NewElem ( index) => Some ( ty:: TyVid { index : index as u32 } ) ,
295
- _ => None ,
296
- } )
297
- . map ( |vid| {
298
- let origin = self . values . get ( vid. index as usize ) . origin . clone ( ) ;
299
- ( vid, origin)
300
- } )
276
+ . enumerate ( )
277
+ . skip ( snapshot. num_vars ) // skip those that existed when snapshot was taken
278
+ . map ( |( index, data) | ( ty:: TyVid { index : index as u32 } , data. origin ) )
301
279
. collect ( )
302
280
}
303
281
@@ -307,47 +285,45 @@ impl<'tcx> TypeVariableTable<'tcx> {
307
285
/// a type variable `V0`, then we started the snapshot, then we
308
286
/// created a type variable `V1`, unifed `V0` with `T0`, and
309
287
/// unified `V1` with `T1`, this function would return `{T0}`.
310
- pub fn types_escaping_snapshot ( & mut self , s : & Snapshot < ' tcx > ) -> Vec < Ty < ' tcx > > {
311
- let mut new_elem_threshold = u32:: MAX ;
312
- let mut escaping_types = Vec :: new ( ) ;
313
- let actions_since_snapshot = self . values . actions_since_snapshot ( & s. snapshot ) ;
314
- debug ! ( "actions_since_snapshot.len() = {}" , actions_since_snapshot. len( ) ) ;
315
- for action in actions_since_snapshot {
316
- match * action {
317
- sv:: UndoLog :: NewElem ( index) => {
318
- // if any new variables were created during the
319
- // snapshot, remember the lower index (which will
320
- // always be the first one we see). Note that this
321
- // action must precede those variables being
322
- // specified.
323
- new_elem_threshold = min ( new_elem_threshold, index as u32 ) ;
324
- debug ! ( "NewElem({}) new_elem_threshold={}" , index, new_elem_threshold) ;
325
- }
326
-
327
- sv:: UndoLog :: Other ( Instantiate { vid, .. } ) => {
328
- if vid. index < new_elem_threshold {
329
- // quick check to see if this variable was
330
- // created since the snapshot started or not.
331
- let escaping_type = match self . eq_relations . probe_value ( vid) {
332
- TypeVariableValue :: Unknown => bug ! ( ) ,
333
- TypeVariableValue :: Known { value } => value,
334
- } ;
335
- escaping_types. push ( escaping_type) ;
336
- }
337
- debug ! ( "SpecifyVar({:?}) new_elem_threshold={}" , vid, new_elem_threshold) ;
338
- }
339
-
340
- _ => { }
341
- }
342
- }
343
-
288
+ pub fn types_escaping_snapshot ( & mut self , snapshot : & Snapshot < ' tcx > ) -> Vec < Ty < ' tcx > > {
289
+ // We want to select only those instantiations that have
290
+ // occurred since the snapshot *and* which affect some
291
+ // variable that existed prior to the snapshot. This code just
292
+ // affects all instantiatons that ever occurred which affect
293
+ // variables prior to the snapshot.
294
+ //
295
+ // It's hard to do better than this, though, without changing
296
+ // the unification table to prefer "lower" vids -- the problem
297
+ // is that we may have a variable X (from before the snapshot)
298
+ // and Y (from after the snapshot) which get unified, with Y
299
+ // chosen as the new root. Now we are "instantiating" Y with a
300
+ // value, but it escapes into X, but we wouldn't readily see
301
+ // that. (In fact, earlier revisions of this code had this
302
+ // bug; it was introduced when we added the `eq_relations`
303
+ // table, but it's hard to create rust code that triggers it.)
304
+ //
305
+ // We could tell the table to prefer lower vids, and then we would
306
+ // see the case above, but we would get less-well-balanced trees.
307
+ //
308
+ // Since I hope to kill the leak-check in this branch, and
309
+ // that's the code which uses this logic anyway, I'm going to
310
+ // use the less efficient algorithm for now.
311
+ let mut escaping_types = Vec :: with_capacity ( snapshot. num_vars ) ;
312
+ escaping_types. extend (
313
+ ( 0 ..snapshot. num_vars ) // for all variables that pre-exist the snapshot...
314
+ . map ( |i| ty:: TyVid { index : i as u32 } )
315
+ . filter_map ( |vid| match self . eq_relations . probe_value ( vid) {
316
+ TypeVariableValue :: Unknown => None ,
317
+ TypeVariableValue :: Known { value } => Some ( value) ,
318
+ } ) ) ; // ...collect what types they've been instantiated with.
319
+ debug ! ( "types_escaping_snapshot = {:?}" , escaping_types) ;
344
320
escaping_types
345
321
}
346
322
347
323
/// Returns indices of all variables that are not yet
348
324
/// instantiated.
349
325
pub fn unsolved_variables ( & mut self ) -> Vec < ty:: TyVid > {
350
- ( 0 ..self . values . len ( ) )
326
+ ( 0 ..self . var_data . len ( ) )
351
327
. filter_map ( |i| {
352
328
let vid = ty:: TyVid { index : i as u32 } ;
353
329
if self . probe ( vid) . is_some ( ) {
@@ -359,27 +335,6 @@ impl<'tcx> TypeVariableTable<'tcx> {
359
335
. collect ( )
360
336
}
361
337
}
362
-
363
- impl sv:: SnapshotVecDelegate for Delegate {
364
- type Value = TypeVariableData ;
365
- type Undo = Instantiate ;
366
-
367
- fn reverse ( _values : & mut Vec < TypeVariableData > , _action : Instantiate ) {
368
- // We don't actually have to *do* anything to reverse an
369
- // instanation; the value for a variable is stored in the
370
- // `eq_relations` and hence its rollback code will handle
371
- // it. In fact, we could *almost* just remove the
372
- // `SnapshotVec` entirely, except that we would have to
373
- // reproduce *some* of its logic, since we want to know which
374
- // type variables have been instantiated since the snapshot
375
- // was started, so we can implement `types_escaping_snapshot`.
376
- //
377
- // (If we extended the `UnificationTable` to let us see which
378
- // values have been unified and so forth, that might also
379
- // suffice.)
380
- }
381
- }
382
-
383
338
///////////////////////////////////////////////////////////////////////////
384
339
385
340
/// These structs (a newtyped TyVid) are used as the unification key
0 commit comments