]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
1a4d82fc | 11 | use std::marker; |
85aaf69f SL |
12 | use std::fmt::Debug; |
13 | use std::marker::PhantomData; | |
d9579d0f AL |
14 | use snapshot_vec as sv; |
15 | ||
16 | #[cfg(test)] | |
17 | mod tests; | |
1a4d82fc JJ |
18 | |
19 | /// This trait is implemented by any type that can serve as a type | |
20 | /// variable. We call such variables *unification keys*. For example, | |
21 | /// this trait is implemented by `IntVid`, which represents integral | |
22 | /// variables. | |
23 | /// | |
24 | /// Each key type has an associated value type `V`. For example, for | |
25 | /// `IntVid`, this is `Option<IntVarValue>`, representing some | |
26 | /// (possibly not yet known) sort of integer. | |
27 | /// | |
d9579d0f AL |
28 | /// Clients are expected to provide implementations of this trait; you |
29 | /// can see some examples in the `test` module. | |
30 | pub trait UnifyKey : Copy + Clone + Debug + PartialEq { | |
31 | type Value: Clone + PartialEq + Debug; | |
85aaf69f | 32 | |
c34b1796 | 33 | fn index(&self) -> u32; |
1a4d82fc | 34 | |
c34b1796 | 35 | fn from_index(u: u32) -> Self; |
1a4d82fc JJ |
36 | |
37 | fn tag(k: Option<Self>) -> &'static str; | |
38 | } | |
39 | ||
9cc50fc6 SL |
40 | /// This trait is implemented for unify values that can be |
41 | /// combined. This relation should be a monoid. | |
42 | pub trait Combine { | |
43 | fn combine(&self, other: &Self) -> Self; | |
44 | } | |
45 | ||
46 | impl Combine for () { | |
47 | fn combine(&self, _other: &()) {} | |
48 | } | |
49 | ||
1a4d82fc JJ |
50 | /// Value of a unification key. We implement Tarjan's union-find |
51 | /// algorithm: when two keys are unified, one of them is converted | |
52 | /// into a "redirect" pointing at the other. These redirects form a | |
53 | /// DAG: the roots of the DAG (nodes that are not redirected) are each | |
54 | /// associated with a value of type `V` and a rank. The rank is used | |
55 | /// to keep the DAG relatively balanced, which helps keep the running | |
56 | /// time of the algorithm under control. For more information, see | |
57 | /// <http://en.wikipedia.org/wiki/Disjoint-set_data_structure>. | |
85aaf69f | 58 | #[derive(PartialEq,Clone,Debug)] |
54a0048b SL |
59 | pub struct VarValue<K: UnifyKey> { |
60 | parent: K, // if equal to self, this is a root | |
d9579d0f | 61 | value: K::Value, // value assigned (only relevant to root) |
54a0048b | 62 | rank: u32, // max depth (only relevant to root) |
1a4d82fc JJ |
63 | } |
64 | ||
65 | /// Table of unification keys and their values. | |
54a0048b | 66 | pub struct UnificationTable<K: UnifyKey> { |
1a4d82fc | 67 | /// Indicates the current value of each key. |
85aaf69f | 68 | values: sv::SnapshotVec<Delegate<K>>, |
1a4d82fc JJ |
69 | } |
70 | ||
71 | /// At any time, users may snapshot a unification table. The changes | |
72 | /// made during the snapshot may either be *committed* or *rolled back*. | |
54a0048b | 73 | pub struct Snapshot<K: UnifyKey> { |
1a4d82fc | 74 | // Link snapshot to the key type `K` of the table. |
85aaf69f | 75 | marker: marker::PhantomData<K>, |
1a4d82fc JJ |
76 | snapshot: sv::Snapshot, |
77 | } | |
78 | ||
c34b1796 | 79 | #[derive(Copy, Clone)] |
d9579d0f AL |
80 | struct Delegate<K>(PhantomData<K>); |
81 | ||
54a0048b | 82 | impl<K: UnifyKey> VarValue<K> { |
d9579d0f AL |
83 | fn new_var(key: K, value: K::Value) -> VarValue<K> { |
84 | VarValue::new(key, value, 0) | |
85 | } | |
86 | ||
87 | fn new(parent: K, value: K::Value, rank: u32) -> VarValue<K> { | |
54a0048b SL |
88 | VarValue { |
89 | parent: parent, // this is a root | |
90 | value: value, | |
91 | rank: rank, | |
92 | } | |
d9579d0f AL |
93 | } |
94 | ||
95 | fn redirect(self, to: K) -> VarValue<K> { | |
96 | VarValue { parent: to, ..self } | |
97 | } | |
98 | ||
99 | fn root(self, rank: u32, value: K::Value) -> VarValue<K> { | |
54a0048b SL |
100 | VarValue { |
101 | rank: rank, | |
102 | value: value, | |
103 | ..self | |
104 | } | |
d9579d0f AL |
105 | } |
106 | ||
107 | /// Returns the key of this node. Only valid if this is a root | |
108 | /// node, which you yourself must ensure. | |
109 | fn key(&self) -> K { | |
110 | self.parent | |
111 | } | |
112 | ||
113 | fn parent(&self, self_key: K) -> Option<K> { | |
114 | self.if_not_self(self.parent, self_key) | |
115 | } | |
116 | ||
117 | fn if_not_self(&self, key: K, self_key: K) -> Option<K> { | |
118 | if key == self_key { | |
119 | None | |
120 | } else { | |
121 | Some(key) | |
122 | } | |
123 | } | |
124 | } | |
1a4d82fc JJ |
125 | |
126 | // We can't use V:LatticeValue, much as I would like to, | |
127 | // because frequently the pattern is that V=Option<U> for some | |
128 | // other type parameter U, and we have no way to say | |
129 | // Option<U>:LatticeValue. | |
130 | ||
54a0048b | 131 | impl<K: UnifyKey> UnificationTable<K> { |
85aaf69f | 132 | pub fn new() -> UnificationTable<K> { |
54a0048b | 133 | UnificationTable { values: sv::SnapshotVec::new() } |
1a4d82fc JJ |
134 | } |
135 | ||
136 | /// Starts a new snapshot. Each snapshot must be either | |
137 | /// rolled back or committed in a "LIFO" (stack) order. | |
138 | pub fn snapshot(&mut self) -> Snapshot<K> { | |
54a0048b SL |
139 | Snapshot { |
140 | marker: marker::PhantomData::<K>, | |
141 | snapshot: self.values.start_snapshot(), | |
142 | } | |
1a4d82fc JJ |
143 | } |
144 | ||
145 | /// Reverses all changes since the last snapshot. Also | |
146 | /// removes any keys that have been created since then. | |
147 | pub fn rollback_to(&mut self, snapshot: Snapshot<K>) { | |
148 | debug!("{}: rollback_to()", UnifyKey::tag(None::<K>)); | |
149 | self.values.rollback_to(snapshot.snapshot); | |
150 | } | |
151 | ||
152 | /// Commits all changes since the last snapshot. Of course, they | |
153 | /// can still be undone if there is a snapshot further out. | |
154 | pub fn commit(&mut self, snapshot: Snapshot<K>) { | |
155 | debug!("{}: commit()", UnifyKey::tag(None::<K>)); | |
156 | self.values.commit(snapshot.snapshot); | |
157 | } | |
158 | ||
85aaf69f | 159 | pub fn new_key(&mut self, value: K::Value) -> K { |
d9579d0f AL |
160 | let len = self.values.len(); |
161 | let key: K = UnifyKey::from_index(len as u32); | |
162 | self.values.push(VarValue::new_var(key, value)); | |
54a0048b | 163 | debug!("{}: created new key: {:?}", UnifyKey::tag(None::<K>), key); |
d9579d0f | 164 | key |
1a4d82fc JJ |
165 | } |
166 | ||
c34b1796 AL |
167 | /// Find the root node for `vid`. This uses the standard |
168 | /// union-find algorithm with path compression: | |
169 | /// <http://en.wikipedia.org/wiki/Disjoint-set_data_structure>. | |
170 | /// | |
171 | /// NB. This is a building-block operation and you would probably | |
172 | /// prefer to call `probe` below. | |
d9579d0f | 173 | fn get(&mut self, vid: K) -> VarValue<K> { |
c34b1796 | 174 | let index = vid.index() as usize; |
d9579d0f AL |
175 | let mut value: VarValue<K> = self.values.get(index).clone(); |
176 | match value.parent(vid) { | |
177 | Some(redirect) => { | |
178 | let root: VarValue<K> = self.get(redirect); | |
179 | if root.key() != redirect { | |
1a4d82fc | 180 | // Path compression |
d9579d0f AL |
181 | value.parent = root.key(); |
182 | self.values.set(index, value); | |
1a4d82fc | 183 | } |
d9579d0f | 184 | root |
1a4d82fc | 185 | } |
54a0048b | 186 | None => value, |
1a4d82fc JJ |
187 | } |
188 | } | |
189 | ||
d9579d0f | 190 | fn is_root(&self, key: K) -> bool { |
c34b1796 | 191 | let index = key.index() as usize; |
d9579d0f | 192 | self.values.get(index).parent(key).is_none() |
1a4d82fc JJ |
193 | } |
194 | ||
c34b1796 AL |
195 | /// Sets the value for `vid` to `new_value`. `vid` MUST be a root |
196 | /// node! This is an internal operation used to impl other things. | |
197 | fn set(&mut self, key: K, new_value: VarValue<K>) { | |
d9579d0f | 198 | assert!(self.is_root(key)); |
1a4d82fc | 199 | |
54a0048b | 200 | debug!("Updating variable {:?} to {:?}", key, new_value); |
1a4d82fc | 201 | |
c34b1796 AL |
202 | let index = key.index() as usize; |
203 | self.values.set(index, new_value); | |
1a4d82fc JJ |
204 | } |
205 | ||
c34b1796 AL |
206 | /// Either redirects `node_a` to `node_b` or vice versa, depending |
207 | /// on the relative rank. The value associated with the new root | |
208 | /// will be `new_value`. | |
209 | /// | |
210 | /// NB: This is the "union" operation of "union-find". It is | |
211 | /// really more of a building block. If the values associated with | |
212 | /// your key are non-trivial, you would probably prefer to call | |
213 | /// `unify_var_var` below. | |
54a0048b | 214 | fn unify(&mut self, root_a: VarValue<K>, root_b: VarValue<K>, new_value: K::Value) -> K { |
d9579d0f AL |
215 | debug!("unify(root_a(id={:?}, rank={:?}), root_b(id={:?}, rank={:?}))", |
216 | root_a.key(), | |
217 | root_a.rank, | |
218 | root_b.key(), | |
219 | root_b.rank); | |
220 | ||
221 | if root_a.rank > root_b.rank { | |
1a4d82fc JJ |
222 | // a has greater rank, so a should become b's parent, |
223 | // i.e., b should redirect to a. | |
54a0048b | 224 | self.redirect_root(root_a.rank, root_b, root_a, new_value) |
d9579d0f | 225 | } else if root_a.rank < root_b.rank { |
1a4d82fc | 226 | // b has greater rank, so a should redirect to b. |
54a0048b | 227 | self.redirect_root(root_b.rank, root_a, root_b, new_value) |
1a4d82fc JJ |
228 | } else { |
229 | // If equal, redirect one to the other and increment the | |
230 | // other's rank. | |
54a0048b | 231 | self.redirect_root(root_a.rank + 1, root_a, root_b, new_value) |
d9579d0f AL |
232 | } |
233 | } | |
c34b1796 | 234 | |
d9579d0f AL |
235 | fn redirect_root(&mut self, |
236 | new_rank: u32, | |
237 | old_root: VarValue<K>, | |
238 | new_root: VarValue<K>, | |
54a0048b | 239 | new_value: K::Value) -> K { |
d9579d0f AL |
240 | let old_root_key = old_root.key(); |
241 | let new_root_key = new_root.key(); | |
242 | self.set(old_root_key, old_root.redirect(new_root_key)); | |
243 | self.set(new_root_key, new_root.root(new_rank, new_value)); | |
54a0048b | 244 | new_root_key |
1a4d82fc JJ |
245 | } |
246 | } | |
247 | ||
54a0048b | 248 | impl<K: UnifyKey> sv::SnapshotVecDelegate for Delegate<K> { |
85aaf69f SL |
249 | type Value = VarValue<K>; |
250 | type Undo = (); | |
251 | ||
d9579d0f AL |
252 | fn reverse(_: &mut Vec<VarValue<K>>, _: ()) {} |
253 | } | |
254 | ||
54a0048b | 255 | // # Base union-find algorithm, where we are just making sets |
d9579d0f | 256 | |
54a0048b | 257 | impl<'tcx, K: UnifyKey> UnificationTable<K> |
9cc50fc6 | 258 | where K::Value: Combine |
d9579d0f | 259 | { |
54a0048b | 260 | pub fn union(&mut self, a_id: K, b_id: K) -> K { |
d9579d0f AL |
261 | let node_a = self.get(a_id); |
262 | let node_b = self.get(b_id); | |
263 | let a_id = node_a.key(); | |
264 | let b_id = node_b.key(); | |
265 | if a_id != b_id { | |
9cc50fc6 | 266 | let new_value = node_a.value.combine(&node_b.value); |
54a0048b SL |
267 | self.unify(node_a, node_b, new_value) |
268 | } else { | |
269 | a_id | |
d9579d0f AL |
270 | } |
271 | } | |
272 | ||
273 | pub fn find(&mut self, id: K) -> K { | |
274 | self.get(id).key() | |
275 | } | |
276 | ||
9cc50fc6 SL |
277 | pub fn find_value(&mut self, id: K) -> K::Value { |
278 | self.get(id).value | |
279 | } | |
280 | ||
d9579d0f AL |
281 | pub fn unioned(&mut self, a_id: K, b_id: K) -> bool { |
282 | self.find(a_id) == self.find(b_id) | |
1a4d82fc JJ |
283 | } |
284 | } | |
285 | ||
54a0048b SL |
286 | // # Non-subtyping unification |
287 | // | |
c34b1796 AL |
288 | // Code to handle keys which carry a value, like ints, |
289 | // floats---anything that doesn't have a subtyping relationship we | |
290 | // need to worry about. | |
291 | ||
54a0048b SL |
292 | impl<'tcx, K, V> UnificationTable<K> |
293 | where K: UnifyKey<Value = Option<V>>, | |
294 | V: Clone + PartialEq + Debug | |
1a4d82fc | 295 | { |
54a0048b | 296 | pub fn unify_var_var(&mut self, a_id: K, b_id: K) -> Result<K, (V, V)> { |
c34b1796 AL |
297 | let node_a = self.get(a_id); |
298 | let node_b = self.get(b_id); | |
d9579d0f AL |
299 | let a_id = node_a.key(); |
300 | let b_id = node_b.key(); | |
1a4d82fc | 301 | |
54a0048b SL |
302 | if a_id == b_id { |
303 | return Ok(a_id); | |
304 | } | |
1a4d82fc JJ |
305 | |
306 | let combined = { | |
307 | match (&node_a.value, &node_b.value) { | |
54a0048b SL |
308 | (&None, &None) => None, |
309 | (&Some(ref v), &None) | (&None, &Some(ref v)) => Some(v.clone()), | |
1a4d82fc JJ |
310 | (&Some(ref v1), &Some(ref v2)) => { |
311 | if *v1 != *v2 { | |
c34b1796 | 312 | return Err((v1.clone(), v2.clone())); |
1a4d82fc | 313 | } |
c34b1796 | 314 | Some(v1.clone()) |
1a4d82fc JJ |
315 | } |
316 | } | |
317 | }; | |
318 | ||
d9579d0f | 319 | Ok(self.unify(node_a, node_b, combined)) |
1a4d82fc JJ |
320 | } |
321 | ||
322 | /// Sets the value of the key `a_id` to `b`. Because simple keys do not have any subtyping | |
323 | /// relationships, if `a_id` already has a value, it must be the same as `b`. | |
54a0048b | 324 | pub fn unify_var_value(&mut self, a_id: K, b: V) -> Result<(), (V, V)> { |
d9579d0f | 325 | let mut node_a = self.get(a_id); |
1a4d82fc JJ |
326 | |
327 | match node_a.value { | |
328 | None => { | |
d9579d0f AL |
329 | node_a.value = Some(b); |
330 | self.set(node_a.key(), node_a); | |
c34b1796 | 331 | Ok(()) |
1a4d82fc JJ |
332 | } |
333 | ||
334 | Some(ref a_t) => { | |
335 | if *a_t == b { | |
c34b1796 | 336 | Ok(()) |
1a4d82fc | 337 | } else { |
c34b1796 | 338 | Err((a_t.clone(), b)) |
1a4d82fc JJ |
339 | } |
340 | } | |
341 | } | |
342 | } | |
343 | ||
c34b1796 AL |
344 | pub fn has_value(&mut self, id: K) -> bool { |
345 | self.get(id).value.is_some() | |
346 | } | |
347 | ||
348 | pub fn probe(&mut self, a_id: K) -> Option<V> { | |
349 | self.get(a_id).value.clone() | |
1a4d82fc | 350 | } |
1a4d82fc | 351 | |
c1a9b12d SL |
352 | pub fn unsolved_variables(&mut self) -> Vec<K> { |
353 | self.values | |
354 | .iter() | |
54a0048b SL |
355 | .filter_map(|vv| { |
356 | if vv.value.is_some() { | |
357 | None | |
358 | } else { | |
359 | Some(vv.key()) | |
360 | } | |
361 | }) | |
c1a9b12d SL |
362 | .collect() |
363 | } | |
364 | } |