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.
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.
11 use std::kinds::marker;
13 use middle::ty::{expected_found, IntVarValue};
15 use middle::typeck::infer::{uok, ures};
16 use middle::typeck::infer::InferCtxt;
17 use std::cell::RefCell;
20 use util::ppaux::Repr;
21 use util::snapshot_vec as sv;
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
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.
33 * Implementations of this trait are at the end of this file.
35 pub trait UnifyKey<V> : Clone + Show + PartialEq + Repr {
36 fn index(&self) -> uint;
38 fn from_index(u: uint) -> Self;
41 * Given an inference context, returns the unification table
42 * appropriate to this key type.
44 fn unification_table<'v>(infcx: &'v InferCtxt)
45 -> &'v RefCell<UnificationTable<Self,V>>;
47 fn tag(k: Option<Self>) -> &'static str;
51 * Trait for valid types that a type variable can be set to. Note that
52 * this is typically not the end type that the value will take on, but
53 * rather an `Option` wrapper (where `None` represents a variable
54 * whose value is not yet set).
56 * Implementations of this trait are at the end of this file.
58 pub trait UnifyValue : Clone + Repr + PartialEq {
62 * Value of a unification key. We implement Tarjan's union-find
63 * algorithm: when two keys are unified, one of them is converted
64 * into a "redirect" pointing at the other. These redirects form a
65 * DAG: the roots of the DAG (nodes that are not redirected) are each
66 * associated with a value of type `V` and a rank. The rank is used
67 * to keep the DAG relatively balanced, which helps keep the running
68 * time of the algorithm under control. For more information, see
69 * <http://en.wikipedia.org/wiki/Disjoint-set_data_structure>.
71 #[deriving(PartialEq,Clone)]
72 pub enum VarValue<K,V> {
78 * Table of unification keys and their values.
80 pub struct UnificationTable<K,V> {
82 * Indicates the current value of each key.
85 values: sv::SnapshotVec<VarValue<K,V>,(),Delegate>,
89 * At any time, users may snapshot a unification table. The changes
90 * made during the snapshot may either be *committed* or *rolled back*.
92 pub struct Snapshot<K> {
93 // Link snapshot to the key type `K` of the table.
94 marker: marker::CovariantType<K>,
95 snapshot: sv::Snapshot,
99 * Internal type used to represent the result of a `get()` operation.
100 * Conveys the current root and value of the key.
102 pub struct Node<K,V> {
110 // We can't use V:LatticeValue, much as I would like to,
111 // because frequently the pattern is that V=Option<U> for some
112 // other type parameter U, and we have no way to say
113 // Option<U>:LatticeValue.
115 impl<V:PartialEq+Clone+Repr,K:UnifyKey<V>> UnificationTable<K,V> {
116 pub fn new() -> UnificationTable<K,V> {
118 values: sv::SnapshotVec::new(Delegate),
123 * Starts a new snapshot. Each snapshot must be either
124 * rolled back or committed in a "LIFO" (stack) order.
126 pub fn snapshot(&mut self) -> Snapshot<K> {
127 Snapshot { marker: marker::CovariantType::<K>,
128 snapshot: self.values.start_snapshot() }
132 * Reverses all changes since the last snapshot. Also
133 * removes any keys that have been created since then.
135 pub fn rollback_to(&mut self, snapshot: Snapshot<K>) {
136 debug!("{}: rollback_to()", UnifyKey::tag(None::<K>));
137 self.values.rollback_to(snapshot.snapshot);
141 * Commits all changes since the last snapshot. Of course, they
142 * can still be undone if there is a snapshot further out.
144 pub fn commit(&mut self, snapshot: Snapshot<K>) {
145 debug!("{}: commit()", UnifyKey::tag(None::<K>));
146 self.values.commit(snapshot.snapshot);
149 pub fn new_key(&mut self, value: V) -> K {
150 let index = self.values.push(Root(value, 0));
151 let k = UnifyKey::from_index(index);
152 debug!("{}: created new key: {}",
153 UnifyKey::tag(None::<K>),
158 pub fn get(&mut self, tcx: &ty::ctxt, vid: K) -> Node<K,V> {
160 * Find the root node for `vid`. This uses the standard
161 * union-find algorithm with path compression:
162 * http://en.wikipedia.org/wiki/Disjoint-set_data_structure
165 let index = vid.index();
166 let value = (*self.values.get(index)).clone();
168 Redirect(redirect) => {
169 let node: Node<K,V> = self.get(tcx, redirect.clone());
170 if node.key != redirect {
172 self.values.set(index, Redirect(node.key.clone()));
176 Root(value, rank) => {
177 Node { key: vid, value: value, rank: rank }
182 fn is_root(&self, key: &K) -> bool {
183 match *self.values.get(key.index()) {
184 Redirect(..) => false,
189 pub fn set(&mut self,
192 new_value: VarValue<K,V>)
195 * Sets the value for `vid` to `new_value`. `vid` MUST be a
196 * root node! Also, we must be in the middle of a snapshot.
199 assert!(self.is_root(&key));
201 debug!("Updating variable {} to {}",
203 new_value.repr(tcx));
205 self.values.set(key.index(), new_value);
208 pub fn unify(&mut self,
215 * Either redirects node_a to node_b or vice versa, depending
216 * on the relative rank. Returns the new root and rank. You
217 * should then update the value of the new root to something
221 debug!("unify(node_a(id={}, rank={}), node_b(id={}, rank={}))",
222 node_a.key.repr(tcx),
224 node_b.key.repr(tcx),
227 if node_a.rank > node_b.rank {
228 // a has greater rank, so a should become b's parent,
229 // i.e., b should redirect to a.
230 self.set(tcx, node_b.key.clone(), Redirect(node_a.key.clone()));
231 (node_a.key.clone(), node_a.rank)
232 } else if node_a.rank < node_b.rank {
233 // b has greater rank, so a should redirect to b.
234 self.set(tcx, node_a.key.clone(), Redirect(node_b.key.clone()));
235 (node_b.key.clone(), node_b.rank)
237 // If equal, redirect one to the other and increment the
239 assert_eq!(node_a.rank, node_b.rank);
240 self.set(tcx, node_b.key.clone(), Redirect(node_a.key.clone()));
241 (node_a.key.clone(), node_a.rank + 1)
246 impl<K,V> sv::SnapshotVecDelegate<VarValue<K,V>,()> for Delegate {
247 fn reverse(&mut self, _: &mut Vec<VarValue<K,V>>, _: ()) {
248 fail!("Nothing to reverse");
252 ///////////////////////////////////////////////////////////////////////////
253 // Code to handle simple keys like ints, floats---anything that
254 // doesn't have a subtyping relationship we need to worry about.
257 * Indicates a type that does not have any kind of subtyping
260 pub trait SimplyUnifiable : Clone + PartialEq + Repr {
261 fn to_type(&self) -> ty::t;
262 fn to_type_err(expected_found<Self>) -> ty::type_err;
265 pub fn err<V:SimplyUnifiable>(a_is_expected: bool,
270 Err(SimplyUnifiable::to_type_err(
271 ty::expected_found {expected: a_t, found: b_t}))
273 Err(SimplyUnifiable::to_type_err(
274 ty::expected_found {expected: b_t, found: a_t}))
278 pub trait InferCtxtMethodsForSimplyUnifiableTypes<V:SimplyUnifiable,
279 K:UnifyKey<Option<V>>> {
280 fn simple_vars(&self,
285 fn simple_var_t(&self,
290 fn probe_var(&self, a_id: K) -> Option<ty::t>;
293 impl<'a,'tcx,V:SimplyUnifiable,K:UnifyKey<Option<V>>>
294 InferCtxtMethodsForSimplyUnifiableTypes<V,K> for InferCtxt<'a, 'tcx>
296 fn simple_vars(&self,
303 * Unifies two simple keys. Because simple keys do
304 * not have any subtyping relationships, if both keys
305 * have already been associated with a value, then those two
306 * values must be the same.
310 let table = UnifyKey::unification_table(self);
311 let node_a = table.borrow_mut().get(tcx, a_id);
312 let node_b = table.borrow_mut().get(tcx, b_id);
313 let a_id = node_a.key.clone();
314 let b_id = node_b.key.clone();
316 if a_id == b_id { return uok(); }
319 match (&node_a.value, &node_b.value) {
323 (&Some(ref v), &None) | (&None, &Some(ref v)) => {
326 (&Some(ref v1), &Some(ref v2)) => {
328 return err(a_is_expected, (*v1).clone(), (*v2).clone())
335 let (new_root, new_rank) = table.borrow_mut().unify(tcx,
338 table.borrow_mut().set(tcx, new_root, Root(combined, new_rank));
342 fn simple_var_t(&self,
349 * Sets the value of the key `a_id` to `b`. Because
350 * simple keys do not have any subtyping relationships,
351 * if `a_id` already has a value, it must be the same as
356 let table = UnifyKey::unification_table(self);
357 let node_a = table.borrow_mut().get(tcx, a_id);
358 let a_id = node_a.key.clone();
362 table.borrow_mut().set(tcx, a_id, Root(Some(b), node_a.rank));
370 return err(a_is_expected, (*a_t).clone(), b);
376 fn probe_var(&self, a_id: K) -> Option<ty::t> {
378 let table = UnifyKey::unification_table(self);
379 let node_a = table.borrow_mut().get(tcx, a_id);
382 Some(ref a_t) => Some(a_t.to_type())
387 ///////////////////////////////////////////////////////////////////////////
389 // Integral type keys
391 impl UnifyKey<Option<IntVarValue>> for ty::IntVid {
392 fn index(&self) -> uint { self.index }
394 fn from_index(i: uint) -> ty::IntVid { ty::IntVid { index: i } }
396 fn unification_table<'v>(infcx: &'v InferCtxt)
397 -> &'v RefCell<UnificationTable<ty::IntVid, Option<IntVarValue>>>
399 return &infcx.int_unification_table;
402 fn tag(_: Option<ty::IntVid>) -> &'static str {
407 impl SimplyUnifiable for IntVarValue {
408 fn to_type(&self) -> ty::t {
410 ty::IntType(i) => ty::mk_mach_int(i),
411 ty::UintType(i) => ty::mk_mach_uint(i),
415 fn to_type_err(err: expected_found<IntVarValue>) -> ty::type_err {
416 return ty::terr_int_mismatch(err);
420 impl UnifyValue for Option<IntVarValue> { }
422 // Floating point type keys
424 impl UnifyKey<Option<ast::FloatTy>> for ty::FloatVid {
425 fn index(&self) -> uint { self.index }
427 fn from_index(i: uint) -> ty::FloatVid { ty::FloatVid { index: i } }
429 fn unification_table<'v>(infcx: &'v InferCtxt)
430 -> &'v RefCell<UnificationTable<ty::FloatVid, Option<ast::FloatTy>>>
432 return &infcx.float_unification_table;
435 fn tag(_: Option<ty::FloatVid>) -> &'static str {
440 impl UnifyValue for Option<ast::FloatTy> {
443 impl SimplyUnifiable for ast::FloatTy {
444 fn to_type(&self) -> ty::t {
445 ty::mk_mach_float(*self)
448 fn to_type_err(err: expected_found<ast::FloatTy>) -> ty::type_err {
449 return ty::terr_float_mismatch(err);
453 impl<K:Repr,V:Repr> Repr for VarValue<K,V> {
454 fn repr(&self, tcx: &ty::ctxt) -> String {
456 Redirect(ref k) => format!("Redirect({})", k.repr(tcx)),
457 Root(ref v, r) => format!("Root({}, {})", v.repr(tcx), r)