diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs index 220a23b183a..b3f4537f472 100644 --- a/src/librustc/middle/infer/combine.rs +++ b/src/librustc/middle/infer/combine.rs @@ -37,7 +37,6 @@ use super::equate::Equate; use super::glb::Glb; use super::lub::Lub; use super::sub::Sub; -use super::unify::InferCtxtMethodsForSimplyUnifiableTypes; use super::{InferCtxt, CombineResult}; use super::{MiscVariable, TypeTrace}; use super::type_variable::{RelationDir, BiTo, EqTo, SubtypeOf, SupertypeOf}; @@ -468,30 +467,29 @@ pub fn super_tys<'tcx, C>(this: &C, // Relate integral variables to other types (&ty::ty_infer(IntVar(a_id)), &ty::ty_infer(IntVar(b_id))) => { - try!(this.infcx().simple_vars(this.a_is_expected(), - a_id, b_id)); + try!(this.infcx().int_unification_table + .borrow_mut() + .unify_var_var(this.a_is_expected(), a_id, b_id)); Ok(a) } (&ty::ty_infer(IntVar(v_id)), &ty::ty_int(v)) => { - unify_integral_variable(this, this.a_is_expected(), - v_id, IntType(v)) + unify_integral_variable(this, this.a_is_expected(), v_id, IntType(v)) } (&ty::ty_int(v), &ty::ty_infer(IntVar(v_id))) => { - unify_integral_variable(this, !this.a_is_expected(), - v_id, IntType(v)) + unify_integral_variable(this, !this.a_is_expected(), v_id, IntType(v)) } (&ty::ty_infer(IntVar(v_id)), &ty::ty_uint(v)) => { - unify_integral_variable(this, this.a_is_expected(), - v_id, UintType(v)) + unify_integral_variable(this, this.a_is_expected(), v_id, UintType(v)) } (&ty::ty_uint(v), &ty::ty_infer(IntVar(v_id))) => { - unify_integral_variable(this, !this.a_is_expected(), - v_id, UintType(v)) + unify_integral_variable(this, !this.a_is_expected(), v_id, UintType(v)) } // Relate floating-point variables to other types (&ty::ty_infer(FloatVar(a_id)), &ty::ty_infer(FloatVar(b_id))) => { - try!(this.infcx().simple_vars(this.a_is_expected(), a_id, b_id)); + try!(this.infcx().float_unification_table + .borrow_mut() + .unify_var_var(this.a_is_expected(), a_id, b_id)); Ok(a) } (&ty::ty_infer(FloatVar(v_id)), &ty::ty_float(v)) => { @@ -617,8 +615,11 @@ pub fn super_tys<'tcx, C>(this: &C, vid: ty::IntVid, val: ty::IntVarValue) -> CombineResult<'tcx, Ty<'tcx>> - where C: Combine<'tcx> { - try!(this.infcx().simple_var_t(vid_is_expected, vid, val)); + where C: Combine<'tcx> + { + try!(this.infcx().int_unification_table + .borrow_mut() + .unify_var_value(vid_is_expected, vid, val)); match val { IntType(v) => Ok(ty::mk_mach_int(this.tcx(), v)), UintType(v) => Ok(ty::mk_mach_uint(this.tcx(), v)), @@ -630,8 +631,11 @@ pub fn super_tys<'tcx, C>(this: &C, vid: ty::FloatVid, val: ast::FloatTy) -> CombineResult<'tcx, Ty<'tcx>> - where C: Combine<'tcx> { - try!(this.infcx().simple_var_t(vid_is_expected, vid, val)); + where C: Combine<'tcx> + { + try!(this.infcx().float_unification_table + .borrow_mut() + .unify_var_value(vid_is_expected, vid, val)); Ok(ty::mk_mach_float(this.tcx(), val)) } } diff --git a/src/librustc/middle/infer/freshen.rs b/src/librustc/middle/infer/freshen.rs index e41b949d5df..39a0a276b28 100644 --- a/src/librustc/middle/infer/freshen.rs +++ b/src/librustc/middle/infer/freshen.rs @@ -37,7 +37,6 @@ use middle::ty_fold::TypeFolder; use std::collections::hash_map::{self, Entry}; use super::InferCtxt; -use super::unify::InferCtxtMethodsForSimplyUnifiableTypes; pub struct TypeFreshener<'a, 'tcx:'a> { infcx: &'a InferCtxt<'a, 'tcx>, @@ -104,29 +103,34 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + let tcx = self.infcx.tcx; + match t.sty { ty::ty_infer(ty::TyVar(v)) => { - self.freshen(self.infcx.type_variables.borrow().probe(v), - ty::TyVar(v), - ty::FreshTy) + self.freshen( + self.infcx.type_variables.borrow().probe(v), + ty::TyVar(v), + ty::FreshTy) } ty::ty_infer(ty::IntVar(v)) => { - self.freshen(self.infcx.probe_var(v), - ty::IntVar(v), - ty::FreshIntTy) + self.freshen( + self.infcx.int_unification_table.borrow_mut().probe(tcx, v), + ty::IntVar(v), + ty::FreshIntTy) } ty::ty_infer(ty::FloatVar(v)) => { - self.freshen(self.infcx.probe_var(v), - ty::FloatVar(v), - ty::FreshIntTy) + self.freshen( + self.infcx.float_unification_table.borrow_mut().probe(tcx, v), + ty::FloatVar(v), + ty::FreshIntTy) } ty::ty_infer(ty::FreshTy(c)) | ty::ty_infer(ty::FreshIntTy(c)) => { if c >= self.freshen_count { - self.tcx().sess.bug( + tcx.sess.bug( &format!("Encountered a freshend type with id {} \ but our counter is only at {}", c, diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 31ce8503ed0..faca486e669 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -43,7 +43,7 @@ use self::region_inference::{RegionVarBindings, RegionSnapshot}; use self::equate::Equate; use self::sub::Sub; use self::lub::Lub; -use self::unify::{UnificationTable, InferCtxtMethodsForSimplyUnifiableTypes}; +use self::unify::UnificationTable; use self::error_reporting::ErrorReporting; pub mod bivariate; @@ -456,14 +456,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { use middle::ty::UnconstrainedNumeric::{Neither, UnconstrainedInt, UnconstrainedFloat}; match ty.sty { ty::ty_infer(ty::IntVar(vid)) => { - match self.int_unification_table.borrow_mut().get(self.tcx, vid).value { + match self.int_unification_table.borrow_mut().get(vid).value { None => UnconstrainedInt, _ => Neither, } }, ty::ty_infer(ty::FloatVar(vid)) => { - match self.float_unification_table.borrow_mut().get(self.tcx, vid).value { - None => return UnconstrainedFloat, + match self.float_unification_table.borrow_mut().get(vid).value { + None => UnconstrainedFloat, _ => Neither, } }, @@ -881,12 +881,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } ty::ty_infer(ty::IntVar(v)) => { - self.probe_var(v) + self.int_unification_table + .borrow_mut() + .probe(self.tcx, v) .unwrap_or(typ) } ty::ty_infer(ty::FloatVar(v)) => { - self.probe_var(v) + self.float_unification_table + .borrow_mut() + .probe(self.tcx, v) .unwrap_or(typ) } diff --git a/src/librustc/middle/infer/unify.rs b/src/librustc/middle/infer/unify.rs index de96e9b49fe..e38d0bb5953 100644 --- a/src/librustc/middle/infer/unify.rs +++ b/src/librustc/middle/infer/unify.rs @@ -14,9 +14,7 @@ use std::marker; use middle::ty::{expected_found, IntVarValue}; use middle::ty::{self, Ty}; -use middle::infer::UnitResult; -use middle::infer::InferCtxt; -use std::cell::RefCell; +use middle::infer::{UnitResult}; use std::fmt::Debug; use std::marker::PhantomData; use syntax::ast; @@ -39,11 +37,6 @@ pub trait UnifyKey : Clone + Debug + PartialEq { fn from_index(u: usize) -> Self; - // Given an inference context, returns the unification table - // appropriate to this key type. - fn unification_table<'v>(infcx: &'v InferCtxt) - -> &'v RefCell>; - fn tag(k: Option) -> &'static str; } @@ -137,14 +130,18 @@ impl UnificationTable { k } - /// Find the root node for `vid`. This uses the standard union-find algorithm with path - /// compression: http://en.wikipedia.org/wiki/Disjoint-set_data_structure - pub fn get(&mut self, tcx: &ty::ctxt, vid: K) -> Node { + /// Find the root node for `vid`. This uses the standard + /// union-find algorithm with path compression: + /// . + /// + /// NB. This is a building-block operation and you would probably + /// prefer to call `probe` below. + pub fn get(&mut self, vid: K) -> Node { let index = vid.index(); let value = (*self.values.get(index)).clone(); match value { Redirect(redirect) => { - let node: Node = self.get(tcx, redirect.clone()); + let node: Node = self.get(redirect.clone()); if node.key != redirect { // Path compression self.values.set(index, Redirect(node.key.clone())); @@ -164,13 +161,9 @@ impl UnificationTable { } } - /// Sets the value for `vid` to `new_value`. `vid` MUST be a root node! Also, we must be in the - /// middle of a snapshot. - pub fn set<'tcx>(&mut self, - _tcx: &ty::ctxt<'tcx>, - key: K, - new_value: VarValue) - { + /// Sets the value for `vid` to `new_value`. `vid` MUST be a root + /// node! This is an internal operation used to impl other things. + fn set(&mut self, key: K, new_value: VarValue) { assert!(self.is_root(&key)); debug!("Updating variable {:?} to {:?}", @@ -179,37 +172,39 @@ impl UnificationTable { self.values.set(key.index(), new_value); } - /// Either redirects node_a to node_b or vice versa, depending on the relative rank. Returns - /// the new root and rank. You should then update the value of the new root to something - /// suitable. - pub fn unify<'tcx>(&mut self, - tcx: &ty::ctxt<'tcx>, - node_a: &Node, - node_b: &Node) - -> (K, usize) - { + /// Either redirects `node_a` to `node_b` or vice versa, depending + /// on the relative rank. The value associated with the new root + /// will be `new_value`. + /// + /// NB: This is the "union" operation of "union-find". It is + /// really more of a building block. If the values associated with + /// your key are non-trivial, you would probably prefer to call + /// `unify_var_var` below. + pub fn unify(&mut self, node_a: &Node, node_b: &Node, new_value: K::Value) { debug!("unify(node_a(id={:?}, rank={:?}), node_b(id={:?}, rank={:?}))", node_a.key, node_a.rank, node_b.key, node_b.rank); - if node_a.rank > node_b.rank { + let (new_root, new_rank) = if node_a.rank > node_b.rank { // a has greater rank, so a should become b's parent, // i.e., b should redirect to a. - self.set(tcx, node_b.key.clone(), Redirect(node_a.key.clone())); + self.set(node_b.key.clone(), Redirect(node_a.key.clone())); (node_a.key.clone(), node_a.rank) } else if node_a.rank < node_b.rank { // b has greater rank, so a should redirect to b. - self.set(tcx, node_a.key.clone(), Redirect(node_b.key.clone())); + self.set(node_a.key.clone(), Redirect(node_b.key.clone())); (node_b.key.clone(), node_b.rank) } else { // If equal, redirect one to the other and increment the // other's rank. assert_eq!(node_a.rank, node_b.rank); - self.set(tcx, node_b.key.clone(), Redirect(node_a.key.clone())); + self.set(node_b.key.clone(), Redirect(node_a.key.clone())); (node_a.key.clone(), node_a.rank + 1) - } + }; + + self.set(new_root, Root(new_value, new_rank)); } } @@ -223,8 +218,9 @@ impl sv::SnapshotVecDelegate for Delegate { } /////////////////////////////////////////////////////////////////////////// -// Code to handle simple keys like ints, floats---anything that -// doesn't have a subtyping relationship we need to worry about. +// Code to handle keys which carry a value, like ints, +// floats---anything that doesn't have a subtyping relationship we +// need to worry about. /// Indicates a type that does not have any kind of subtyping /// relationship. @@ -246,42 +242,19 @@ pub fn err<'tcx, V:SimplyUnifiable<'tcx>>(a_is_expected: bool, } } -pub trait InferCtxtMethodsForSimplyUnifiableTypes<'tcx,K,V> +impl<'tcx,K,V> UnificationTable where K : UnifyKey>, V : SimplyUnifiable<'tcx>, Option : UnifyValue, { - fn simple_vars(&self, - a_is_expected: bool, - a_id: K, - b_id: K) - -> UnitResult<'tcx>; - fn simple_var_t(&self, - a_is_expected: bool, - a_id: K, - b: V) - -> UnitResult<'tcx>; - fn probe_var(&self, a_id: K) -> Option>; -} - -impl<'a,'tcx,V,K> InferCtxtMethodsForSimplyUnifiableTypes<'tcx,K,V> for InferCtxt<'a,'tcx> - where K : UnifyKey>, - V : SimplyUnifiable<'tcx>, - Option : UnifyValue, -{ - /// Unifies two simple keys. Because simple keys do not have any subtyping relationships, if - /// both keys have already been associated with a value, then those two values must be the - /// same. - fn simple_vars(&self, - a_is_expected: bool, - a_id: K, - b_id: K) - -> UnitResult<'tcx> + pub fn unify_var_var(&mut self, + a_is_expected: bool, + a_id: K, + b_id: K) + -> UnitResult<'tcx> { - let tcx = self.tcx; - let table = UnifyKey::unification_table(self); - let node_a: Node = table.borrow_mut().get(tcx, a_id); - let node_b: Node = table.borrow_mut().get(tcx, b_id); + let node_a = self.get(a_id); + let node_b = self.get(b_id); let a_id = node_a.key.clone(); let b_id = node_b.key.clone(); @@ -304,46 +277,38 @@ impl<'a,'tcx,V,K> InferCtxtMethodsForSimplyUnifiableTypes<'tcx,K,V> for InferCtx } }; - let (new_root, new_rank) = table.borrow_mut().unify(tcx, - &node_a, - &node_b); - table.borrow_mut().set(tcx, new_root, Root(combined, new_rank)); - return Ok(()) + Ok(self.unify(&node_a, &node_b, combined)) } /// Sets the value of the key `a_id` to `b`. Because simple keys do not have any subtyping /// relationships, if `a_id` already has a value, it must be the same as `b`. - fn simple_var_t(&self, - a_is_expected: bool, - a_id: K, - b: V) - -> UnitResult<'tcx> + pub fn unify_var_value(&mut self, + a_is_expected: bool, + a_id: K, + b: V) + -> UnitResult<'tcx> { - let tcx = self.tcx; - let table = UnifyKey::unification_table(self); - let node_a = table.borrow_mut().get(tcx, a_id); + let node_a = self.get(a_id); let a_id = node_a.key.clone(); match node_a.value { None => { - table.borrow_mut().set(tcx, a_id, Root(Some(b), node_a.rank)); - return Ok(()); + self.set(a_id, Root(Some(b), node_a.rank)); + Ok(()) } Some(ref a_t) => { if *a_t == b { - return Ok(()); + Ok(()) } else { - return err(a_is_expected, (*a_t).clone(), b); + err(a_is_expected, (*a_t).clone(), b) } } } } - fn probe_var(&self, a_id: K) -> Option> { - let tcx = self.tcx; - let table = UnifyKey::unification_table(self); - let node_a = table.borrow_mut().get(tcx, a_id); + pub fn probe(&mut self, tcx: &ty::ctxt<'tcx>, a_id: K) -> Option> { + let node_a = self.get(a_id); match node_a.value { None => None, Some(ref a_t) => Some(a_t.to_type(tcx)) @@ -357,18 +322,9 @@ impl<'a,'tcx,V,K> InferCtxtMethodsForSimplyUnifiableTypes<'tcx,K,V> for InferCtx impl UnifyKey for ty::IntVid { type Value = Option; - fn index(&self) -> usize { self.index as usize } - fn from_index(i: usize) -> ty::IntVid { ty::IntVid { index: i as u32 } } - - fn unification_table<'v>(infcx: &'v InferCtxt) -> &'v RefCell> { - return &infcx.int_unification_table; - } - - fn tag(_: Option) -> &'static str { - "IntVid" - } + fn tag(_: Option) -> &'static str { "IntVid" } } impl<'tcx> SimplyUnifiable<'tcx> for IntVarValue { @@ -390,18 +346,9 @@ impl UnifyValue for Option { } impl UnifyKey for ty::FloatVid { type Value = Option; - fn index(&self) -> usize { self.index as usize } - fn from_index(i: usize) -> ty::FloatVid { ty::FloatVid { index: i as u32 } } - - fn unification_table<'v>(infcx: &'v InferCtxt) -> &'v RefCell> { - return &infcx.float_unification_table; - } - - fn tag(_: Option) -> &'static str { - "FloatVid" - } + fn tag(_: Option) -> &'static str { "FloatVid" } } impl UnifyValue for Option {