@@ -20,9 +20,11 @@ use std::marker::PhantomData;
2020use std:: mem;
2121use std:: u32;
2222use rustc_data_structures:: snapshot_vec as sv;
23+ use rustc_data_structures:: unify as ut;
2324
2425pub struct TypeVariableTable < ' tcx > {
2526 values : sv:: SnapshotVec < Delegate < ' tcx > > ,
27+ eq_relations : ut:: UnificationTable < ty:: TyVid > ,
2628}
2729
2830struct TypeVariableData < ' tcx > {
@@ -50,20 +52,22 @@ pub struct Default<'tcx> {
5052}
5153
5254pub struct Snapshot {
53- snapshot : sv:: Snapshot
55+ snapshot : sv:: Snapshot ,
56+ eq_snapshot : ut:: Snapshot < ty:: TyVid > ,
5457}
5558
5659enum UndoEntry < ' tcx > {
5760 // The type of the var was specified.
5861 SpecifyVar ( ty:: TyVid , Vec < Relation > , Option < Default < ' tcx > > ) ,
5962 Relate ( ty:: TyVid , ty:: TyVid ) ,
63+ RelateRange ( ty:: TyVid , usize ) ,
6064}
6165
6266struct Delegate < ' tcx > ( PhantomData < & ' tcx ( ) > ) ;
6367
6468type Relation = ( RelationDir , ty:: TyVid ) ;
6569
66- #[ derive( Copy , Clone , PartialEq , Debug ) ]
70+ #[ derive( Copy , Clone , Eq , PartialEq , Hash , Debug ) ]
6771pub enum RelationDir {
6872 SubtypeOf , SupertypeOf , EqTo , BiTo
6973}
@@ -81,7 +85,10 @@ impl RelationDir {
8185
8286impl < ' tcx > TypeVariableTable < ' tcx > {
8387 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+ }
8592 }
8693
8794 fn relations < ' a > ( & ' a mut self , a : ty:: TyVid ) -> & ' a mut Vec < Relation > {
@@ -103,22 +110,48 @@ impl<'tcx> TypeVariableTable<'tcx> {
103110 ///
104111 /// Precondition: neither `a` nor `b` are known.
105112 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) ;
106115 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+ }
110140 }
111141 }
112142
113143 /// Instantiates `vid` with the type `ty` and then pushes an entry onto `stack` for each of the
114144 /// relations of `vid` to other variables. The relations will have the form `(ty, dir, vid1)`
115145 /// where `vid1` is some other variable id.
146+ ///
147+ /// Precondition: `vid` must be a root in the unification table
116148 pub fn instantiate_and_push (
117149 & mut self ,
118150 vid : ty:: TyVid ,
119151 ty : Ty < ' tcx > ,
120152 stack : & mut Vec < ( Ty < ' tcx > , RelationDir , ty:: TyVid ) > )
121153 {
154+ debug_assert ! ( self . root_var( vid) == vid) ;
122155 let old_value = {
123156 let value_ptr = & mut self . values . get_mut ( vid. index as usize ) . value ;
124157 mem:: replace ( value_ptr, Known ( ty) )
@@ -140,21 +173,33 @@ impl<'tcx> TypeVariableTable<'tcx> {
140173 pub fn new_var ( & mut self ,
141174 diverging : bool ,
142175 default : Option < Default < ' tcx > > ) -> ty:: TyVid {
176+ self . eq_relations . new_key ( ( ) ) ;
143177 let index = self . values . push ( TypeVariableData {
144178 value : Bounded { relations : vec ! [ ] , default : default } ,
145179 diverging : diverging
146180 } ) ;
147181 ty:: TyVid { index : index as u32 }
148182 }
149183
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) ;
151196 match self . values . get ( vid. index as usize ) . value {
152197 Bounded { .. } => None ,
153198 Known ( t) => Some ( t)
154199 }
155200 }
156201
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 > {
158203 match t. sty {
159204 ty:: TyInfer ( ty:: TyVar ( v) ) => {
160205 match self . probe ( v) {
@@ -167,18 +212,23 @@ impl<'tcx> TypeVariableTable<'tcx> {
167212 }
168213
169214 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+ }
171219 }
172220
173221 pub fn rollback_to ( & mut self , s : Snapshot ) {
174222 self . values . rollback_to ( s. snapshot ) ;
223+ self . eq_relations . rollback_to ( s. eq_snapshot ) ;
175224 }
176225
177226 pub fn commit ( & mut self , s : Snapshot ) {
178227 self . values . commit ( s. snapshot ) ;
228+ self . eq_relations . commit ( s. eq_snapshot ) ;
179229 }
180230
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 > > {
182232 /*!
183233 * Find the set of type variables that existed *before* `s`
184234 * but which have only been unified since `s` started, and
@@ -208,7 +258,10 @@ impl<'tcx> TypeVariableTable<'tcx> {
208258 if vid. index < new_elem_threshold {
209259 // quick check to see if this variable was
210260 // 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+ } ;
212265 escaping_types. push ( escaping_type) ;
213266 }
214267 debug ! ( "SpecifyVar({:?}) new_elem_threshold={}" , vid, new_elem_threshold) ;
@@ -221,13 +274,15 @@ impl<'tcx> TypeVariableTable<'tcx> {
221274 escaping_types
222275 }
223276
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+ }
231286 } )
232287 . collect ( )
233288 }
@@ -250,6 +305,13 @@ impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> {
250305 relations ( & mut ( * values) [ a. index as usize ] ) . pop ( ) ;
251306 relations ( & mut ( * values) [ b. index as usize ] ) . pop ( ) ;
252307 }
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+ }
253315 }
254316 }
255317}
0 commit comments