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.
12 use std::collections::SmallIntMap;
14 use middle::ty::{Vid, expected_found, IntVarValue};
16 use middle::typeck::infer::{Bounds, uok, ures};
17 use middle::typeck::infer::InferCtxt;
18 use middle::typeck::infer::to_str::InferStr;
19 use std::cell::RefCell;
23 pub enum VarValue<V, T> {
28 pub struct ValsAndBindings<V, T> {
29 pub vals: SmallIntMap<VarValue<V, T>>,
30 pub bindings: Vec<(V, VarValue<V, T>)> ,
33 impl<V:Clone, T:Clone> ValsAndBindings<V, T> {
34 pub fn new() -> ValsAndBindings<V, T> {
36 vals: SmallIntMap::new(),
42 pub struct Node<V, T> {
44 pub possible_types: T,
48 pub trait UnifyVid<T> {
49 fn appropriate_vals_and_bindings<'v>(infcx: &'v InferCtxt)
50 -> &'v RefCell<ValsAndBindings<Self, T>>;
53 pub trait UnifyInferCtxtMethods {
55 V:Clone + PartialEq + Vid + UnifyVid<T>>(
59 fn set<T:Clone + InferStr,
60 V:Clone + Vid + ToStr + UnifyVid<T>>(
63 new_v: VarValue<V, T>);
64 fn unify<T:Clone + InferStr,
65 V:Clone + Vid + ToStr + UnifyVid<T>>(
72 impl<'a> UnifyInferCtxtMethods for InferCtxt<'a> {
74 V:Clone + PartialEq + Vid + UnifyVid<T>>(
80 * Find the root node for `vid`. This uses the standard
81 * union-find algorithm with path compression:
82 * http://en.wikipedia.org/wiki/Disjoint-set_data_structure
86 let vb = UnifyVid::appropriate_vals_and_bindings(self);
87 return helper(tcx, &mut *vb.borrow_mut(), vid);
89 fn helper<T:Clone, V:Clone+PartialEq+Vid>(
91 vb: &mut ValsAndBindings<V,T>,
94 let vid_u = vid.to_uint();
95 let var_val = match vb.vals.find(&vid_u) {
96 Some(&ref var_val) => (*var_val).clone(),
99 "failed lookup of vid `{}`", vid_u).as_slice());
104 let node: Node<V,T> = helper(tcx, vb, vid.clone());
105 if node.root != vid {
107 vb.vals.insert(vid.to_uint(),
108 Redirect(node.root.clone()));
113 Node {root: vid, possible_types: pt, rank: rk}
119 fn set<T:Clone + InferStr,
120 V:Clone + Vid + ToStr + UnifyVid<T>>(
123 new_v: VarValue<V, T>) {
126 * Sets the value for `vid` to `new_v`. `vid` MUST be a root node!
129 debug!("Updating variable {} to {}",
130 vid.to_str(), new_v.inf_str(self));
132 let vb = UnifyVid::appropriate_vals_and_bindings(self);
133 let mut vb = vb.borrow_mut();
134 let old_v = (*vb.vals.get(&vid.to_uint())).clone();
135 vb.bindings.push((vid.clone(), old_v));
136 vb.vals.insert(vid.to_uint(), new_v);
139 fn unify<T:Clone + InferStr,
140 V:Clone + Vid + ToStr + UnifyVid<T>>(
145 // Rank optimization: if you don't know what it is, check
146 // out <http://en.wikipedia.org/wiki/Disjoint-set_data_structure>
148 debug!("unify(node_a(id={:?}, rank={:?}), \
149 node_b(id={:?}, rank={:?}))",
150 node_a.root, node_a.rank,
151 node_b.root, node_b.rank);
153 if node_a.rank > node_b.rank {
154 // a has greater rank, so a should become b's parent,
155 // i.e., b should redirect to a.
156 self.set(node_b.root.clone(), Redirect(node_a.root.clone()));
157 (node_a.root.clone(), node_a.rank)
158 } else if node_a.rank < node_b.rank {
159 // b has greater rank, so a should redirect to b.
160 self.set(node_a.root.clone(), Redirect(node_b.root.clone()));
161 (node_b.root.clone(), node_b.rank)
163 // If equal, redirect one to the other and increment the
165 assert_eq!(node_a.rank, node_b.rank);
166 self.set(node_b.root.clone(), Redirect(node_a.root.clone()));
167 (node_a.root.clone(), node_a.rank + 1)
173 // ______________________________________________________________________
174 // Code to handle simple variables like ints, floats---anything that
175 // doesn't have a subtyping relationship we need to worry about.
177 pub trait SimplyUnifiable {
178 fn to_type_err(expected_found<Self>) -> ty::type_err;
181 pub fn mk_err<T:SimplyUnifiable>(a_is_expected: bool,
185 Err(SimplyUnifiable::to_type_err(
186 ty::expected_found {expected: a_t, found: b_t}))
188 Err(SimplyUnifiable::to_type_err(
189 ty::expected_found {expected: b_t, found: a_t}))
193 pub trait InferCtxtMethods {
194 fn simple_vars<T:Clone + PartialEq + InferStr + SimplyUnifiable,
195 V:Clone + PartialEq + Vid + ToStr + UnifyVid<Option<T>>>(
201 fn simple_var_t<T:Clone + PartialEq + InferStr + SimplyUnifiable,
202 V:Clone + PartialEq + Vid + ToStr + UnifyVid<Option<T>>>(
210 impl<'a> InferCtxtMethods for InferCtxt<'a> {
211 fn simple_vars<T:Clone + PartialEq + InferStr + SimplyUnifiable,
212 V:Clone + PartialEq + Vid + ToStr + UnifyVid<Option<T>>>(
220 * Unifies two simple variables. Because simple variables do
221 * not have any subtyping relationships, if both variables
222 * have already been associated with a value, then those two
223 * values must be the same. */
225 let node_a = self.get(a_id);
226 let node_b = self.get(b_id);
227 let a_id = node_a.root.clone();
228 let b_id = node_b.root.clone();
230 if a_id == b_id { return uok(); }
232 let combined = match (&node_a.possible_types, &node_b.possible_types)
234 (&None, &None) => None,
235 (&Some(ref v), &None) | (&None, &Some(ref v)) => {
238 (&Some(ref v1), &Some(ref v2)) => {
240 return mk_err(a_is_expected, (*v1).clone(), (*v2).clone())
246 let (new_root, new_rank) = self.unify(&node_a, &node_b);
247 self.set(new_root, Root(combined, new_rank));
251 fn simple_var_t<T:Clone + PartialEq + InferStr + SimplyUnifiable,
252 V:Clone + PartialEq + Vid + ToStr + UnifyVid<Option<T>>>(
260 * Sets the value of the variable `a_id` to `b`. Because
261 * simple variables do not have any subtyping relationships,
262 * if `a_id` already has a value, it must be the same as
265 let node_a = self.get(a_id);
266 let a_id = node_a.root.clone();
268 match node_a.possible_types {
270 self.set(a_id, Root(Some(b), node_a.rank));
278 return mk_err(a_is_expected, (*a_t).clone(), b);
285 // ______________________________________________________________________
287 impl UnifyVid<Bounds<ty::t>> for ty::TyVid {
288 fn appropriate_vals_and_bindings<'v>(infcx: &'v InferCtxt)
289 -> &'v RefCell<ValsAndBindings<ty::TyVid, Bounds<ty::t>>> {
290 return &infcx.ty_var_bindings;
294 impl UnifyVid<Option<IntVarValue>> for ty::IntVid {
295 fn appropriate_vals_and_bindings<'v>(infcx: &'v InferCtxt)
296 -> &'v RefCell<ValsAndBindings<ty::IntVid, Option<IntVarValue>>> {
297 return &infcx.int_var_bindings;
301 impl SimplyUnifiable for IntVarValue {
302 fn to_type_err(err: expected_found<IntVarValue>) -> ty::type_err {
303 return ty::terr_int_mismatch(err);
307 impl UnifyVid<Option<ast::FloatTy>> for ty::FloatVid {
308 fn appropriate_vals_and_bindings<'v>(infcx: &'v InferCtxt)
309 -> &'v RefCell<ValsAndBindings<ty::FloatVid, Option<ast::FloatTy>>> {
310 return &infcx.float_var_bindings;
314 impl SimplyUnifiable for ast::FloatTy {
315 fn to_type_err(err: expected_found<ast::FloatTy>) -> ty::type_err {
316 return ty::terr_float_mismatch(err);