8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
- use self :: TypeVariableValue :: * ;
12
11
use syntax:: ast;
13
12
use syntax_pos:: Span ;
14
13
use ty:: { self , Ty } ;
15
14
16
15
use std:: cmp:: min;
17
16
use std:: marker:: PhantomData ;
18
- use std:: mem;
19
17
use std:: u32;
20
18
use rustc_data_structures:: fx:: FxHashMap ;
21
19
use rustc_data_structures:: snapshot_vec as sv;
22
20
use rustc_data_structures:: unify as ut;
23
21
24
22
pub struct TypeVariableTable < ' tcx > {
25
- values : sv:: SnapshotVec < Delegate < ' tcx > > ,
23
+ values : sv:: SnapshotVec < Delegate > ,
26
24
27
25
/// Two variables are unified in `eq_relations` when we have a
28
- /// constraint `?X == ?Y`.
29
- eq_relations : ut:: UnificationTable < ut:: InPlace < ty:: TyVid > > ,
26
+ /// constraint `?X == ?Y`. This table also stores, for each key,
27
+ /// the known value.
28
+ eq_relations : ut:: UnificationTable < ut:: InPlace < TyVidEqKey < ' tcx > > > ,
30
29
31
30
/// Two variables are unified in `eq_relations` when we have a
32
31
/// constraint `?X <: ?Y` *or* a constraint `?Y <: ?X`. This second
@@ -71,30 +70,28 @@ pub enum TypeVariableOrigin {
71
70
72
71
pub type TypeVariableMap = FxHashMap < ty:: TyVid , TypeVariableOrigin > ;
73
72
74
- struct TypeVariableData < ' tcx > {
75
- value : TypeVariableValue < ' tcx > ,
73
+ struct TypeVariableData {
76
74
origin : TypeVariableOrigin ,
77
75
diverging : bool
78
76
}
79
77
78
+ #[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
80
79
enum TypeVariableValue < ' tcx > {
81
- Known {
82
- value : Ty < ' tcx >
83
- } ,
80
+ Known { value : Ty < ' tcx > } ,
84
81
Unknown ,
85
82
}
86
83
87
- pub struct Snapshot {
84
+ pub struct Snapshot < ' tcx > {
88
85
snapshot : sv:: Snapshot ,
89
- eq_snapshot : ut:: Snapshot < ut:: InPlace < ty :: TyVid > > ,
86
+ eq_snapshot : ut:: Snapshot < ut:: InPlace < TyVidEqKey < ' tcx > > > ,
90
87
sub_snapshot : ut:: Snapshot < ut:: InPlace < ty:: TyVid > > ,
91
88
}
92
89
93
90
struct Instantiate {
94
91
vid : ty:: TyVid ,
95
92
}
96
93
97
- struct Delegate < ' tcx > ( PhantomData < & ' tcx ( ) > ) ;
94
+ struct Delegate ;
98
95
99
96
impl < ' tcx > TypeVariableTable < ' tcx > {
100
97
pub fn new ( ) -> TypeVariableTable < ' tcx > {
@@ -105,10 +102,18 @@ impl<'tcx> TypeVariableTable<'tcx> {
105
102
}
106
103
}
107
104
105
+ /// Returns the diverges flag given when `vid` was created.
106
+ ///
107
+ /// Note that this function does not return care whether
108
+ /// `vid` has been unified with something else or not.
108
109
pub fn var_diverges < ' a > ( & ' a self , vid : ty:: TyVid ) -> bool {
109
110
self . values . get ( vid. index as usize ) . diverging
110
111
}
111
112
113
+ /// Returns the origin that was given when `vid` was created.
114
+ ///
115
+ /// Note that this function does not return care whether
116
+ /// `vid` has been unified with something else or not.
112
117
pub fn var_origin ( & self , vid : ty:: TyVid ) -> & TypeVariableOrigin {
113
118
& self . values . get ( vid. index as usize ) . origin
114
119
}
@@ -137,41 +142,49 @@ impl<'tcx> TypeVariableTable<'tcx> {
137
142
/// Precondition: `vid` must not have been previously instantiated.
138
143
pub fn instantiate ( & mut self , vid : ty:: TyVid , ty : Ty < ' tcx > ) {
139
144
let vid = self . root_var ( vid) ;
140
- debug_assert ! ( self . probe_root( vid) . is_none( ) ) ;
141
-
142
- let old_value = {
143
- let vid_data = & mut self . values [ vid. index as usize ] ;
144
- mem:: replace ( & mut vid_data. value , TypeVariableValue :: Known { value : ty } )
145
- } ;
146
-
147
- match old_value {
148
- TypeVariableValue :: Unknown => {
149
- self . values . record ( Instantiate { vid : vid } ) ;
150
- }
151
- TypeVariableValue :: Known { value : old_ty } => {
152
- bug ! ( "instantiating type variable `{:?}` twice: new-value = {:?}, old-value={:?}" ,
153
- vid, ty, old_ty)
154
- }
155
- }
145
+ debug_assert ! ( self . probe( vid) . is_none( ) ) ;
146
+ debug_assert ! ( self . eq_relations. probe_value( vid) == TypeVariableValue :: Unknown ,
147
+ "instantiating type variable `{:?}` twice: new-value = {:?}, old-value={:?}" ,
148
+ vid, ty, self . eq_relations. probe_value( vid) ) ;
149
+ self . eq_relations . union_value ( vid, TypeVariableValue :: Known { value : ty } ) ;
150
+
151
+ // Hack: we only need this so that `types_escaping_snapshot`
152
+ // can see what has been unified; see the Delegate impl for
153
+ // more details.
154
+ self . values . record ( Instantiate { vid : vid } ) ;
156
155
}
157
156
157
+ /// Creates a new type variable.
158
+ ///
159
+ /// - `diverging`: indicates if this is a "diverging" type
160
+ /// variable, e.g. one created as the type of a `return`
161
+ /// expression. The code in this module doesn't care if a
162
+ /// variable is diverging, but the main Rust type-checker will
163
+ /// sometimes "unify" such variables with the `!` or `()` types.
164
+ /// - `origin`: indicates *why* the type variable was created.
165
+ /// The code in this module doesn't care, but it can be useful
166
+ /// for improving error messages.
158
167
pub fn new_var ( & mut self ,
159
168
diverging : bool ,
160
169
origin : TypeVariableOrigin )
161
170
-> ty:: TyVid {
162
- debug ! ( "new_var(diverging={:?}, origin={:?})" , diverging, origin) ;
163
- self . eq_relations . new_key ( ( ) ) ;
164
- self . sub_relations . new_key ( ( ) ) ;
171
+ let eq_key = self . eq_relations . new_key ( TypeVariableValue :: Unknown ) ;
172
+
173
+ let sub_key = self . sub_relations . new_key ( ( ) ) ;
174
+ assert_eq ! ( eq_key. vid, sub_key) ;
175
+
165
176
let index = self . values . push ( TypeVariableData {
166
- value : Unknown ,
167
177
origin,
168
178
diverging,
169
179
} ) ;
170
- let v = ty:: TyVid { index : index as u32 } ;
171
- debug ! ( "new_var: diverging={:?} index={:?}" , diverging, v) ;
172
- v
180
+ assert_eq ! ( eq_key. vid. index, index as u32 ) ;
181
+
182
+ debug ! ( "new_var(index={:?}, diverging={:?}, origin={:?}" , eq_key. vid, diverging, origin) ;
183
+
184
+ eq_key. vid
173
185
}
174
186
187
+ /// Returns the number of type variables created thus far.
175
188
pub fn num_vars ( & self ) -> usize {
176
189
self . values . len ( )
177
190
}
@@ -182,7 +195,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
182
195
/// algorithm), so `root_var(a) == root_var(b)` implies that `a ==
183
196
/// b` (transitively).
184
197
pub fn root_var ( & mut self , vid : ty:: TyVid ) -> ty:: TyVid {
185
- self . eq_relations . find ( vid)
198
+ self . eq_relations . find ( vid) . vid
186
199
}
187
200
188
201
/// Returns the "root" variable of `vid` in the `sub_relations`
@@ -202,24 +215,19 @@ impl<'tcx> TypeVariableTable<'tcx> {
202
215
self . sub_root_var ( a) == self . sub_root_var ( b)
203
216
}
204
217
218
+ /// Retrieves the type to which `vid` has been instantiated, if
219
+ /// any.
205
220
pub fn probe ( & mut self , vid : ty:: TyVid ) -> Option < Ty < ' tcx > > {
206
221
let vid = self . root_var ( vid) ;
207
- self . probe_root ( vid)
208
- }
209
-
210
- pub fn origin ( & self , vid : ty:: TyVid ) -> TypeVariableOrigin {
211
- self . values . get ( vid. index as usize ) . origin . clone ( )
212
- }
213
-
214
- /// Retrieves the type of `vid` given that it is currently a root in the unification table
215
- pub fn probe_root ( & mut self , vid : ty:: TyVid ) -> Option < Ty < ' tcx > > {
216
- debug_assert ! ( self . root_var( vid) == vid) ;
217
- match self . values . get ( vid. index as usize ) . value {
218
- Unknown => None ,
219
- Known { value } => Some ( value)
222
+ match self . eq_relations . probe_value ( vid) {
223
+ TypeVariableValue :: Unknown => None ,
224
+ TypeVariableValue :: Known { value } => Some ( value)
220
225
}
221
226
}
222
227
228
+ /// If `t` is a type-inference variable, and it has been
229
+ /// instantiated, then return the with which it was
230
+ /// instantiated. Otherwise, returns `t`.
223
231
pub fn replace_if_possible ( & mut self , t : Ty < ' tcx > ) -> Ty < ' tcx > {
224
232
match t. sty {
225
233
ty:: TyInfer ( ty:: TyVar ( v) ) => {
@@ -232,15 +240,22 @@ impl<'tcx> TypeVariableTable<'tcx> {
232
240
}
233
241
}
234
242
235
- pub fn snapshot ( & mut self ) -> Snapshot {
243
+ /// Creates a snapshot of the type variable state. This snapshot
244
+ /// must later be committed (`commit()`) or rolled back
245
+ /// (`rollback_to()`). Nested snapshots are permitted, but must
246
+ /// be processed in a stack-like fashion.
247
+ pub fn snapshot ( & mut self ) -> Snapshot < ' tcx > {
236
248
Snapshot {
237
249
snapshot : self . values . start_snapshot ( ) ,
238
250
eq_snapshot : self . eq_relations . snapshot ( ) ,
239
251
sub_snapshot : self . sub_relations . snapshot ( ) ,
240
252
}
241
253
}
242
254
243
- pub fn rollback_to ( & mut self , s : Snapshot ) {
255
+ /// Undoes all changes since the snapshot was created. Any
256
+ /// snapshots created since that point must already have been
257
+ /// committed or rolled back.
258
+ pub fn rollback_to ( & mut self , s : Snapshot < ' tcx > ) {
244
259
debug ! ( "rollback_to{:?}" , {
245
260
for action in self . values. actions_since_snapshot( & s. snapshot) {
246
261
match * action {
@@ -258,7 +273,11 @@ impl<'tcx> TypeVariableTable<'tcx> {
258
273
self . sub_relations . rollback_to ( sub_snapshot) ;
259
274
}
260
275
261
- pub fn commit ( & mut self , s : Snapshot ) {
276
+ /// Commits all changes since the snapshot was created, making
277
+ /// them permanent (unless this snapshot was created within
278
+ /// another snapshot). Any snapshots created since that point
279
+ /// must already have been committed or rolled back.
280
+ pub fn commit ( & mut self , s : Snapshot < ' tcx > ) {
262
281
let Snapshot { snapshot, eq_snapshot, sub_snapshot } = s;
263
282
self . values . commit ( snapshot) ;
264
283
self . eq_relations . commit ( eq_snapshot) ;
@@ -269,7 +288,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
269
288
/// ty-variables created during the snapshot, and the values
270
289
/// `{V2}` are the root variables that they were unified with,
271
290
/// along with their origin.
272
- pub fn types_created_since_snapshot ( & mut self , s : & Snapshot ) -> TypeVariableMap {
291
+ pub fn types_created_since_snapshot ( & mut self , s : & Snapshot < ' tcx > ) -> TypeVariableMap {
273
292
let actions_since_snapshot = self . values . actions_since_snapshot ( & s. snapshot ) ;
274
293
275
294
actions_since_snapshot
@@ -285,16 +304,13 @@ impl<'tcx> TypeVariableTable<'tcx> {
285
304
. collect ( )
286
305
}
287
306
288
- pub fn types_escaping_snapshot ( & mut self , s : & Snapshot ) -> Vec < Ty < ' tcx > > {
289
- /*!
290
- * Find the set of type variables that existed *before* `s`
291
- * but which have only been unified since `s` started, and
292
- * return the types with which they were unified. So if we had
293
- * a type variable `V0`, then we started the snapshot, then we
294
- * created a type variable `V1`, unifed `V0` with `T0`, and
295
- * unified `V1` with `T1`, this function would return `{T0}`.
296
- */
297
-
307
+ /// Find the set of type variables that existed *before* `s`
308
+ /// but which have only been unified since `s` started, and
309
+ /// return the types with which they were unified. So if we had
310
+ /// a type variable `V0`, then we started the snapshot, then we
311
+ /// created a type variable `V1`, unifed `V0` with `T0`, and
312
+ /// unified `V1` with `T1`, this function would return `{T0}`.
313
+ pub fn types_escaping_snapshot ( & mut self , s : & Snapshot < ' tcx > ) -> Vec < Ty < ' tcx > > {
298
314
let mut new_elem_threshold = u32:: MAX ;
299
315
let mut escaping_types = Vec :: new ( ) ;
300
316
let actions_since_snapshot = self . values . actions_since_snapshot ( & s. snapshot ) ;
@@ -315,9 +331,9 @@ impl<'tcx> TypeVariableTable<'tcx> {
315
331
if vid. index < new_elem_threshold {
316
332
// quick check to see if this variable was
317
333
// created since the snapshot started or not.
318
- let escaping_type = match self . values . get ( vid. index as usize ) . value {
319
- Unknown => bug ! ( ) ,
320
- Known { value } => value,
334
+ let escaping_type = match self . eq_relations . probe_value ( vid) {
335
+ TypeVariableValue :: Unknown => bug ! ( ) ,
336
+ TypeVariableValue :: Known { value } => value,
321
337
} ;
322
338
escaping_types. push ( escaping_type) ;
323
339
}
@@ -331,6 +347,8 @@ impl<'tcx> TypeVariableTable<'tcx> {
331
347
escaping_types
332
348
}
333
349
350
+ /// Returns indices of all variables that are not yet
351
+ /// instantiated.
334
352
pub fn unsolved_variables ( & mut self ) -> Vec < ty:: TyVid > {
335
353
( 0 ..self . values . len ( ) )
336
354
. filter_map ( |i| {
@@ -345,19 +363,80 @@ impl<'tcx> TypeVariableTable<'tcx> {
345
363
}
346
364
}
347
365
348
- impl < ' tcx > sv:: SnapshotVecDelegate for Delegate < ' tcx > {
349
- type Value = TypeVariableData < ' tcx > ;
366
+ impl sv:: SnapshotVecDelegate for Delegate {
367
+ type Value = TypeVariableData ;
350
368
type Undo = Instantiate ;
351
369
352
- fn reverse ( values : & mut Vec < TypeVariableData < ' tcx > > , action : Instantiate ) {
353
- let Instantiate { vid } = action;
354
- values[ vid. index as usize ] . value = Unknown ;
370
+ fn reverse ( _values : & mut Vec < TypeVariableData > , _action : Instantiate ) {
371
+ // We don't actually have to *do* anything to reverse an
372
+ // instanation; the value for a variable is stored in the
373
+ // `eq_relations` and hence its rollback code will handle
374
+ // it. In fact, we could *almost* just remove the
375
+ // `SnapshotVec` entirely, except that we would have to
376
+ // reproduce *some* of its logic, since we want to know which
377
+ // type variables have been instantiated since the snapshot
378
+ // was started, so we can implement `types_escaping_snapshot`.
379
+ //
380
+ // (If we extended the `UnificationTable` to let us see which
381
+ // values have been unified and so forth, that might also
382
+ // suffice.)
383
+ }
384
+ }
385
+
386
+ ///////////////////////////////////////////////////////////////////////////
387
+
388
+ /// These structs (a newtyped TyVid) are used as the unification key
389
+ /// for the `eq_relations`; they carry a `TypeVariableValue` along
390
+ /// with them.
391
+ #[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
392
+ struct TyVidEqKey < ' tcx > {
393
+ vid : ty:: TyVid ,
394
+
395
+ // in the table, we map each ty-vid to one of these:
396
+ phantom : PhantomData < TypeVariableValue < ' tcx > > ,
397
+ }
398
+
399
+ impl < ' tcx > From < ty:: TyVid > for TyVidEqKey < ' tcx > {
400
+ fn from ( vid : ty:: TyVid ) -> Self {
401
+ TyVidEqKey { vid, phantom : PhantomData }
402
+ }
403
+ }
404
+
405
+ impl < ' tcx > ut:: UnifyKey for TyVidEqKey < ' tcx > {
406
+ type Value = TypeVariableValue < ' tcx > ;
407
+ fn index ( & self ) -> u32 { self . vid . index }
408
+ fn from_index ( i : u32 ) -> Self { TyVidEqKey :: from ( ty:: TyVid { index : i } ) }
409
+ fn tag ( ) -> & ' static str { "TyVidEqKey" }
410
+ }
411
+
412
+ impl < ' tcx > ut:: UnifyValue for TypeVariableValue < ' tcx > {
413
+ type Error = ut:: NoError ;
414
+
415
+ fn unify_values ( value1 : & Self , value2 : & Self ) -> Result < Self , ut:: NoError > {
416
+ match ( value1, value2) {
417
+ // We never equate two type variables, both of which
418
+ // have known types. Instead, we recursively equate
419
+ // those types.
420
+ ( & TypeVariableValue :: Known { .. } , & TypeVariableValue :: Known { .. } ) => {
421
+ bug ! ( "equating two type variables, both of which have known types" )
422
+ }
423
+
424
+ // If one side is known, prefer that one.
425
+ ( & TypeVariableValue :: Known { .. } , & TypeVariableValue :: Unknown { .. } ) => Ok ( * value1) ,
426
+ ( & TypeVariableValue :: Unknown { .. } , & TypeVariableValue :: Known { .. } ) => Ok ( * value2) ,
427
+
428
+ // If both sides are *unknown*, it hardly matters, does it?
429
+ ( & TypeVariableValue :: Unknown , & TypeVariableValue :: Unknown ) => Ok ( * value1) ,
430
+ }
355
431
}
356
432
}
357
433
434
+ /// Raw `TyVid` are used as the unification key for `sub_relations`;
435
+ /// they carry no values.
358
436
impl ut:: UnifyKey for ty:: TyVid {
359
437
type Value = ( ) ;
360
438
fn index ( & self ) -> u32 { self . index }
361
439
fn from_index ( i : u32 ) -> ty:: TyVid { ty:: TyVid { index : i } }
362
440
fn tag ( ) -> & ' static str { "TyVid" }
363
441
}
442
+
0 commit comments