@@ -20,9 +20,11 @@ use std::marker::PhantomData;
20
20
use std:: mem;
21
21
use std:: u32;
22
22
use rustc_data_structures:: snapshot_vec as sv;
23
+ use rustc_data_structures:: unify as ut;
23
24
24
25
pub struct TypeVariableTable < ' tcx > {
25
26
values : sv:: SnapshotVec < Delegate < ' tcx > > ,
27
+ eq_relations : ut:: UnificationTable < ty:: TyVid > ,
26
28
}
27
29
28
30
struct TypeVariableData < ' tcx > {
@@ -50,20 +52,22 @@ pub struct Default<'tcx> {
50
52
}
51
53
52
54
pub struct Snapshot {
53
- snapshot : sv:: Snapshot
55
+ snapshot : sv:: Snapshot ,
56
+ eq_snapshot : ut:: Snapshot < ty:: TyVid > ,
54
57
}
55
58
56
59
enum UndoEntry < ' tcx > {
57
60
// The type of the var was specified.
58
61
SpecifyVar ( ty:: TyVid , Vec < Relation > , Option < Default < ' tcx > > ) ,
59
62
Relate ( ty:: TyVid , ty:: TyVid ) ,
63
+ RelateRange ( ty:: TyVid , usize ) ,
60
64
}
61
65
62
66
struct Delegate < ' tcx > ( PhantomData < & ' tcx ( ) > ) ;
63
67
64
68
type Relation = ( RelationDir , ty:: TyVid ) ;
65
69
66
- #[ derive( Copy , Clone , PartialEq , Debug ) ]
70
+ #[ derive( Copy , Clone , Eq , PartialEq , Hash , Debug ) ]
67
71
pub enum RelationDir {
68
72
SubtypeOf , SupertypeOf , EqTo , BiTo
69
73
}
@@ -81,7 +85,10 @@ impl RelationDir {
81
85
82
86
impl < ' tcx > TypeVariableTable < ' tcx > {
83
87
pub fn new ( ) -> TypeVariableTable < ' tcx > {
84
- TypeVariableTable { values : sv:: SnapshotVec :: new ( ) }
88
+ TypeVariableTable {
89
+ values : sv:: SnapshotVec :: new ( ) ,
90
+ eq_relations : ut:: UnificationTable :: new ( ) ,
91
+ }
85
92
}
86
93
87
94
fn relations < ' a > ( & ' a mut self , a : ty:: TyVid ) -> & ' a mut Vec < Relation > {
@@ -103,22 +110,48 @@ impl<'tcx> TypeVariableTable<'tcx> {
103
110
///
104
111
/// Precondition: neither `a` nor `b` are known.
105
112
pub fn relate_vars ( & mut self , a : ty:: TyVid , dir : RelationDir , b : ty:: TyVid ) {
113
+ let a = self . root_var ( a) ;
114
+ let b = self . root_var ( b) ;
106
115
if a != b {
107
- self . relations ( a) . push ( ( dir, b) ) ;
108
- self . relations ( b) . push ( ( dir. opposite ( ) , a) ) ;
109
- self . values . record ( Relate ( a, b) ) ;
116
+ if dir == EqTo {
117
+ // a and b must be equal which we mark in the unification table
118
+ let root = self . eq_relations . union ( a, b) ;
119
+ // In addition to being equal, all relations from the variable which is no longer
120
+ // the root must be added to the root so they are not forgotten as the other
121
+ // variable should no longer be referenced (other than to get the root)
122
+ let other = if a == root { b } else { a } ;
123
+ let count = {
124
+ let ( relations, root_relations) = if other. index < root. index {
125
+ let ( pre, post) = self . values . split_at_mut ( root. index as usize ) ;
126
+ ( relations ( & mut pre[ other. index as usize ] ) , relations ( & mut post[ 0 ] ) )
127
+ } else {
128
+ let ( pre, post) = self . values . split_at_mut ( other. index as usize ) ;
129
+ ( relations ( & mut post[ 0 ] ) , relations ( & mut pre[ root. index as usize ] ) )
130
+ } ;
131
+ root_relations. extend_from_slice ( relations) ;
132
+ relations. len ( )
133
+ } ;
134
+ self . values . record ( RelateRange ( root, count) ) ;
135
+ } else {
136
+ self . relations ( a) . push ( ( dir, b) ) ;
137
+ self . relations ( b) . push ( ( dir. opposite ( ) , a) ) ;
138
+ self . values . record ( Relate ( a, b) ) ;
139
+ }
110
140
}
111
141
}
112
142
113
143
/// Instantiates `vid` with the type `ty` and then pushes an entry onto `stack` for each of the
114
144
/// relations of `vid` to other variables. The relations will have the form `(ty, dir, vid1)`
115
145
/// where `vid1` is some other variable id.
146
+ ///
147
+ /// Precondition: `vid` must be a root in the unification table
116
148
pub fn instantiate_and_push (
117
149
& mut self ,
118
150
vid : ty:: TyVid ,
119
151
ty : Ty < ' tcx > ,
120
152
stack : & mut Vec < ( Ty < ' tcx > , RelationDir , ty:: TyVid ) > )
121
153
{
154
+ debug_assert ! ( self . root_var( vid) == vid) ;
122
155
let old_value = {
123
156
let value_ptr = & mut self . values . get_mut ( vid. index as usize ) . value ;
124
157
mem:: replace ( value_ptr, Known ( ty) )
@@ -140,21 +173,33 @@ impl<'tcx> TypeVariableTable<'tcx> {
140
173
pub fn new_var ( & mut self ,
141
174
diverging : bool ,
142
175
default : Option < Default < ' tcx > > ) -> ty:: TyVid {
176
+ self . eq_relations . new_key ( ( ) ) ;
143
177
let index = self . values . push ( TypeVariableData {
144
178
value : Bounded { relations : vec ! [ ] , default : default } ,
145
179
diverging : diverging
146
180
} ) ;
147
181
ty:: TyVid { index : index as u32 }
148
182
}
149
183
150
- pub fn probe ( & self , vid : ty:: TyVid ) -> Option < Ty < ' tcx > > {
184
+ pub fn root_var ( & mut self , vid : ty:: TyVid ) -> ty:: TyVid {
185
+ self . eq_relations . find ( vid)
186
+ }
187
+
188
+ pub fn probe ( & mut self , vid : ty:: TyVid ) -> Option < Ty < ' tcx > > {
189
+ let vid = self . root_var ( vid) ;
190
+ self . probe_root ( vid)
191
+ }
192
+
193
+ /// Retrieves the type of `vid` given that it is currently a root in the unification table
194
+ pub fn probe_root ( & mut self , vid : ty:: TyVid ) -> Option < Ty < ' tcx > > {
195
+ debug_assert ! ( self . root_var( vid) == vid) ;
151
196
match self . values . get ( vid. index as usize ) . value {
152
197
Bounded { .. } => None ,
153
198
Known ( t) => Some ( t)
154
199
}
155
200
}
156
201
157
- pub fn replace_if_possible ( & self , t : Ty < ' tcx > ) -> Ty < ' tcx > {
202
+ pub fn replace_if_possible ( & mut self , t : Ty < ' tcx > ) -> Ty < ' tcx > {
158
203
match t. sty {
159
204
ty:: TyInfer ( ty:: TyVar ( v) ) => {
160
205
match self . probe ( v) {
@@ -167,18 +212,23 @@ impl<'tcx> TypeVariableTable<'tcx> {
167
212
}
168
213
169
214
pub fn snapshot ( & mut self ) -> Snapshot {
170
- Snapshot { snapshot : self . values . start_snapshot ( ) }
215
+ Snapshot {
216
+ snapshot : self . values . start_snapshot ( ) ,
217
+ eq_snapshot : self . eq_relations . snapshot ( ) ,
218
+ }
171
219
}
172
220
173
221
pub fn rollback_to ( & mut self , s : Snapshot ) {
174
222
self . values . rollback_to ( s. snapshot ) ;
223
+ self . eq_relations . rollback_to ( s. eq_snapshot ) ;
175
224
}
176
225
177
226
pub fn commit ( & mut self , s : Snapshot ) {
178
227
self . values . commit ( s. snapshot ) ;
228
+ self . eq_relations . commit ( s. eq_snapshot ) ;
179
229
}
180
230
181
- pub fn types_escaping_snapshot ( & self , s : & Snapshot ) -> Vec < Ty < ' tcx > > {
231
+ pub fn types_escaping_snapshot ( & mut self , s : & Snapshot ) -> Vec < Ty < ' tcx > > {
182
232
/*!
183
233
* Find the set of type variables that existed *before* `s`
184
234
* but which have only been unified since `s` started, and
@@ -208,7 +258,10 @@ impl<'tcx> TypeVariableTable<'tcx> {
208
258
if vid. index < new_elem_threshold {
209
259
// quick check to see if this variable was
210
260
// created since the snapshot started or not.
211
- let escaping_type = self . probe ( vid) . unwrap ( ) ;
261
+ let escaping_type = match self . values . get ( vid. index as usize ) . value {
262
+ Bounded { .. } => unreachable ! ( ) ,
263
+ Known ( ty) => ty,
264
+ } ;
212
265
escaping_types. push ( escaping_type) ;
213
266
}
214
267
debug ! ( "SpecifyVar({:?}) new_elem_threshold={}" , vid, new_elem_threshold) ;
@@ -221,13 +274,15 @@ impl<'tcx> TypeVariableTable<'tcx> {
221
274
escaping_types
222
275
}
223
276
224
- pub fn unsolved_variables ( & self ) -> Vec < ty:: TyVid > {
225
- self . values
226
- . iter ( )
227
- . enumerate ( )
228
- . filter_map ( |( i, value) | match & value. value {
229
- & TypeVariableValue :: Known ( _) => None ,
230
- & TypeVariableValue :: Bounded { .. } => Some ( ty:: TyVid { index : i as u32 } )
277
+ pub fn unsolved_variables ( & mut self ) -> Vec < ty:: TyVid > {
278
+ ( 0 ..self . values . len ( ) )
279
+ . filter_map ( |i| {
280
+ let vid = ty:: TyVid { index : i as u32 } ;
281
+ if self . probe ( vid) . is_some ( ) {
282
+ None
283
+ } else {
284
+ Some ( vid)
285
+ }
231
286
} )
232
287
. collect ( )
233
288
}
@@ -250,6 +305,13 @@ impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> {
250
305
relations ( & mut ( * values) [ a. index as usize ] ) . pop ( ) ;
251
306
relations ( & mut ( * values) [ b. index as usize ] ) . pop ( ) ;
252
307
}
308
+
309
+ RelateRange ( i, n) => {
310
+ let relations = relations ( & mut ( * values) [ i. index as usize ] ) ;
311
+ for _ in 0 ..n {
312
+ relations. pop ( ) ;
313
+ }
314
+ }
253
315
}
254
316
}
255
317
}
0 commit comments