]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/infer/unify.rs
Auto merge of #22517 - brson:relnotes, r=Gankro
[rust.git] / src / librustc / middle / infer / unify.rs
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
11 pub use self::VarValue::*;
12
13 use std::marker;
14
15 use middle::ty::{expected_found, IntVarValue};
16 use middle::ty::{self, Ty};
17 use middle::infer::{uok, ures};
18 use middle::infer::InferCtxt;
19 use std::cell::RefCell;
20 use std::fmt::Debug;
21 use syntax::ast;
22 use util::snapshot_vec as sv;
23
24 /// This trait is implemented by any type that can serve as a type
25 /// variable. We call such variables *unification keys*. For example,
26 /// this trait is implemented by `IntVid`, which represents integral
27 /// variables.
28 ///
29 /// Each key type has an associated value type `V`. For example, for
30 /// `IntVid`, this is `Option<IntVarValue>`, representing some
31 /// (possibly not yet known) sort of integer.
32 ///
33 /// Implementations of this trait are at the end of this file.
34 pub trait UnifyKey : Clone + Debug + PartialEq {
35     type Value : UnifyValue;
36
37     fn index(&self) -> uint;
38
39     fn from_index(u: uint) -> Self;
40
41     // Given an inference context, returns the unification table
42     // appropriate to this key type.
43     fn unification_table<'v>(infcx: &'v InferCtxt)
44                              -> &'v RefCell<UnificationTable<Self>>;
45
46     fn tag(k: Option<Self>) -> &'static str;
47 }
48
49 /// Trait for valid types that a type variable can be set to. Note that
50 /// this is typically not the end type that the value will take on, but
51 /// rather an `Option` wrapper (where `None` represents a variable
52 /// whose value is not yet set).
53 ///
54 /// Implementations of this trait are at the end of this file.
55 pub trait UnifyValue : Clone + PartialEq + Debug {
56 }
57
58 /// Value of a unification key. We implement Tarjan's union-find
59 /// algorithm: when two keys are unified, one of them is converted
60 /// into a "redirect" pointing at the other. These redirects form a
61 /// DAG: the roots of the DAG (nodes that are not redirected) are each
62 /// associated with a value of type `V` and a rank. The rank is used
63 /// to keep the DAG relatively balanced, which helps keep the running
64 /// time of the algorithm under control. For more information, see
65 /// <http://en.wikipedia.org/wiki/Disjoint-set_data_structure>.
66 #[derive(PartialEq,Clone,Debug)]
67 pub enum VarValue<K:UnifyKey> {
68     Redirect(K),
69     Root(K::Value, uint),
70 }
71
72 /// Table of unification keys and their values.
73 pub struct UnificationTable<K:UnifyKey> {
74     /// Indicates the current value of each key.
75     values: sv::SnapshotVec<Delegate<K>>,
76 }
77
78 /// At any time, users may snapshot a unification table.  The changes
79 /// made during the snapshot may either be *committed* or *rolled back*.
80 pub struct Snapshot<K:UnifyKey> {
81     // Link snapshot to the key type `K` of the table.
82     marker: marker::CovariantType<K>,
83     snapshot: sv::Snapshot,
84 }
85
86 /// Internal type used to represent the result of a `get()` operation.
87 /// Conveys the current root and value of the key.
88 pub struct Node<K:UnifyKey> {
89     pub key: K,
90     pub value: K::Value,
91     pub rank: uint,
92 }
93
94 #[derive(Copy)]
95 pub struct Delegate<K>;
96
97 // We can't use V:LatticeValue, much as I would like to,
98 // because frequently the pattern is that V=Option<U> for some
99 // other type parameter U, and we have no way to say
100 // Option<U>:LatticeValue.
101
102 impl<K:UnifyKey> UnificationTable<K> {
103     pub fn new() -> UnificationTable<K> {
104         UnificationTable {
105             values: sv::SnapshotVec::new(Delegate),
106         }
107     }
108
109     /// Starts a new snapshot. Each snapshot must be either
110     /// rolled back or committed in a "LIFO" (stack) order.
111     pub fn snapshot(&mut self) -> Snapshot<K> {
112         Snapshot { marker: marker::CovariantType::<K>,
113                    snapshot: self.values.start_snapshot() }
114     }
115
116     /// Reverses all changes since the last snapshot. Also
117     /// removes any keys that have been created since then.
118     pub fn rollback_to(&mut self, snapshot: Snapshot<K>) {
119         debug!("{}: rollback_to()", UnifyKey::tag(None::<K>));
120         self.values.rollback_to(snapshot.snapshot);
121     }
122
123     /// Commits all changes since the last snapshot. Of course, they
124     /// can still be undone if there is a snapshot further out.
125     pub fn commit(&mut self, snapshot: Snapshot<K>) {
126         debug!("{}: commit()", UnifyKey::tag(None::<K>));
127         self.values.commit(snapshot.snapshot);
128     }
129
130     pub fn new_key(&mut self, value: K::Value) -> K {
131         let index = self.values.push(Root(value, 0));
132         let k = UnifyKey::from_index(index);
133         debug!("{}: created new key: {:?}",
134                UnifyKey::tag(None::<K>),
135                k);
136         k
137     }
138
139     /// Find the root node for `vid`. This uses the standard union-find algorithm with path
140     /// compression: http://en.wikipedia.org/wiki/Disjoint-set_data_structure
141     pub fn get(&mut self, tcx: &ty::ctxt, vid: K) -> Node<K> {
142         let index = vid.index();
143         let value = (*self.values.get(index)).clone();
144         match value {
145             Redirect(redirect) => {
146                 let node: Node<K> = self.get(tcx, redirect.clone());
147                 if node.key != redirect {
148                     // Path compression
149                     self.values.set(index, Redirect(node.key.clone()));
150                 }
151                 node
152             }
153             Root(value, rank) => {
154                 Node { key: vid, value: value, rank: rank }
155             }
156         }
157     }
158
159     fn is_root(&self, key: &K) -> bool {
160         match *self.values.get(key.index()) {
161             Redirect(..) => false,
162             Root(..) => true,
163         }
164     }
165
166     /// Sets the value for `vid` to `new_value`. `vid` MUST be a root node! Also, we must be in the
167     /// middle of a snapshot.
168     pub fn set<'tcx>(&mut self,
169                      _tcx: &ty::ctxt<'tcx>,
170                      key: K,
171                      new_value: VarValue<K>)
172     {
173         assert!(self.is_root(&key));
174
175         debug!("Updating variable {:?} to {:?}",
176                key, new_value);
177
178         self.values.set(key.index(), new_value);
179     }
180
181     /// Either redirects node_a to node_b or vice versa, depending on the relative rank. Returns
182     /// the new root and rank. You should then update the value of the new root to something
183     /// suitable.
184     pub fn unify<'tcx>(&mut self,
185                        tcx: &ty::ctxt<'tcx>,
186                        node_a: &Node<K>,
187                        node_b: &Node<K>)
188                        -> (K, uint)
189     {
190         debug!("unify(node_a(id={:?}, rank={:?}), node_b(id={:?}, rank={:?}))",
191                node_a.key,
192                node_a.rank,
193                node_b.key,
194                node_b.rank);
195
196         if node_a.rank > node_b.rank {
197             // a has greater rank, so a should become b's parent,
198             // i.e., b should redirect to a.
199             self.set(tcx, node_b.key.clone(), Redirect(node_a.key.clone()));
200             (node_a.key.clone(), node_a.rank)
201         } else if node_a.rank < node_b.rank {
202             // b has greater rank, so a should redirect to b.
203             self.set(tcx, node_a.key.clone(), Redirect(node_b.key.clone()));
204             (node_b.key.clone(), node_b.rank)
205         } else {
206             // If equal, redirect one to the other and increment the
207             // other's rank.
208             assert_eq!(node_a.rank, node_b.rank);
209             self.set(tcx, node_b.key.clone(), Redirect(node_a.key.clone()));
210             (node_a.key.clone(), node_a.rank + 1)
211         }
212     }
213 }
214
215 impl<K:UnifyKey> sv::SnapshotVecDelegate for Delegate<K> {
216     type Value = VarValue<K>;
217     type Undo = ();
218
219     fn reverse(&mut self, _: &mut Vec<VarValue<K>>, _: ()) {
220         panic!("Nothing to reverse");
221     }
222 }
223
224 ///////////////////////////////////////////////////////////////////////////
225 // Code to handle simple keys like ints, floats---anything that
226 // doesn't have a subtyping relationship we need to worry about.
227
228 /// Indicates a type that does not have any kind of subtyping
229 /// relationship.
230 pub trait SimplyUnifiable<'tcx> : Clone + PartialEq + Debug {
231     fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx>;
232     fn to_type_err(expected_found<Self>) -> ty::type_err<'tcx>;
233 }
234
235 pub fn err<'tcx, V:SimplyUnifiable<'tcx>>(a_is_expected: bool,
236                                           a_t: V,
237                                           b_t: V)
238                                           -> ures<'tcx> {
239     if a_is_expected {
240         Err(SimplyUnifiable::to_type_err(
241             ty::expected_found {expected: a_t, found: b_t}))
242     } else {
243         Err(SimplyUnifiable::to_type_err(
244             ty::expected_found {expected: b_t, found: a_t}))
245     }
246 }
247
248 pub trait InferCtxtMethodsForSimplyUnifiableTypes<'tcx,K,V>
249     where K : UnifyKey<Value=Option<V>>,
250           V : SimplyUnifiable<'tcx>,
251           Option<V> : UnifyValue,
252 {
253     fn simple_vars(&self,
254                    a_is_expected: bool,
255                    a_id: K,
256                    b_id: K)
257                    -> ures<'tcx>;
258     fn simple_var_t(&self,
259                     a_is_expected: bool,
260                     a_id: K,
261                     b: V)
262                     -> ures<'tcx>;
263     fn probe_var(&self, a_id: K) -> Option<Ty<'tcx>>;
264 }
265
266 impl<'a,'tcx,V,K> InferCtxtMethodsForSimplyUnifiableTypes<'tcx,K,V> for InferCtxt<'a,'tcx>
267     where K : UnifyKey<Value=Option<V>>,
268           V : SimplyUnifiable<'tcx>,
269           Option<V> : UnifyValue,
270 {
271     /// Unifies two simple keys. Because simple keys do not have any subtyping relationships, if
272     /// both keys have already been associated with a value, then those two values must be the
273     /// same.
274     fn simple_vars(&self,
275                    a_is_expected: bool,
276                    a_id: K,
277                    b_id: K)
278                    -> ures<'tcx>
279     {
280         let tcx = self.tcx;
281         let table = UnifyKey::unification_table(self);
282         let node_a: Node<K> = table.borrow_mut().get(tcx, a_id);
283         let node_b: Node<K> = table.borrow_mut().get(tcx, b_id);
284         let a_id = node_a.key.clone();
285         let b_id = node_b.key.clone();
286
287         if a_id == b_id { return uok(); }
288
289         let combined = {
290             match (&node_a.value, &node_b.value) {
291                 (&None, &None) => {
292                     None
293                 }
294                 (&Some(ref v), &None) | (&None, &Some(ref v)) => {
295                     Some((*v).clone())
296                 }
297                 (&Some(ref v1), &Some(ref v2)) => {
298                     if *v1 != *v2 {
299                         return err(a_is_expected, (*v1).clone(), (*v2).clone())
300                     }
301                     Some((*v1).clone())
302                 }
303             }
304         };
305
306         let (new_root, new_rank) = table.borrow_mut().unify(tcx,
307                                                             &node_a,
308                                                             &node_b);
309         table.borrow_mut().set(tcx, new_root, Root(combined, new_rank));
310         return Ok(())
311     }
312
313     /// Sets the value of the key `a_id` to `b`. Because simple keys do not have any subtyping
314     /// relationships, if `a_id` already has a value, it must be the same as `b`.
315     fn simple_var_t(&self,
316                     a_is_expected: bool,
317                     a_id: K,
318                     b: V)
319                     -> ures<'tcx>
320     {
321         let tcx = self.tcx;
322         let table = UnifyKey::unification_table(self);
323         let node_a = table.borrow_mut().get(tcx, a_id);
324         let a_id = node_a.key.clone();
325
326         match node_a.value {
327             None => {
328                 table.borrow_mut().set(tcx, a_id, Root(Some(b), node_a.rank));
329                 return Ok(());
330             }
331
332             Some(ref a_t) => {
333                 if *a_t == b {
334                     return Ok(());
335                 } else {
336                     return err(a_is_expected, (*a_t).clone(), b);
337                 }
338             }
339         }
340     }
341
342     fn probe_var(&self, a_id: K) -> Option<Ty<'tcx>> {
343         let tcx = self.tcx;
344         let table = UnifyKey::unification_table(self);
345         let node_a = table.borrow_mut().get(tcx, a_id);
346         match node_a.value {
347             None => None,
348             Some(ref a_t) => Some(a_t.to_type(tcx))
349         }
350     }
351 }
352
353 ///////////////////////////////////////////////////////////////////////////
354
355 // Integral type keys
356
357 impl UnifyKey for ty::IntVid {
358     type Value = Option<IntVarValue>;
359
360     fn index(&self) -> uint { self.index as uint }
361
362     fn from_index(i: uint) -> ty::IntVid { ty::IntVid { index: i as u32 } }
363
364     fn unification_table<'v>(infcx: &'v InferCtxt) -> &'v RefCell<UnificationTable<ty::IntVid>> {
365         return &infcx.int_unification_table;
366     }
367
368     fn tag(_: Option<ty::IntVid>) -> &'static str {
369         "IntVid"
370     }
371 }
372
373 impl<'tcx> SimplyUnifiable<'tcx> for IntVarValue {
374     fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> {
375         match *self {
376             ty::IntType(i) => ty::mk_mach_int(tcx, i),
377             ty::UintType(i) => ty::mk_mach_uint(tcx, i),
378         }
379     }
380
381     fn to_type_err(err: expected_found<IntVarValue>) -> ty::type_err<'tcx> {
382         return ty::terr_int_mismatch(err);
383     }
384 }
385
386 impl UnifyValue for Option<IntVarValue> { }
387
388 // Floating point type keys
389
390 impl UnifyKey for ty::FloatVid {
391     type Value = Option<ast::FloatTy>;
392
393     fn index(&self) -> uint { self.index as uint }
394
395     fn from_index(i: uint) -> ty::FloatVid { ty::FloatVid { index: i as u32 } }
396
397     fn unification_table<'v>(infcx: &'v InferCtxt) -> &'v RefCell<UnificationTable<ty::FloatVid>> {
398         return &infcx.float_unification_table;
399     }
400
401     fn tag(_: Option<ty::FloatVid>) -> &'static str {
402         "FloatVid"
403     }
404 }
405
406 impl UnifyValue for Option<ast::FloatTy> {
407 }
408
409 impl<'tcx> SimplyUnifiable<'tcx> for ast::FloatTy {
410     fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> {
411         ty::mk_mach_float(tcx, *self)
412     }
413
414     fn to_type_err(err: expected_found<ast::FloatTy>) -> ty::type_err<'tcx> {
415         ty::terr_float_mismatch(err)
416     }
417 }