提交 020373f2 编写于 作者: N Niko Matsakis

Refactor the unification code and rejuvenate the unit test

infrastructure that has been accidentally left out of the build
for a rather long time (it was still using `@DVec`!)
上级 4c39962d
......@@ -850,17 +850,23 @@ fn from_uint(v: uint) -> BuiltinBound {
}
#[deriving(Clone, PartialEq, Eq, Hash)]
pub struct TyVid(pub uint);
pub struct TyVid {
pub index: uint
}
#[deriving(Clone, PartialEq, Eq, Hash)]
pub struct IntVid(pub uint);
pub struct IntVid {
pub index: uint
}
#[deriving(Clone, PartialEq, Eq, Hash)]
pub struct FloatVid(pub uint);
pub struct FloatVid {
pub index: uint
}
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash)]
pub struct RegionVid {
pub id: uint
pub index: uint
}
#[deriving(Clone, PartialEq, Eq, Hash)]
......@@ -893,47 +899,27 @@ fn ne(&self, other: &InferRegion) -> bool {
}
}
pub trait Vid {
fn to_uint(&self) -> uint;
}
impl Vid for TyVid {
fn to_uint(&self) -> uint { let TyVid(v) = *self; v }
}
impl fmt::Show for TyVid {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result{
write!(f, "<generic #{}>", self.to_uint())
write!(f, "<generic #{}>", self.index)
}
}
impl Vid for IntVid {
fn to_uint(&self) -> uint { let IntVid(v) = *self; v }
}
impl fmt::Show for IntVid {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "<generic integer #{}>", self.to_uint())
write!(f, "<generic integer #{}>", self.index)
}
}
impl Vid for FloatVid {
fn to_uint(&self) -> uint { let FloatVid(v) = *self; v }
}
impl fmt::Show for FloatVid {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "<generic float #{}>", self.to_uint())
write!(f, "<generic float #{}>", self.index)
}
}
impl Vid for RegionVid {
fn to_uint(&self) -> uint { self.id }
}
impl fmt::Show for RegionVid {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.id.fmt(f)
write!(f, "'<generic lifetime #{}>", self.index)
}
}
......
......@@ -519,7 +519,8 @@ fn universally_quantify_polytype(&self, polytype: ty_param_bounds_and_ty)
fn can_unify_universally_quantified<'a>(&self,
a: &'a UniversalQuantificationResult,
b: &'a UniversalQuantificationResult)
-> bool {
-> bool
{
infer::can_mk_subty(&self.inference_context,
a.monotype,
b.monotype).is_ok()
......
......@@ -71,9 +71,9 @@ fn foo<A>(a: A, b: A) { ... }
use middle::typeck::infer::{CoerceResult, resolve_type, Coercion};
use middle::typeck::infer::combine::{CombineFields, Combine};
use middle::typeck::infer::sub::Sub;
use middle::typeck::infer::to_str::InferStr;
use middle::typeck::infer::resolve::try_resolve_tvar_shallow;
use util::common::indenter;
use util::ppaux::Repr;
use syntax::abi;
use syntax::ast::MutImmutable;
......@@ -91,8 +91,8 @@ pub fn get_ref<'a>(&'a self) -> &'a CombineFields<'f> {
pub fn tys(&self, a: ty::t, b: ty::t) -> CoerceResult {
debug!("Coerce.tys({} => {})",
a.inf_str(self.get_ref().infcx),
b.inf_str(self.get_ref().infcx));
a.repr(self.get_ref().infcx.tcx),
b.repr(self.get_ref().infcx.tcx));
let _indent = indenter();
// Examine the supertype and consider auto-borrowing.
......@@ -233,8 +233,8 @@ pub fn coerce_borrowed_pointer(&self,
mt_b: ty::mt)
-> CoerceResult {
debug!("coerce_borrowed_pointer(a={}, sty_a={:?}, b={}, mt_b={:?})",
a.inf_str(self.get_ref().infcx), sty_a,
b.inf_str(self.get_ref().infcx), mt_b);
a.repr(self.get_ref().infcx.tcx), sty_a,
b.repr(self.get_ref().infcx.tcx), mt_b);
// If we have a parameter of type `&M T_a` and the value
// provided is `expr`, we will be adding an implicit borrow,
......@@ -270,8 +270,8 @@ pub fn coerce_borrowed_string(&self,
b: ty::t)
-> CoerceResult {
debug!("coerce_borrowed_string(a={}, sty_a={:?}, b={})",
a.inf_str(self.get_ref().infcx), sty_a,
b.inf_str(self.get_ref().infcx));
a.repr(self.get_ref().infcx.tcx), sty_a,
b.repr(self.get_ref().infcx.tcx));
match *sty_a {
ty::ty_uniq(t) => match ty::get(t).sty {
......@@ -300,8 +300,8 @@ pub fn coerce_borrowed_vector(&self,
mutbl_b: ast::Mutability)
-> CoerceResult {
debug!("coerce_borrowed_vector(a={}, sty_a={:?}, b={})",
a.inf_str(self.get_ref().infcx), sty_a,
b.inf_str(self.get_ref().infcx));
a.repr(self.get_ref().infcx.tcx), sty_a,
b.repr(self.get_ref().infcx.tcx));
let sub = Sub(self.get_ref().clone());
let coercion = Coercion(self.get_ref().trace.clone());
......@@ -336,8 +336,8 @@ fn coerce_borrowed_object(&self,
b_mutbl: ast::Mutability) -> CoerceResult
{
debug!("coerce_borrowed_object(a={}, sty_a={:?}, b={})",
a.inf_str(self.get_ref().infcx), sty_a,
b.inf_str(self.get_ref().infcx));
a.repr(self.get_ref().infcx.tcx), sty_a,
b.repr(self.get_ref().infcx.tcx));
let tcx = self.get_ref().infcx.tcx;
let coercion = Coercion(self.get_ref().trace.clone());
......@@ -376,8 +376,8 @@ pub fn coerce_borrowed_fn(&self,
b: ty::t)
-> CoerceResult {
debug!("coerce_borrowed_fn(a={}, sty_a={:?}, b={})",
a.inf_str(self.get_ref().infcx), sty_a,
b.inf_str(self.get_ref().infcx));
a.repr(self.get_ref().infcx.tcx), sty_a,
b.repr(self.get_ref().infcx.tcx));
match *sty_a {
ty::ty_bare_fn(ref f) => {
......@@ -400,7 +400,7 @@ fn coerce_from_bare_fn(&self, a: ty::t, fn_ty_a: &ty::BareFnTy, b: ty::t)
self.unpack_actual_value(b, |sty_b| {
debug!("coerce_from_bare_fn(a={}, b={})",
a.inf_str(self.get_ref().infcx), b.inf_str(self.get_ref().infcx));
a.repr(self.get_ref().infcx.tcx), b.repr(self.get_ref().infcx.tcx));
if fn_ty_a.abi != abi::Rust || fn_ty_a.fn_style != ast::NormalFn {
return self.subtype(a, b);
......@@ -429,8 +429,8 @@ pub fn coerce_unsafe_ptr(&self,
mt_b: ty::mt)
-> CoerceResult {
debug!("coerce_unsafe_ptr(a={}, sty_a={:?}, b={})",
a.inf_str(self.get_ref().infcx), sty_a,
b.inf_str(self.get_ref().infcx));
a.repr(self.get_ref().infcx.tcx), sty_a,
b.repr(self.get_ref().infcx.tcx));
let mt_a = match *sty_a {
ty::ty_rptr(_, mt) => mt,
......@@ -462,8 +462,8 @@ pub fn coerce_object(&self,
bounds: ty::BuiltinBounds) -> CoerceResult {
debug!("coerce_object(a={}, sty_a={:?}, b={})",
a.inf_str(self.get_ref().infcx), sty_a,
b.inf_str(self.get_ref().infcx));
a.repr(self.get_ref().infcx.tcx), sty_a,
b.repr(self.get_ref().infcx.tcx));
Ok(Some(ty::AutoObject(trait_store, bounds,
trait_def_id, trait_substs.clone())))
......
......@@ -57,8 +57,7 @@
use middle::typeck::infer::glb::Glb;
use middle::typeck::infer::lub::Lub;
use middle::typeck::infer::sub::Sub;
use middle::typeck::infer::to_str::InferStr;
use middle::typeck::infer::unify::InferCtxtMethods;
use middle::typeck::infer::unify::InferCtxtMethodsForSimplyUnifiableTypes;
use middle::typeck::infer::{InferCtxt, cres, ures};
use middle::typeck::infer::{TypeTrace};
use util::common::indent;
......@@ -263,7 +262,7 @@ fn trait_stores(&self,
a: ty::TraitStore,
b: ty::TraitStore)
-> cres<ty::TraitStore> {
debug!("{}.trait_stores(a={:?}, b={:?})", self.tag(), a, b);
debug!("{}.trait_stores(a={}, b={})", self.tag(), a, b);
match (a, b) {
(ty::RegionTraitStore(a_r, a_m),
......@@ -409,8 +408,8 @@ fn check_ptr_to_unsized<C:Combine>(this: &C,
tcx.sess.bug(
format!("{}: bot and var types should have been handled ({},{})",
this.tag(),
a.inf_str(this.infcx()),
b.inf_str(this.infcx())).as_slice());
a.repr(this.infcx().tcx),
b.repr(this.infcx().tcx)).as_slice());
}
// Relate integral variables to other types
......
......@@ -17,16 +17,17 @@
use middle::typeck::infer::lattice::*;
use middle::typeck::infer::lub::Lub;
use middle::typeck::infer::sub::Sub;
use middle::typeck::infer::to_str::InferStr;
use middle::typeck::infer::{cres, InferCtxt};
use middle::typeck::infer::{TypeTrace, Subtype};
use middle::typeck::infer::fold_regions_in_sig;
use middle::typeck::infer::region_inference::RegionMark;
use syntax::ast::{Many, Once, MutImmutable, MutMutable};
use syntax::ast::{NormalFn, UnsafeFn, NodeId};
use syntax::ast::{Onceness, FnStyle};
use std::collections::HashMap;
use util::common::{indenter};
use util::ppaux::mt_to_str;
use util::ppaux::Repr;
pub struct Glb<'f>(pub CombineFields<'f>); // "greatest lower bound" (common subtype)
......@@ -104,8 +105,8 @@ fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres<BuiltinBounds> {
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region> {
debug!("{}.regions({:?}, {:?})",
self.tag(),
a.inf_str(self.get_ref().infcx),
b.inf_str(self.get_ref().infcx));
a.repr(self.get_ref().infcx.tcx),
b.repr(self.get_ref().infcx.tcx));
Ok(self.get_ref().infcx.region_vars.glb_regions(Subtype(self.trace()), a, b))
}
......@@ -124,14 +125,12 @@ fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
// please see the large comment in `region_inference.rs`.
debug!("{}.fn_sigs({:?}, {:?})",
self.tag(), a.inf_str(self.get_ref().infcx), b.inf_str(self.get_ref().infcx));
self.tag(), a.repr(self.get_ref().infcx.tcx), b.repr(self.get_ref().infcx.tcx));
let _indenter = indenter();
// Take a snapshot. We'll never roll this back, but in later
// phases we do want to be able to examine "all bindings that
// were created as part of this type comparison", and making a
// snapshot is a convenient way to do that.
let snapshot = self.get_ref().infcx.region_vars.start_snapshot();
// Make a mark so we can examine "all bindings that were
// created as part of this type comparison".
let mark = self.get_ref().infcx.region_vars.mark();
// Instantiate each bound region with a fresh region variable.
let (a_with_fresh, a_map) =
......@@ -145,18 +144,18 @@ fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
// Collect constraints.
let sig0 = if_ok!(super_fn_sigs(self, &a_with_fresh, &b_with_fresh));
debug!("sig0 = {}", sig0.inf_str(self.get_ref().infcx));
debug!("sig0 = {}", sig0.repr(self.get_ref().infcx.tcx));
// Generalize the regions appearing in fn_ty0 if possible
let new_vars =
self.get_ref().infcx.region_vars.vars_created_since_snapshot(snapshot);
self.get_ref().infcx.region_vars.vars_created_since_mark(mark);
let sig1 =
fold_regions_in_sig(
self.get_ref().infcx.tcx,
&sig0,
|r| {
generalize_region(self,
snapshot,
mark,
new_vars.as_slice(),
sig0.binder_id,
&a_map,
......@@ -164,11 +163,11 @@ fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
b_vars.as_slice(),
r)
});
debug!("sig1 = {}", sig1.inf_str(self.get_ref().infcx));
debug!("sig1 = {}", sig1.repr(self.get_ref().infcx.tcx));
return Ok(sig1);
fn generalize_region(this: &Glb,
snapshot: uint,
mark: RegionMark,
new_vars: &[RegionVid],
new_binder_id: NodeId,
a_map: &HashMap<ty::BoundRegion, ty::Region>,
......@@ -180,7 +179,7 @@ fn generalize_region(this: &Glb,
return r0;
}
let tainted = this.get_ref().infcx.region_vars.tainted(snapshot, r0);
let tainted = this.get_ref().infcx.region_vars.tainted(mark, r0);
let mut a_r = None;
let mut b_r = None;
......
......@@ -32,22 +32,20 @@
* a lattice.
*/
use middle::ty::{RegionVid, TyVar, Vid};
use middle::ty::{RegionVid, TyVar};
use middle::ty;
use middle::typeck::infer::{then, ToUres};
use middle::typeck::infer::{ToUres};
use middle::typeck::infer::*;
use middle::typeck::infer::combine::*;
use middle::typeck::infer::glb::Glb;
use middle::typeck::infer::lub::Lub;
use middle::typeck::infer::unify::*;
use middle::typeck::infer::unify::{Root, UnifyKey};
use middle::typeck::infer::sub::Sub;
use middle::typeck::infer::to_str::InferStr;
use util::common::indenter;
use util::ppaux::Repr;
use std::collections::HashMap;
trait LatticeValue {
trait LatticeValue : Clone + Repr + PartialEq {
fn sub(cf: CombineFields, a: &Self, b: &Self) -> ures;
fn lub(cf: CombineFields, a: &Self, b: &Self) -> cres<Self>;
fn glb(cf: CombineFields, a: &Self, b: &Self) -> cres<Self>;
......@@ -70,72 +68,73 @@ fn glb(cf: CombineFields, a: &ty::t, b: &ty::t) -> cres<ty::t> {
}
}
pub trait CombineFieldsLatticeMethods {
fn var_sub_var<T:Clone + InferStr + LatticeValue,
V:Clone + PartialEq + ToStr + Vid + UnifyVid<Bounds<T>>>(&self,
a_id: V,
b_id: V)
-> ures;
pub trait CombineFieldsLatticeMethods<T:LatticeValue, K:UnifyKey<Bounds<T>>> {
/// make variable a subtype of variable
fn var_sub_var(&self,
a_id: K,
b_id: K)
-> ures;
/// make variable a subtype of T
fn var_sub_t<T:Clone + InferStr + LatticeValue,
V:Clone + PartialEq + ToStr + Vid + UnifyVid<Bounds<T>>>(
&self,
a_id: V,
fn var_sub_t(&self,
a_id: K,
b: T)
-> ures;
fn t_sub_var<T:Clone + InferStr + LatticeValue,
V:Clone + PartialEq + ToStr + Vid + UnifyVid<Bounds<T>>>(
&self,
/// make T a subtype of variable
fn t_sub_var(&self,
a: T,
b_id: V)
b_id: K)
-> ures;
fn merge_bnd<T:Clone + InferStr + LatticeValue>(
&self,
a: &Bound<T>,
b: &Bound<T>,
lattice_op: LatticeOp<T>)
-> cres<Bound<T>>;
fn set_var_to_merged_bounds<T:Clone + InferStr + LatticeValue,
V:Clone+PartialEq+ToStr+Vid+UnifyVid<Bounds<T>>>(
&self,
v_id: V,
fn set_var_to_merged_bounds(&self,
v_id: K,
a: &Bounds<T>,
b: &Bounds<T>,
rank: uint)
-> ures;
fn bnds<T:Clone + InferStr + LatticeValue>(
&self,
a: &Bound<T>,
b: &Bound<T>)
-> ures;
}
impl<'f> CombineFieldsLatticeMethods for CombineFields<'f> {
fn var_sub_var<T:Clone + InferStr + LatticeValue,
V:Clone + PartialEq + ToStr + Vid + UnifyVid<Bounds<T>>>(
&self,
a_id: V,
b_id: V)
-> ures {
pub trait CombineFieldsLatticeMethods2<T:LatticeValue> {
fn merge_bnd(&self,
a: &Bound<T>,
b: &Bound<T>,
lattice_op: LatticeOp<T>)
-> cres<Bound<T>>;
fn bnds(&self, a: &Bound<T>, b: &Bound<T>) -> ures;
}
impl<'f,T:LatticeValue, K:UnifyKey<Bounds<T>>>
CombineFieldsLatticeMethods<T,K> for CombineFields<'f>
{
fn var_sub_var(&self,
a_id: K,
b_id: K)
-> ures
{
/*!
*
* Make one variable a subtype of another variable. This is a
* subtle and tricky process, as described in detail at the
* top of infer.rs*/
* top of infer.rs.
*/
let tcx = self.infcx.tcx;
let table = UnifyKey::unification_table(self.infcx);
// Need to make sub_id a subtype of sup_id.
let node_a = self.infcx.get(a_id);
let node_b = self.infcx.get(b_id);
let a_id = node_a.root.clone();
let b_id = node_b.root.clone();
let a_bounds = node_a.possible_types.clone();
let b_bounds = node_b.possible_types.clone();
let node_a = table.borrow_mut().get(tcx, a_id);
let node_b = table.borrow_mut().get(tcx, b_id);
let a_id = node_a.key.clone();
let b_id = node_b.key.clone();
let a_bounds = node_a.value.clone();
let b_bounds = node_b.value.clone();
debug!("vars({}={} <: {}={})",
a_id.to_str(), a_bounds.inf_str(self.infcx),
b_id.to_str(), b_bounds.inf_str(self.infcx));
a_id, a_bounds.repr(tcx),
b_id, b_bounds.repr(tcx));
if a_id == b_id { return uok(); }
if a_id == b_id { return Ok(()); }
// If both A's UB and B's LB have already been bound to types,
// see if we can make those types subtypes.
......@@ -157,96 +156,72 @@ fn var_sub_var<T:Clone + InferStr + LatticeValue,
// A remains a subtype of B. Actually, there are other options,
// but that's the route we choose to take.
let (new_root, new_rank) = self.infcx.unify(&node_a, &node_b);
let (new_root, new_rank) =
table.borrow_mut().unify(tcx, &node_a, &node_b);
self.set_var_to_merged_bounds(new_root,
&a_bounds, &b_bounds,
new_rank)
}
/// make variable a subtype of T
fn var_sub_t<T:Clone + InferStr + LatticeValue,
V:Clone + PartialEq + ToStr + Vid + UnifyVid<Bounds<T>>>(
&self,
a_id: V,
fn var_sub_t(&self,
a_id: K,
b: T)
-> ures {
-> ures
{
/*!
*
* Make a variable (`a_id`) a subtype of the concrete type `b` */
let node_a = self.infcx.get(a_id);
let a_id = node_a.root.clone();
let a_bounds = &node_a.possible_types;
* Make a variable (`a_id`) a subtype of the concrete type `b`.
*/
let tcx = self.infcx.tcx;
let table = UnifyKey::unification_table(self.infcx);
let node_a = table.borrow_mut().get(tcx, a_id);
let a_id = node_a.key.clone();
let a_bounds = &node_a.value;
let b_bounds = &Bounds { lb: None, ub: Some(b.clone()) };
debug!("var_sub_t({}={} <: {})",
a_id.to_str(),
a_bounds.inf_str(self.infcx),
b.inf_str(self.infcx));
a_id,
a_bounds.repr(self.infcx.tcx),
b.repr(self.infcx.tcx));
self.set_var_to_merged_bounds(
a_id, a_bounds, b_bounds, node_a.rank)
}
fn t_sub_var<T:Clone + InferStr + LatticeValue,
V:Clone + PartialEq + ToStr + Vid + UnifyVid<Bounds<T>>>(
&self,
fn t_sub_var(&self,
a: T,
b_id: V)
-> ures {
b_id: K)
-> ures
{
/*!
*
* Make a concrete type (`a`) a subtype of the variable `b_id` */
* Make a concrete type (`a`) a subtype of the variable `b_id`
*/
let tcx = self.infcx.tcx;
let table = UnifyKey::unification_table(self.infcx);
let a_bounds = &Bounds { lb: Some(a.clone()), ub: None };
let node_b = self.infcx.get(b_id);
let b_id = node_b.root.clone();
let b_bounds = &node_b.possible_types;
let node_b = table.borrow_mut().get(tcx, b_id);
let b_id = node_b.key.clone();
let b_bounds = &node_b.value;
debug!("t_sub_var({} <: {}={})",
a.inf_str(self.infcx),
b_id.to_str(),
b_bounds.inf_str(self.infcx));
a.repr(self.infcx.tcx),
b_id,
b_bounds.repr(self.infcx.tcx));
self.set_var_to_merged_bounds(
b_id, a_bounds, b_bounds, node_b.rank)
}
fn merge_bnd<T:Clone + InferStr + LatticeValue>(
&self,
a: &Bound<T>,
b: &Bound<T>,
lattice_op: LatticeOp<T>)
-> cres<Bound<T>> {
/*!
*
* Combines two bounds into a more general bound. */
debug!("merge_bnd({},{})",
a.inf_str(self.infcx),
b.inf_str(self.infcx));
let _r = indenter();
match (a, b) {
(&None, &None) => Ok(None),
(&Some(_), &None) => Ok((*a).clone()),
(&None, &Some(_)) => Ok((*b).clone()),
(&Some(ref v_a), &Some(ref v_b)) => {
lattice_op(self.clone(), v_a, v_b).and_then(|v| Ok(Some(v)))
}
}
}
fn set_var_to_merged_bounds<T:Clone + InferStr + LatticeValue,
V:Clone+PartialEq+ToStr+Vid+UnifyVid<Bounds<T>>>(
&self,
v_id: V,
fn set_var_to_merged_bounds(&self,
v_id: K,
a: &Bounds<T>,
b: &Bounds<T>,
rank: uint)
-> ures {
-> ures
{
/*!
*
* Updates the bounds for the variable `v_id` to be the intersection
* of `a` and `b`. That is, the new bounds for `v_id` will be
* a bounds c such that:
......@@ -254,7 +229,8 @@ fn set_var_to_merged_bounds<T:Clone + InferStr + LatticeValue,
* c.ub <: b.ub
* a.lb <: c.lb
* b.lb <: c.lb
* If this cannot be achieved, the result is failure. */
* If this cannot be achieved, the result is failure.
*/
// Think of the two diamonds, we want to find the
// intersection. There are basically four possibilities (you
......@@ -271,11 +247,13 @@ fn set_var_to_merged_bounds<T:Clone + InferStr + LatticeValue,
// A \ / A
// B
let tcx = self.infcx.tcx;
let table = UnifyKey::unification_table(self.infcx);
debug!("merge({},{},{})",
v_id.to_str(),
a.inf_str(self.infcx),
b.inf_str(self.infcx));
let _indent = indenter();
v_id,
a.repr(self.infcx.tcx),
b.repr(self.infcx.tcx));
// First, relate the lower/upper bounds of A and B.
// Note that these relations *must* hold for us
......@@ -289,29 +267,57 @@ fn set_var_to_merged_bounds<T:Clone + InferStr + LatticeValue,
let lb = if_ok!(self.merge_bnd(&a.lb, &b.lb, LatticeValue::lub));
let bounds = Bounds { lb: lb, ub: ub };
debug!("merge({}): bounds={}",
v_id.to_str(),
bounds.inf_str(self.infcx));
v_id,
bounds.repr(self.infcx.tcx));
// the new bounds must themselves
// be relatable:
let () = if_ok!(self.bnds(&bounds.lb, &bounds.ub));
self.infcx.set(v_id, Root(bounds, rank));
uok()
table.borrow_mut().set(tcx, v_id, Root(bounds, rank));
Ok(())
}
}
fn bnds<T:Clone + InferStr + LatticeValue>(&self,
a: &Bound<T>,
b: &Bound<T>)
-> ures {
debug!("bnds({} <: {})", a.inf_str(self.infcx),
b.inf_str(self.infcx));
let _r = indenter();
impl<'f,T:LatticeValue>
CombineFieldsLatticeMethods2<T> for CombineFields<'f>
{
fn merge_bnd(&self,
a: &Bound<T>,
b: &Bound<T>,
lattice_op: LatticeOp<T>)
-> cres<Bound<T>>
{
/*!
* Combines two bounds into a more general bound.
*/
debug!("merge_bnd({},{})",
a.repr(self.infcx.tcx),
b.repr(self.infcx.tcx));
match (a, b) {
(&None, &None) => Ok(None),
(&Some(_), &None) => Ok((*a).clone()),
(&None, &Some(_)) => Ok((*b).clone()),
(&Some(ref v_a), &Some(ref v_b)) => {
lattice_op(self.clone(), v_a, v_b).and_then(|v| Ok(Some(v)))
}
}
}
fn bnds(&self,
a: &Bound<T>,
b: &Bound<T>)
-> ures
{
debug!("bnds({} <: {})",
a.repr(self.infcx.tcx),
b.repr(self.infcx.tcx));
match (a, b) {
(&None, &None) |
(&Some(_), &None) |
(&None, &Some(_)) => {
uok()
Ok(())
}
(&Some(ref t_a), &Some(ref t_b)) => {
LatticeValue::sub(self.clone(), t_a, t_b)
......@@ -368,9 +374,10 @@ pub fn super_lattice_tys<L:LatticeDir+TyLatticeDir+Combine>(this: &L,
a: ty::t,
b: ty::t)
-> cres<ty::t> {
debug!("{}.lattice_tys({}, {})", this.tag(),
a.inf_str(this.infcx()),
b.inf_str(this.infcx()));
debug!("{}.lattice_tys({}, {})",
this.tag(),
a.repr(this.infcx().tcx),
b.repr(this.infcx().tcx));
if a == b {
return Ok(a);
......@@ -410,8 +417,8 @@ pub fn super_lattice_tys<L:LatticeDir+TyLatticeDir+Combine>(this: &L,
pub type LatticeDirOp<'a, T> = |a: &T, b: &T|: 'a -> cres<T>;
#[deriving(Clone)]
pub enum LatticeVarResult<V,T> {
VarResult(V),
pub enum LatticeVarResult<K,T> {
VarResult(K),
ValueResult(T)
}
......@@ -429,26 +436,31 @@ pub enum LatticeVarResult<V,T> {
* - If the variables do not both have an upper bound, we will unify
* the variables and return the unified variable, in which case the
* result is a variable. This is indicated with a `VarResult`
* return. */
pub fn lattice_vars<L:LatticeDir + Combine,
T:Clone + InferStr + LatticeValue,
V:Clone + PartialEq + ToStr + Vid + UnifyVid<Bounds<T>>>(
* return.
*/
pub fn lattice_vars<L:LatticeDir+Combine,
T:LatticeValue,
K:UnifyKey<Bounds<T>>>(
this: &L, // defines whether we want LUB or GLB
a_vid: V, // first variable
b_vid: V, // second variable
a_vid: K, // first variable
b_vid: K, // second variable
lattice_dir_op: LatticeDirOp<T>) // LUB or GLB operation on types
-> cres<LatticeVarResult<V,T>> {
let nde_a = this.infcx().get(a_vid);
let nde_b = this.infcx().get(b_vid);
let a_vid = nde_a.root.clone();
let b_vid = nde_b.root.clone();
let a_bounds = &nde_a.possible_types;
let b_bounds = &nde_b.possible_types;
-> cres<LatticeVarResult<K,T>>
{
let tcx = this.infcx().tcx;
let table = UnifyKey::unification_table(this.infcx());
let node_a = table.borrow_mut().get(tcx, a_vid);
let node_b = table.borrow_mut().get(tcx, b_vid);
let a_vid = node_a.key.clone();
let b_vid = node_b.key.clone();
let a_bounds = &node_a.value;
let b_bounds = &node_b.value;
debug!("{}.lattice_vars({}={} <: {}={})",
this.tag(),
a_vid.to_str(), a_bounds.inf_str(this.infcx()),
b_vid.to_str(), b_bounds.inf_str(this.infcx()));
a_vid, a_bounds.repr(tcx),
b_vid, b_bounds.repr(tcx));
// Same variable: the easy case.
if a_vid == b_vid {
......@@ -471,36 +483,39 @@ pub fn lattice_vars<L:LatticeDir + Combine,
// Otherwise, we need to merge A and B into one variable. We can
// then use either variable as an upper bound:
let cf = this.combine_fields();
cf.var_sub_var(a_vid.clone(), b_vid.clone()).then(|| {
Ok(VarResult(a_vid.clone()))
})
let () = try!(cf.var_sub_var(a_vid.clone(), b_vid.clone()));
Ok(VarResult(a_vid.clone()))
}
pub fn lattice_var_and_t<L:LatticeDir + Combine,
T:Clone + InferStr + LatticeValue,
V:Clone + PartialEq + ToStr + Vid + UnifyVid<Bounds<T>>>(
pub fn lattice_var_and_t<L:LatticeDir+Combine,
T:LatticeValue,
K:UnifyKey<Bounds<T>>>(
this: &L,
a_id: V,
a_id: K,
b: &T,
lattice_dir_op: LatticeDirOp<T>)
-> cres<T> {
let nde_a = this.infcx().get(a_id);
let a_id = nde_a.root.clone();
let a_bounds = &nde_a.possible_types;
-> cres<T>
{
let tcx = this.infcx().tcx;
let table = UnifyKey::unification_table(this.infcx());
let node_a = table.borrow_mut().get(tcx, a_id);
let a_id = node_a.key.clone();
let a_bounds = &node_a.value;
// The comments in this function are written for LUB, but they
// apply equally well to GLB if you inverse upper/lower/sub/super/etc.
debug!("{}.lattice_var_and_t({}={} <: {})",
this.tag(),
a_id.to_str(),
a_bounds.inf_str(this.infcx()),
b.inf_str(this.infcx()));
a_id,
a_bounds.repr(this.infcx().tcx),
b.repr(this.infcx().tcx));
match this.bnd(a_bounds) {
Some(ref a_bnd) => {
// If a has an upper bound, return the LUB(a.ub, b)
debug!("bnd=Some({})", a_bnd.inf_str(this.infcx()));
debug!("bnd=Some({})", a_bnd.repr(this.infcx().tcx));
lattice_dir_op(a_bnd, b)
}
None => {
......@@ -508,11 +523,12 @@ pub fn lattice_var_and_t<L:LatticeDir + Combine,
// and then return b.
debug!("bnd=None");
let a_bounds = this.with_bnd(a_bounds, (*b).clone());
this.combine_fields().bnds(&a_bounds.lb, &a_bounds.ub).then(|| {
this.infcx().set(a_id.clone(),
Root(a_bounds.clone(), nde_a.rank));
Ok((*b).clone())
})
let () = try!(this.combine_fields().bnds(&a_bounds.lb,
&a_bounds.ub));
table.borrow_mut().set(tcx,
a_id.clone(),
Root(a_bounds.clone(), node_a.rank));
Ok((*b).clone())
}
}
}
......
......@@ -16,16 +16,17 @@
use middle::typeck::infer::glb::Glb;
use middle::typeck::infer::lattice::*;
use middle::typeck::infer::sub::Sub;
use middle::typeck::infer::to_str::InferStr;
use middle::typeck::infer::{cres, InferCtxt};
use middle::typeck::infer::fold_regions_in_sig;
use middle::typeck::infer::{TypeTrace, Subtype};
use middle::typeck::infer::region_inference::RegionMark;
use std::collections::HashMap;
use syntax::ast::{Many, Once, NodeId};
use syntax::ast::{NormalFn, UnsafeFn};
use syntax::ast::{Onceness, FnStyle};
use syntax::ast::{MutMutable, MutImmutable};
use util::ppaux::mt_to_str;
use util::ppaux::Repr;
pub struct Lub<'f>(pub CombineFields<'f>); // least-upper-bound: common supertype
......@@ -101,10 +102,10 @@ fn contraregions(&self, a: ty::Region, b: ty::Region)
}
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region> {
debug!("{}.regions({:?}, {:?})",
debug!("{}.regions({}, {})",
self.tag(),
a.inf_str(self.get_ref().infcx),
b.inf_str(self.get_ref().infcx));
a.repr(self.get_ref().infcx.tcx),
b.repr(self.get_ref().infcx.tcx));
Ok(self.get_ref().infcx.region_vars.lub_regions(Subtype(self.trace()), a, b))
}
......@@ -113,11 +114,9 @@ fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
// Note: this is a subtle algorithm. For a full explanation,
// please see the large comment in `region_inference.rs`.
// Take a snapshot. We'll never roll this back, but in later
// phases we do want to be able to examine "all bindings that
// were created as part of this type comparison", and making a
// snapshot is a convenient way to do that.
let snapshot = self.get_ref().infcx.region_vars.start_snapshot();
// Make a mark so we can examine "all bindings that were
// created as part of this type comparison".
let mark = self.get_ref().infcx.region_vars.mark();
// Instantiate each bound region with a fresh region variable.
let (a_with_fresh, a_map) =
......@@ -129,21 +128,21 @@ fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
// Collect constraints.
let sig0 = if_ok!(super_fn_sigs(self, &a_with_fresh, &b_with_fresh));
debug!("sig0 = {}", sig0.inf_str(self.get_ref().infcx));
debug!("sig0 = {}", sig0.repr(self.get_ref().infcx.tcx));
// Generalize the regions appearing in sig0 if possible
let new_vars =
self.get_ref().infcx.region_vars.vars_created_since_snapshot(snapshot);
self.get_ref().infcx.region_vars.vars_created_since_mark(mark);
let sig1 =
fold_regions_in_sig(
self.get_ref().infcx.tcx,
&sig0,
|r| generalize_region(self, snapshot, new_vars.as_slice(),
|r| generalize_region(self, mark, new_vars.as_slice(),
sig0.binder_id, &a_map, r));
return Ok(sig1);
fn generalize_region(this: &Lub,
snapshot: uint,
mark: RegionMark,
new_vars: &[RegionVid],
new_scope: NodeId,
a_map: &HashMap<ty::BoundRegion, ty::Region>,
......@@ -156,7 +155,7 @@ fn generalize_region(this: &Lub,
return r0;
}
let tainted = this.get_ref().infcx.region_vars.tainted(snapshot, r0);
let tainted = this.get_ref().infcx.region_vars.tainted(mark, r0);
// Variables created during LUB computation which are
// *related* to regions that pre-date the LUB computation
......
......@@ -23,21 +23,21 @@
use middle::subst;
use middle::subst::Substs;
use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, Vid};
use middle::ty::{TyVid, IntVid, FloatVid, RegionVid};
use middle::ty;
use middle::ty_fold;
use middle::ty_fold::TypeFolder;
use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
use middle::typeck::infer::coercion::Coerce;
use middle::typeck::infer::combine::{Combine, CombineFields, eq_tys};
use middle::typeck::infer::region_inference::{RegionVarBindings};
use middle::typeck::infer::region_inference::{RegionVarBindings,
RegionSnapshot};
use middle::typeck::infer::resolve::{resolver};
use middle::typeck::infer::sub::Sub;
use middle::typeck::infer::lub::Lub;
use middle::typeck::infer::to_str::InferStr;
use middle::typeck::infer::unify::{ValsAndBindings, Root};
use middle::typeck::infer::unify::{UnificationTable, Snapshot};
use middle::typeck::infer::error_reporting::ErrorReporting;
use std::cell::{Cell, RefCell};
use std::cell::{RefCell};
use std::collections::HashMap;
use std::rc::Rc;
use syntax::ast;
......@@ -55,17 +55,17 @@
pub mod region_inference;
pub mod resolve;
pub mod sub;
pub mod to_str;
pub mod unify;
pub mod coercion;
pub mod error_reporting;
pub mod test;
pub type Bound<T> = Option<T>;
#[deriving(Clone)]
#[deriving(PartialEq,Clone)]
pub struct Bounds<T> {
lb: Bound<T>,
ub: Bound<T>
pub lb: Bound<T>,
pub ub: Bound<T>
}
pub type cres<T> = Result<T,ty::type_err>; // "combine result"
......@@ -76,24 +76,23 @@ pub struct Bounds<T> {
pub struct InferCtxt<'a> {
pub tcx: &'a ty::ctxt,
// We instantiate ValsAndBindings with bounds<ty::t> because the
// We instantiate UnificationTable with bounds<ty::t> because the
// types that might instantiate a general type variable have an
// order, represented by its upper and lower bounds.
pub ty_var_bindings: RefCell<ValsAndBindings<ty::TyVid, Bounds<ty::t>>>,
pub ty_var_counter: Cell<uint>,
type_unification_table:
RefCell<UnificationTable<ty::TyVid, Bounds<ty::t>>>,
// Map from integral variable to the kind of integer it represents
pub int_var_bindings: RefCell<ValsAndBindings<ty::IntVid,
Option<IntVarValue>>>,
pub int_var_counter: Cell<uint>,
int_unification_table:
RefCell<UnificationTable<ty::IntVid, Option<IntVarValue>>>,
// Map from floating variable to the kind of float it represents
pub float_var_bindings: RefCell<ValsAndBindings<ty::FloatVid,
Option<ast::FloatTy>>>,
pub float_var_counter: Cell<uint>,
float_unification_table:
RefCell<UnificationTable<ty::FloatVid, Option<ast::FloatTy>>>,
// For region variables.
pub region_vars: RegionVarBindings<'a>,
region_vars:
RegionVarBindings<'a>,
}
/// Why did we require that the two types be related?
......@@ -261,16 +260,9 @@ pub fn fixup_err_to_str(f: fixup_err) -> String {
pub fn new_infer_ctxt<'a>(tcx: &'a ty::ctxt) -> InferCtxt<'a> {
InferCtxt {
tcx: tcx,
ty_var_bindings: RefCell::new(ValsAndBindings::new()),
ty_var_counter: Cell::new(0),
int_var_bindings: RefCell::new(ValsAndBindings::new()),
int_var_counter: Cell::new(0),
float_var_bindings: RefCell::new(ValsAndBindings::new()),
float_var_counter: Cell::new(0),
type_unification_table: RefCell::new(UnificationTable::new()),
int_unification_table: RefCell::new(UnificationTable::new()),
float_unification_table: RefCell::new(UnificationTable::new()),
region_vars: RegionVarBindings::new(tcx),
}
}
......@@ -280,20 +272,23 @@ pub fn common_supertype(cx: &InferCtxt,
a_is_expected: bool,
a: ty::t,
b: ty::t)
-> ty::t {
-> ty::t
{
/*!
* Computes the least upper-bound of `a` and `b`. If this is
* not possible, reports an error and returns ty::err.
*/
debug!("common_supertype({}, {})", a.inf_str(cx), b.inf_str(cx));
debug!("common_supertype({}, {})",
a.repr(cx.tcx), b.repr(cx.tcx));
let trace = TypeTrace {
origin: origin,
values: Types(expected_found(a_is_expected, a, b))
};
let result = cx.commit(|| cx.lub(a_is_expected, trace.clone()).tys(a, b));
let result =
cx.commit_if_ok(|| cx.lub(a_is_expected, trace.clone()).tys(a, b));
match result {
Ok(t) => t,
Err(ref err) => {
......@@ -309,9 +304,9 @@ pub fn mk_subty(cx: &InferCtxt,
a: ty::t,
b: ty::t)
-> ures {
debug!("mk_subty({} <: {})", a.inf_str(cx), b.inf_str(cx));
debug!("mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
indent(|| {
cx.commit(|| {
cx.commit_if_ok(|| {
let trace = TypeTrace {
origin: origin,
values: Types(expected_found(a_is_expected, a, b))
......@@ -322,15 +317,13 @@ pub fn mk_subty(cx: &InferCtxt,
}
pub fn can_mk_subty(cx: &InferCtxt, a: ty::t, b: ty::t) -> ures {
debug!("can_mk_subty({} <: {})", a.inf_str(cx), b.inf_str(cx));
indent(|| {
cx.probe(|| {
let trace = TypeTrace {
origin: Misc(codemap::DUMMY_SP),
values: Types(expected_found(true, a, b))
};
cx.sub(true, trace).tys(a, b)
})
debug!("can_mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
cx.probe(|| {
let trace = TypeTrace {
origin: Misc(codemap::DUMMY_SP),
values: Types(expected_found(true, a, b))
};
cx.sub(true, trace).tys(a, b)
}).to_ures()
}
......@@ -339,10 +332,10 @@ pub fn mk_subr(cx: &InferCtxt,
origin: SubregionOrigin,
a: ty::Region,
b: ty::Region) {
debug!("mk_subr({} <: {})", a.inf_str(cx), b.inf_str(cx));
cx.region_vars.start_snapshot();
debug!("mk_subr({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
let snapshot = cx.region_vars.start_snapshot();
cx.region_vars.make_subregion(origin, a, b);
cx.region_vars.commit();
cx.region_vars.commit(snapshot);
}
pub fn mk_eqty(cx: &InferCtxt,
......@@ -350,18 +343,17 @@ pub fn mk_eqty(cx: &InferCtxt,
origin: TypeOrigin,
a: ty::t,
b: ty::t)
-> ures {
debug!("mk_eqty({} <: {})", a.inf_str(cx), b.inf_str(cx));
indent(|| {
cx.commit(|| {
let trace = TypeTrace {
origin: origin,
values: Types(expected_found(a_is_expected, a, b))
};
let suber = cx.sub(a_is_expected, trace);
eq_tys(&suber, a, b)
})
}).to_ures()
-> ures
{
debug!("mk_eqty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
cx.commit_if_ok(|| {
let trace = TypeTrace {
origin: origin,
values: Types(expected_found(a_is_expected, a, b))
};
let suber = cx.sub(a_is_expected, trace);
eq_tys(&suber, a, b)
})
}
pub fn mk_sub_trait_refs(cx: &InferCtxt,
......@@ -372,9 +364,9 @@ pub fn mk_sub_trait_refs(cx: &InferCtxt,
-> ures
{
debug!("mk_sub_trait_refs({} <: {})",
a.inf_str(cx), b.inf_str(cx));
a.repr(cx.tcx), b.repr(cx.tcx));
indent(|| {
cx.commit(|| {
cx.commit_if_ok(|| {
let trace = TypeTrace {
origin: origin,
values: TraitRefs(expected_found(a_is_expected, a.clone(), b.clone()))
......@@ -401,9 +393,9 @@ pub fn mk_coercety(cx: &InferCtxt,
a: ty::t,
b: ty::t)
-> CoerceResult {
debug!("mk_coercety({} -> {})", a.inf_str(cx), b.inf_str(cx));
debug!("mk_coercety({} -> {})", a.repr(cx.tcx), b.repr(cx.tcx));
indent(|| {
cx.commit(|| {
cx.commit_if_ok(|| {
let trace = TypeTrace {
origin: origin,
values: Types(expected_found(a_is_expected, a, b))
......@@ -417,13 +409,15 @@ pub fn mk_coercety(cx: &InferCtxt,
pub fn resolve_type(cx: &InferCtxt,
a: ty::t,
modes: uint)
-> fres<ty::t> {
-> fres<ty::t>
{
let mut resolver = resolver(cx, modes);
resolver.resolve_type_chk(a)
cx.commit_unconditionally(|| resolver.resolve_type_chk(a))
}
pub fn resolve_region(cx: &InferCtxt, r: ty::Region, modes: uint)
-> fres<ty::Region> {
-> fres<ty::Region>
{
let mut resolver = resolver(cx, modes);
resolver.resolve_region_chk(r)
}
......@@ -473,19 +467,11 @@ pub fn uok() -> ures {
Ok(())
}
fn rollback_to<V:Clone + Vid,T:Clone>(vb: &mut ValsAndBindings<V, T>,
len: uint) {
while vb.bindings.len() != len {
let (vid, old_v) = vb.bindings.pop().unwrap();
vb.vals.insert(vid.to_uint(), old_v);
}
}
pub struct Snapshot {
ty_var_bindings_len: uint,
int_var_bindings_len: uint,
float_var_bindings_len: uint,
region_vars_snapshot: uint,
pub struct CombinedSnapshot {
type_snapshot: Snapshot<ty::TyVid>,
int_snapshot: Snapshot<ty::IntVid>,
float_snapshot: Snapshot<ty::FloatVid>,
region_vars_snapshot: RegionSnapshot,
}
impl<'a> InferCtxt<'a> {
......@@ -508,40 +494,67 @@ pub fn in_snapshot(&self) -> bool {
self.region_vars.in_snapshot()
}
pub fn start_snapshot(&self) -> Snapshot {
Snapshot {
ty_var_bindings_len: self.ty_var_bindings.borrow().bindings.len(),
int_var_bindings_len: self.int_var_bindings.borrow().bindings.len(),
float_var_bindings_len: self.float_var_bindings.borrow().bindings.len(),
fn start_snapshot(&self) -> CombinedSnapshot {
CombinedSnapshot {
type_snapshot: self.type_unification_table.borrow_mut().snapshot(),
int_snapshot: self.int_unification_table.borrow_mut().snapshot(),
float_snapshot: self.float_unification_table.borrow_mut().snapshot(),
region_vars_snapshot: self.region_vars.start_snapshot(),
}
}
pub fn rollback_to(&self, snapshot: &Snapshot) {
fn rollback_to(&self, snapshot: CombinedSnapshot) {
debug!("rollback!");
rollback_to(&mut *self.ty_var_bindings.borrow_mut(),
snapshot.ty_var_bindings_len);
rollback_to(&mut *self.int_var_bindings.borrow_mut(),
snapshot.int_var_bindings_len);
rollback_to(&mut *self.float_var_bindings.borrow_mut(),
snapshot.float_var_bindings_len);
self.region_vars.rollback_to(snapshot.region_vars_snapshot);
let CombinedSnapshot { type_snapshot,
int_snapshot,
float_snapshot,
region_vars_snapshot } = snapshot;
self.type_unification_table
.borrow_mut()
.rollback_to(self.tcx, type_snapshot);
self.int_unification_table
.borrow_mut()
.rollback_to(self.tcx, int_snapshot);
self.float_unification_table
.borrow_mut()
.rollback_to(self.tcx, float_snapshot);
self.region_vars
.rollback_to(region_vars_snapshot);
}
fn commit_from(&self, snapshot: CombinedSnapshot) {
debug!("commit_from!");
let CombinedSnapshot { type_snapshot,
int_snapshot,
float_snapshot,
region_vars_snapshot } = snapshot;
self.type_unification_table
.borrow_mut()
.commit(type_snapshot);
self.int_unification_table
.borrow_mut()
.commit(int_snapshot);
self.float_unification_table
.borrow_mut()
.commit(float_snapshot);
self.region_vars
.commit(region_vars_snapshot);
}
/// Execute `f` and commit the bindings
pub fn commit_unconditionally<R>(&self, f: || -> R) -> R {
debug!("commit()");
let snapshot = self.start_snapshot();
let r = f();
self.commit_from(snapshot);
r
}
/// Execute `f` and commit the bindings if successful
pub fn commit<T,E>(&self, f: || -> Result<T,E>) -> Result<T,E> {
assert!(!self.in_snapshot());
debug!("commit()");
indent(|| {
let r = self.try(|| f());
self.ty_var_bindings.borrow_mut().bindings.truncate(0);
self.int_var_bindings.borrow_mut().bindings.truncate(0);
self.region_vars.commit();
r
})
pub fn commit_if_ok<T,E>(&self, f: || -> Result<T,E>) -> Result<T,E> {
self.commit_unconditionally(|| self.try(|| f()))
}
/// Execute `f`, unroll bindings on failure
......@@ -549,11 +562,13 @@ pub fn try<T,E>(&self, f: || -> Result<T,E>) -> Result<T,E> {
debug!("try()");
let snapshot = self.start_snapshot();
let r = f();
debug!("try() -- r.is_ok() = {}", r.is_ok());
match r {
Ok(_) => { debug!("success"); }
Err(ref e) => {
debug!("error: {:?}", *e);
self.rollback_to(&snapshot)
Ok(_) => {
self.commit_from(snapshot);
}
Err(_) => {
self.rollback_to(snapshot);
}
}
r
......@@ -562,36 +577,18 @@ pub fn try<T,E>(&self, f: || -> Result<T,E>) -> Result<T,E> {
/// Execute `f` then unroll any bindings it creates
pub fn probe<T,E>(&self, f: || -> Result<T,E>) -> Result<T,E> {
debug!("probe()");
indent(|| {
let snapshot = self.start_snapshot();
let r = f();
self.rollback_to(&snapshot);
r
})
let snapshot = self.start_snapshot();
let r = f();
self.rollback_to(snapshot);
r
}
}
fn next_simple_var<V:Clone,T:Clone>(counter: &mut uint,
bindings: &mut ValsAndBindings<V,
Option<T>>)
-> uint {
let id = *counter;
*counter += 1;
bindings.vals.insert(id, Root(None, 0));
return id;
}
impl<'a> InferCtxt<'a> {
pub fn next_ty_var_id(&self) -> TyVid {
let id = self.ty_var_counter.get();
self.ty_var_counter.set(id + 1);
{
let mut ty_var_bindings = self.ty_var_bindings.borrow_mut();
let vals = &mut ty_var_bindings.vals;
vals.insert(id, Root(Bounds { lb: None, ub: None }, 0u));
}
debug!("created type variable {}", TyVid(id));
return TyVid(id);
self.type_unification_table
.borrow_mut()
.new_key(Bounds { lb: None, ub: None })
}
pub fn next_ty_var(&self) -> ty::t {
......@@ -603,21 +600,15 @@ pub fn next_ty_vars(&self, n: uint) -> Vec<ty::t> {
}
pub fn next_int_var_id(&self) -> IntVid {
let mut int_var_counter = self.int_var_counter.get();
let mut int_var_bindings = self.int_var_bindings.borrow_mut();
let result = IntVid(next_simple_var(&mut int_var_counter,
&mut *int_var_bindings));
self.int_var_counter.set(int_var_counter);
result
self.int_unification_table
.borrow_mut()
.new_key(None)
}
pub fn next_float_var_id(&self) -> FloatVid {
let mut float_var_counter = self.float_var_counter.get();
let mut float_var_bindings = self.float_var_bindings.borrow_mut();
let result = FloatVid(next_simple_var(&mut float_var_counter,
&mut *float_var_bindings));
self.float_var_counter.set(float_var_counter);
result
self.float_unification_table
.borrow_mut()
.new_key(None)
}
pub fn next_region_var(&self, origin: RegionVariableOrigin) -> ty::Region {
......
......@@ -12,7 +12,7 @@
use middle::ty;
use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid, Vid};
use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid};
use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound,
ReLateBound};
use middle::ty::{ReScope, ReVar, ReSkolemized, BrFresh};
......@@ -45,13 +45,17 @@ pub struct TwoRegions {
b: Region,
}
#[deriving(PartialEq)]
pub enum UndoLogEntry {
Snapshot,
OpenSnapshot,
CommitedSnapshot,
Mark,
AddVar(RegionVid),
AddConstraint(Constraint),
AddCombination(CombineMapType, TwoRegions)
}
#[deriving(PartialEq)]
pub enum CombineMapType {
Lub, Glb
}
......@@ -131,16 +135,27 @@ pub struct RegionVarBindings<'a> {
// The undo log records actions that might later be undone.
//
// Note: when the undo_log is empty, we are not actively
// snapshotting. When the `start_snapshot()` method is called, we
// push a Snapshot entry onto the list to indicate that we are now
// actively snapshotting. The reason for this is that otherwise
// we end up adding entries for things like the lower bound on
// a variable and so forth, which can never be rolled back.
undo_log: RefCell<Vec<UndoLogEntry> >,
// snapshotting. When the `start_snapshot()` method is called, we
// push an OpenSnapshot entry onto the list to indicate that we
// are now actively snapshotting. The reason for this is that
// otherwise we end up adding entries for things like the lower
// bound on a variable and so forth, which can never be rolled
// back.
undo_log: RefCell<Vec<UndoLogEntry>>,
// This contains the results of inference. It begins as an empty
// option and only acquires a value after inference is complete.
values: RefCell<Option<Vec<VarValue> >>,
values: RefCell<Option<Vec<VarValue>>>,
}
#[deriving(Show)]
pub struct RegionSnapshot {
length: uint
}
#[deriving(Show)]
pub struct RegionMark {
length: uint
}
impl<'a> RegionVarBindings<'a> {
......@@ -162,48 +177,62 @@ pub fn in_snapshot(&self) -> bool {
self.undo_log.borrow().len() > 0
}
pub fn start_snapshot(&self) -> uint {
debug!("RegionVarBindings: start_snapshot()");
if self.in_snapshot() {
self.undo_log.borrow().len()
} else {
self.undo_log.borrow_mut().push(Snapshot);
0
}
pub fn start_snapshot(&self) -> RegionSnapshot {
let length = self.undo_log.borrow().len();
debug!("RegionVarBindings: start_snapshot({})", length);
self.undo_log.borrow_mut().push(OpenSnapshot);
RegionSnapshot { length: length }
}
pub fn mark(&self) -> RegionMark {
let length = self.undo_log.borrow().len();
debug!("RegionVarBindings: mark({})", length);
self.undo_log.borrow_mut().push(Mark);
RegionMark { length: length }
}
pub fn commit(&self) {
pub fn commit(&self, snapshot: RegionSnapshot) {
debug!("RegionVarBindings: commit()");
assert!(self.undo_log.borrow().len() > snapshot.length);
assert!(*self.undo_log.borrow().get(snapshot.length) == OpenSnapshot);
let mut undo_log = self.undo_log.borrow_mut();
while undo_log.len() > 0 {
undo_log.pop().unwrap();
if snapshot.length == 0 {
undo_log.truncate(0);
} else {
*undo_log.get_mut(snapshot.length) = CommitedSnapshot;
}
}
pub fn rollback_to(&self, snapshot: uint) {
pub fn rollback_to(&self, snapshot: RegionSnapshot) {
debug!("RegionVarBindings: rollback_to({})", snapshot);
let mut undo_log = self.undo_log.borrow_mut();
while undo_log.len() > snapshot {
let undo_item = undo_log.pop().unwrap();
debug!("undo_item={:?}", undo_item);
match undo_item {
Snapshot => {}
AddVar(vid) => {
let mut var_origins = self.var_origins.borrow_mut();
assert_eq!(var_origins.len(), vid.to_uint() + 1);
var_origins.pop().unwrap();
}
AddConstraint(ref constraint) => {
self.constraints.borrow_mut().remove(constraint);
}
AddCombination(Glb, ref regions) => {
self.glbs.borrow_mut().remove(regions);
}
AddCombination(Lub, ref regions) => {
self.lubs.borrow_mut().remove(regions);
}
assert!(undo_log.len() > snapshot.length);
assert!(*undo_log.get(snapshot.length) == OpenSnapshot);
while undo_log.len() > snapshot.length + 1 {
match undo_log.pop().unwrap() {
OpenSnapshot => {
fail!("Failure to observe stack discipline");
}
Mark | CommitedSnapshot => { }
AddVar(vid) => {
let mut var_origins = self.var_origins.borrow_mut();
assert_eq!(var_origins.len(), vid.index + 1);
var_origins.pop().unwrap();
}
AddConstraint(ref constraint) => {
self.constraints.borrow_mut().remove(constraint);
}
AddCombination(Glb, ref regions) => {
self.glbs.borrow_mut().remove(regions);
}
AddCombination(Lub, ref regions) => {
self.lubs.borrow_mut().remove(regions);
}
}
}
let c = undo_log.pop().unwrap();
assert!(c == OpenSnapshot);
}
pub fn num_vars(&self) -> uint {
......@@ -213,7 +242,7 @@ pub fn num_vars(&self) -> uint {
pub fn new_region_var(&self, origin: RegionVariableOrigin) -> RegionVid {
let id = self.num_vars();
self.var_origins.borrow_mut().push(origin.clone());
let vid = RegionVid { id: id };
let vid = RegionVid { index: id };
if self.in_snapshot() {
self.undo_log.borrow_mut().push(AddVar(vid));
}
......@@ -368,15 +397,15 @@ pub fn resolve_var(&self, rid: RegionVid) -> ty::Region {
let v = match *self.values.borrow() {
None => {
self.tcx.sess.span_bug(
self.var_origins.borrow().get(rid.to_uint()).span(),
self.var_origins.borrow().get(rid.index).span(),
"attempt to resolve region variable before values have \
been computed!")
}
Some(ref values) => *values.get(rid.to_uint())
Some(ref values) => *values.get(rid.index)
};
debug!("RegionVarBindings: resolve_var({:?}={})={:?}",
rid, rid.to_uint(), v);
rid, rid.index, v);
match v {
Value(r) => r,
......@@ -427,9 +456,12 @@ pub fn combine_vars(&self,
ReInfer(ReVar(c))
}
pub fn vars_created_since_snapshot(&self, snapshot: uint)
-> Vec<RegionVid> {
self.undo_log.borrow().slice_from(snapshot).iter()
pub fn vars_created_since_mark(&self, mark: RegionMark)
-> Vec<RegionVid>
{
self.undo_log.borrow()
.slice_from(mark.length)
.iter()
.filter_map(|&elt| match elt {
AddVar(vid) => Some(vid),
_ => None
......@@ -437,20 +469,18 @@ pub fn vars_created_since_snapshot(&self, snapshot: uint)
.collect()
}
pub fn tainted(&self, snapshot: uint, r0: Region) -> Vec<Region> {
pub fn tainted(&self, mark: RegionMark, r0: Region) -> Vec<Region> {
/*!
* Computes all regions that have been related to `r0` in any
* way since the snapshot `snapshot` was taken---`r0` itself
* will be the first entry. This is used when checking whether
* way since the mark `mark` was made---`r0` itself will be
* the first entry. This is used when checking whether
* skolemized regions are being improperly related to other
* regions.
*/
debug!("tainted(snapshot={}, r0={:?})", snapshot, r0);
debug!("tainted(mark={}, r0={})", mark, r0.repr(self.tcx));
let _indenter = indenter();
let undo_len = self.undo_log.borrow().len();
// `result_set` acts as a worklist: we explore all outgoing
// edges and add any new regions we find to result_set. This
// is not a terribly efficient implementation.
......@@ -459,16 +489,14 @@ pub fn tainted(&self, snapshot: uint, r0: Region) -> Vec<Region> {
while result_index < result_set.len() {
// nb: can't use uint::range() here because result_set grows
let r = *result_set.get(result_index);
debug!("result_index={}, r={:?}", result_index, r);
let mut undo_index = snapshot;
while undo_index < undo_len {
// nb: can't use uint::range() here as we move result_set
let regs = match self.undo_log.borrow().get(undo_index) {
for undo_entry in
self.undo_log.borrow().slice_from(mark.length).iter()
{
let regs = match undo_entry {
&AddConstraint(ConstrainVarSubVar(ref a, ref b)) => {
Some((ReInfer(ReVar(*a)),
ReInfer(ReVar(*b))))
Some((ReInfer(ReVar(*a)), ReInfer(ReVar(*b))))
}
&AddConstraint(ConstrainRegSubVar(ref a, ref b)) => {
Some((*a, ReInfer(ReVar(*b))))
......@@ -479,7 +507,11 @@ pub fn tainted(&self, snapshot: uint, r0: Region) -> Vec<Region> {
&AddConstraint(ConstrainRegSubReg(a, b)) => {
Some((a, b))
}
_ => {
&AddCombination(..) |
&Mark |
&AddVar(..) |
&OpenSnapshot |
&CommitedSnapshot => {
None
}
};
......@@ -493,8 +525,6 @@ pub fn tainted(&self, snapshot: uint, r0: Region) -> Vec<Region> {
consider_adding_edge(result_set, r, r2, r1);
}
}
undo_index += 1;
}
result_index += 1;
......@@ -559,7 +589,7 @@ fn lub_concrete_regions(&self, a: Region, b: Region) -> Region {
(ReInfer(ReVar(v_id)), _) | (_, ReInfer(ReVar(v_id))) => {
self.tcx.sess.span_bug(
self.var_origins.borrow().get(v_id.to_uint()).span(),
self.var_origins.borrow().get(v_id.index).span(),
format!("lub_concrete_regions invoked with \
non-concrete regions: {:?}, {:?}",
a,
......@@ -665,7 +695,7 @@ fn glb_concrete_regions(&self,
(ReInfer(ReVar(v_id)), _) |
(_, ReInfer(ReVar(v_id))) => {
self.tcx.sess.span_bug(
self.var_origins.borrow().get(v_id.to_uint()).span(),
self.var_origins.borrow().get(v_id.index).span(),
format!("glb_concrete_regions invoked with \
non-concrete regions: {:?}, {:?}",
a,
......@@ -804,14 +834,14 @@ fn expansion(&self, var_data: &mut [VarData]) {
self.iterate_until_fixed_point("Expansion", |constraint| {
match *constraint {
ConstrainRegSubVar(a_region, b_vid) => {
let b_data = &mut var_data[b_vid.to_uint()];
let b_data = &mut var_data[b_vid.index];
self.expand_node(a_region, b_vid, b_data)
}
ConstrainVarSubVar(a_vid, b_vid) => {
match var_data[a_vid.to_uint()].value {
match var_data[a_vid.index].value {
NoValue | ErrorValue => false,
Value(a_region) => {
let b_node = &mut var_data[b_vid.to_uint()];
let b_node = &mut var_data[b_vid.index];
self.expand_node(a_region, b_vid, b_node)
}
}
......@@ -873,16 +903,16 @@ fn contraction(&self,
false
}
ConstrainVarSubVar(a_vid, b_vid) => {
match var_data[b_vid.to_uint()].value {
match var_data[b_vid.index].value {
NoValue | ErrorValue => false,
Value(b_region) => {
let a_data = &mut var_data[a_vid.to_uint()];
let a_data = &mut var_data[a_vid.index];
self.contract_node(a_vid, a_data, b_region)
}
}
}
ConstrainVarSubReg(a_vid, b_region) => {
let a_data = &mut var_data[a_vid.to_uint()];
let a_data = &mut var_data[a_vid.index];
self.contract_node(a_vid, a_data, b_region)
}
ConstrainRegSubReg(..) => {
......@@ -1054,7 +1084,7 @@ fn extract_values_and_collect_conflicts(
}
let graph = opt_graph.get_ref();
let node_vid = RegionVid { id: idx };
let node_vid = RegionVid { index: idx };
match var_data[idx].classification {
Expanding => {
self.collect_error_for_expanding_node(
......@@ -1091,17 +1121,17 @@ fn construct_graph(&self) -> RegionGraph {
for (constraint, _) in constraints.iter() {
match *constraint {
ConstrainVarSubVar(a_id, b_id) => {
graph.add_edge(NodeIndex(a_id.to_uint()),
NodeIndex(b_id.to_uint()),
graph.add_edge(NodeIndex(a_id.index),
NodeIndex(b_id.index),
*constraint);
}
ConstrainRegSubVar(_, b_id) => {
graph.add_edge(dummy_idx,
NodeIndex(b_id.to_uint()),
NodeIndex(b_id.index),
*constraint);
}
ConstrainVarSubReg(a_id, _) => {
graph.add_edge(NodeIndex(a_id.to_uint()),
graph.add_edge(NodeIndex(a_id.index),
dummy_idx,
*constraint);
}
......@@ -1157,7 +1187,7 @@ fn free_regions_first(a: &RegionAndOrigin,
if !self.is_subregion_of(lower_bound.region,
upper_bound.region) {
errors.push(SubSupConflict(
self.var_origins.borrow().get(node_idx.to_uint()).clone(),
self.var_origins.borrow().get(node_idx.index).clone(),
lower_bound.origin.clone(),
lower_bound.region,
upper_bound.origin.clone(),
......@@ -1168,7 +1198,7 @@ fn free_regions_first(a: &RegionAndOrigin,
}
self.tcx.sess.span_bug(
self.var_origins.borrow().get(node_idx.to_uint()).span(),
self.var_origins.borrow().get(node_idx.index).span(),
format!("collect_error_for_expanding_node() could not find error \
for var {:?}, lower_bounds={}, upper_bounds={}",
node_idx,
......@@ -1207,7 +1237,7 @@ fn collect_error_for_contracting_node(
Ok(_) => {}
Err(_) => {
errors.push(SupSupConflict(
self.var_origins.borrow().get(node_idx.to_uint()).clone(),
self.var_origins.borrow().get(node_idx.index).clone(),
upper_bound_1.origin.clone(),
upper_bound_1.region,
upper_bound_2.origin.clone(),
......@@ -1219,7 +1249,7 @@ fn collect_error_for_contracting_node(
}
self.tcx.sess.span_bug(
self.var_origins.borrow().get(node_idx.to_uint()).span(),
self.var_origins.borrow().get(node_idx.index).span(),
format!("collect_error_for_contracting_node() could not find error \
for var {:?}, upper_bounds={}",
node_idx,
......@@ -1256,12 +1286,12 @@ struct WalkState {
while !state.stack.is_empty() {
let node_idx = state.stack.pop().unwrap();
let classification = var_data[node_idx.to_uint()].classification;
let classification = var_data[node_idx.index].classification;
// check whether we've visited this node on some previous walk
if dup_vec[node_idx.to_uint()] == uint::MAX {
dup_vec[node_idx.to_uint()] = orig_node_idx.to_uint();
} else if dup_vec[node_idx.to_uint()] != orig_node_idx.to_uint() {
if dup_vec[node_idx.index] == uint::MAX {
dup_vec[node_idx.index] = orig_node_idx.index;
} else if dup_vec[node_idx.index] != orig_node_idx.index {
state.dup_found = true;
}
......@@ -1289,7 +1319,7 @@ fn process_edges(this: &RegionVarBindings,
dir: Direction) {
debug!("process_edges(source_vid={:?}, dir={:?})", source_vid, dir);
let source_node_index = NodeIndex(source_vid.to_uint());
let source_node_index = NodeIndex(source_vid.index);
graph.each_adjacent_edge(source_node_index, dir, |_, edge| {
match edge.data {
ConstrainVarSubVar(from_vid, to_vid) => {
......
......@@ -53,10 +53,9 @@
use middle::ty_fold;
use middle::typeck::infer::{Bounds, cyclic_ty, fixup_err, fres, InferCtxt};
use middle::typeck::infer::unresolved_ty;
use middle::typeck::infer::to_str::InferStr;
use middle::typeck::infer::unify::{Root, UnifyInferCtxtMethods};
use util::common::{indent, indenter};
use util::ppaux::ty_to_str;
use middle::typeck::infer::unify::Root;
use util::common::{indent};
use util::ppaux::{ty_to_str, Repr};
use syntax::ast;
......@@ -150,8 +149,7 @@ pub fn resolve_region_chk(&mut self, orig: ty::Region)
}
pub fn resolve_type(&mut self, typ: ty::t) -> ty::t {
debug!("resolve_type({})", typ.inf_str(self.infcx));
let _i = indenter();
debug!("resolve_type({})", typ.repr(self.infcx.tcx));
if !ty::type_needs_infer(typ) {
return typ;
......@@ -188,7 +186,7 @@ pub fn resolve_type(&mut self, typ: ty::t) -> ty::t {
}
pub fn resolve_region(&mut self, orig: ty::Region) -> ty::Region {
debug!("Resolve_region({})", orig.inf_str(self.infcx));
debug!("Resolve_region({})", orig.repr(self.infcx.tcx));
match orig {
ty::ReInfer(ty::ReVar(rid)) => self.resolve_region_var(rid),
_ => orig
......@@ -216,14 +214,15 @@ pub fn resolve_ty_var(&mut self, vid: TyVid) -> ty::t {
// tend to carry more restrictions or higher
// perf. penalties, so it pays to know more.
let nde = self.infcx.get(vid);
let bounds = nde.possible_types;
let t1 = match bounds {
Bounds { ub:_, lb:Some(t) } if !type_is_bot(t)
=> self.resolve_type(t),
Bounds { ub:Some(t), lb:_ } => self.resolve_type(t),
Bounds { ub:_, lb:Some(t) } => self.resolve_type(t),
let node =
self.infcx.type_unification_table.borrow_mut().get(tcx, vid);
let t1 = match node.value {
Bounds { ub:_, lb:Some(t) } if !type_is_bot(t) => {
self.resolve_type(t)
}
Bounds { ub:Some(t), lb:_ } | Bounds { ub:_, lb:Some(t) } => {
self.resolve_type(t)
}
Bounds { ub:None, lb:None } => {
if self.should(force_tvar) {
self.err = Some(unresolved_ty(vid));
......@@ -241,15 +240,18 @@ pub fn resolve_int_var(&mut self, vid: IntVid) -> ty::t {
return ty::mk_int_var(self.infcx.tcx, vid);
}
let node = self.infcx.get(vid);
match node.possible_types {
let tcx = self.infcx.tcx;
let table = &self.infcx.int_unification_table;
let node = table.borrow_mut().get(tcx, vid);
match node.value {
Some(IntType(t)) => ty::mk_mach_int(t),
Some(UintType(t)) => ty::mk_mach_uint(t),
None => {
if self.should(force_ivar) {
// As a last resort, default to int.
let ty = ty::mk_int();
self.infcx.set(vid, Root(Some(IntType(ast::TyI)), node.rank));
table.borrow_mut().set(
tcx, node.key, Root(Some(IntType(ast::TyI)), node.rank));
ty
} else {
ty::mk_int_var(self.infcx.tcx, vid)
......@@ -263,14 +265,17 @@ pub fn resolve_float_var(&mut self, vid: FloatVid) -> ty::t {
return ty::mk_float_var(self.infcx.tcx, vid);
}
let node = self.infcx.get(vid);
match node.possible_types {
let tcx = self.infcx.tcx;
let table = &self.infcx.float_unification_table;
let node = table.borrow_mut().get(tcx, vid);
match node.value {
Some(t) => ty::mk_mach_float(t),
None => {
if self.should(force_fvar) {
// As a last resort, default to f64.
let ty = ty::mk_f64();
self.infcx.set(vid, Root(Some(ast::TyF64), node.rank));
table.borrow_mut().set(
tcx, node.key, Root(Some(ast::TyF64), node.rank));
ty
} else {
ty::mk_float_var(self.infcx.tcx, vid)
......
......@@ -20,10 +20,9 @@
use middle::typeck::infer::lattice::CombineFieldsLatticeMethods;
use middle::typeck::infer::lub::Lub;
use middle::typeck::infer::then;
use middle::typeck::infer::to_str::InferStr;
use middle::typeck::infer::{TypeTrace, Subtype};
use util::common::{indenter};
use util::ppaux::bound_region_to_str;
use util::ppaux::{bound_region_to_str, Repr};
use syntax::ast::{Onceness, FnStyle, MutImmutable, MutMutable};
......@@ -63,14 +62,16 @@ fn contraregions(&self, a: ty::Region, b: ty::Region)
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region> {
debug!("{}.regions({}, {})",
self.tag(),
a.inf_str(self.get_ref().infcx),
b.inf_str(self.get_ref().infcx));
a.repr(self.get_ref().infcx.tcx),
b.repr(self.get_ref().infcx.tcx));
self.get_ref().infcx.region_vars.make_subregion(Subtype(self.trace()), a, b);
Ok(a)
}
fn mts(&self, a: &ty::mt, b: &ty::mt) -> cres<ty::mt> {
debug!("mts({} <: {})", a.inf_str(self.get_ref().infcx), b.inf_str(self.get_ref().infcx));
debug!("mts({} <: {})",
a.repr(self.get_ref().infcx.tcx),
b.repr(self.get_ref().infcx.tcx));
if a.mutbl != b.mutbl {
return Err(ty::terr_mutability);
......@@ -116,7 +117,7 @@ fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres<BuiltinBounds> {
fn tys(&self, a: ty::t, b: ty::t) -> cres<ty::t> {
debug!("{}.tys({}, {})", self.tag(),
a.inf_str(self.get_ref().infcx), b.inf_str(self.get_ref().infcx));
a.repr(self.get_ref().infcx.tcx), b.repr(self.get_ref().infcx.tcx));
if a == b { return Ok(a); }
let _indenter = indenter();
match (&ty::get(a).sty, &ty::get(b).sty) {
......@@ -149,7 +150,7 @@ fn tys(&self, a: ty::t, b: ty::t) -> cres<ty::t> {
fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
debug!("fn_sigs(a={}, b={})",
a.inf_str(self.get_ref().infcx), b.inf_str(self.get_ref().infcx));
a.repr(self.get_ref().infcx.tcx), b.repr(self.get_ref().infcx.tcx));
let _indenter = indenter();
// Rather than checking the subtype relationship between `a` and `b`
......@@ -159,11 +160,9 @@ fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
// Note: this is a subtle algorithm. For a full explanation,
// please see the large comment in `region_inference.rs`.
// Take a snapshot. We'll never roll this back, but in later
// phases we do want to be able to examine "all bindings that
// were created as part of this type comparison", and making a
// snapshot is a convenient way to do that.
let snapshot = self.get_ref().infcx.region_vars.start_snapshot();
// Make a mark so we can examine "all bindings that were
// created as part of this type comparison".
let mark = self.get_ref().infcx.region_vars.mark();
// First, we instantiate each bound region in the subtype with a fresh
// region variable.
......@@ -183,8 +182,8 @@ fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
})
};
debug!("a_sig={}", a_sig.inf_str(self.get_ref().infcx));
debug!("b_sig={}", b_sig.inf_str(self.get_ref().infcx));
debug!("a_sig={}", a_sig.repr(self.get_ref().infcx.tcx));
debug!("b_sig={}", b_sig.repr(self.get_ref().infcx.tcx));
// Compare types now that bound regions have been replaced.
let sig = if_ok!(super_fn_sigs(self, &a_sig, &b_sig));
......@@ -192,9 +191,9 @@ fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
// Presuming type comparison succeeds, we need to check
// that the skolemized regions do not "leak".
let new_vars =
self.get_ref().infcx.region_vars.vars_created_since_snapshot(snapshot);
self.get_ref().infcx.region_vars.vars_created_since_mark(mark);
for (&skol_br, &skol) in skol_map.iter() {
let tainted = self.get_ref().infcx.region_vars.tainted(snapshot, skol);
let tainted = self.get_ref().infcx.region_vars.tainted(mark, skol);
for tainted_region in tainted.iter() {
// Each skolemized should only be relatable to itself
// or new variables:
......@@ -209,9 +208,11 @@ fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
// A is not as polymorphic as B:
if self.a_is_expected() {
debug!("Not as polymorphic!");
return Err(ty::terr_regions_insufficiently_polymorphic(
skol_br, *tainted_region));
} else {
debug!("Overly polymorphic!");
return Err(ty::terr_regions_overly_polymorphic(
skol_br, *tainted_region));
}
......
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use middle::ty::{FnSig, Vid};
use middle::ty::IntVarValue;
use middle::ty;
use middle::typeck::infer::{Bound, Bounds};
use middle::typeck::infer::InferCtxt;
use middle::typeck::infer::unify::{Redirect, Root, VarValue};
use util::ppaux::{mt_to_str, ty_to_str, trait_ref_to_str};
use syntax::ast;
pub trait InferStr {
fn inf_str(&self, cx: &InferCtxt) -> String;
}
impl InferStr for ty::t {
fn inf_str(&self, cx: &InferCtxt) -> String {
ty_to_str(cx.tcx, *self)
}
}
impl InferStr for FnSig {
fn inf_str(&self, cx: &InferCtxt) -> String {
format!("({}) -> {}",
self.inputs.iter()
.map(|a| a.inf_str(cx))
.collect::<Vec<String>>().connect(", "),
self.output.inf_str(cx))
}
}
impl InferStr for ty::mt {
fn inf_str(&self, cx: &InferCtxt) -> String {
mt_to_str(cx.tcx, self)
}
}
impl InferStr for ty::Region {
fn inf_str(&self, _cx: &InferCtxt) -> String {
format!("{:?}", *self)
}
}
impl<V:InferStr> InferStr for Bound<V> {
fn inf_str(&self, cx: &InferCtxt) -> String {
match *self {
Some(ref v) => v.inf_str(cx),
None => "none".to_string()
}
}
}
impl<T:InferStr> InferStr for Bounds<T> {
fn inf_str(&self, cx: &InferCtxt) -> String {
format!("{{{} <: {}}}", self.lb.inf_str(cx), self.ub.inf_str(cx))
}
}
impl<V:Vid + ToStr,T:InferStr> InferStr for VarValue<V, T> {
fn inf_str(&self, cx: &InferCtxt) -> String {
match *self {
Redirect(ref vid) => format!("Redirect({})", vid.to_str()),
Root(ref pt, rk) => {
format!("Root({}, {})", pt.inf_str(cx), rk)
}
}
}
}
impl InferStr for IntVarValue {
fn inf_str(&self, _cx: &InferCtxt) -> String {
self.to_str()
}
}
impl InferStr for ast::FloatTy {
fn inf_str(&self, _cx: &InferCtxt) -> String {
self.to_str()
}
}
impl InferStr for ty::TraitRef {
fn inf_str(&self, cx: &InferCtxt) -> String {
trait_ref_to_str(cx.tcx, self)
}
}
......@@ -24,6 +24,10 @@
use middle::ty::{ty_uniq, ty_trait, ty_int, ty_uint, ty_infer};
use middle::ty;
use middle::typeck;
use middle::typeck::infer;
use middle::typeck::infer::unify;
use VV = middle::typeck::infer::unify::VarValue;
use middle::typeck::infer::region_inference;
use std::rc::Rc;
use std::gc::Gc;
......@@ -574,6 +578,12 @@ fn repr(&self, tcx: &ctxt) -> String {
}
}
impl Repr for ty::mt {
fn repr(&self, tcx: &ctxt) -> String {
mt_to_str(tcx, self)
}
}
impl Repr for subst::Substs {
fn repr(&self, tcx: &ctxt) -> String {
format!("Substs[types={}, regions={}]",
......@@ -707,7 +717,7 @@ fn repr(&self, tcx: &ctxt) -> String {
}
ty::ReInfer(ReVar(ref vid)) => {
format!("ReInfer({})", vid.id)
format!("ReInfer({})", vid.index)
}
ty::ReInfer(ReSkolemized(id, ref bound_region)) => {
......@@ -878,13 +888,6 @@ fn repr(&self, tcx: &ctxt) -> String {
}
}
impl Repr for ty::RegionVid {
fn repr(&self, _tcx: &ctxt) -> String {
format!("{:?}", *self)
}
}
impl Repr for ty::TraitStore {
fn repr(&self, tcx: &ctxt) -> String {
trait_store_to_str(tcx, *self)
......@@ -998,3 +1001,83 @@ fn repr(&self, tcx: &ctxt) -> String {
self.region.repr(tcx))
}
}
impl Repr for ty::IntVid {
fn repr(&self, _tcx: &ctxt) -> String {
format!("{}", self)
}
}
impl Repr for ty::FloatVid {
fn repr(&self, _tcx: &ctxt) -> String {
format!("{}", self)
}
}
impl Repr for ty::RegionVid {
fn repr(&self, _tcx: &ctxt) -> String {
format!("{}", self)
}
}
impl Repr for ty::TyVid {
fn repr(&self, _tcx: &ctxt) -> String {
format!("{}", self)
}
}
impl Repr for ty::IntVarValue {
fn repr(&self, _tcx: &ctxt) -> String {
format!("{:?}", *self)
}
}
impl Repr for ast::IntTy {
fn repr(&self, _tcx: &ctxt) -> String {
format!("{:?}", *self)
}
}
impl Repr for ast::UintTy {
fn repr(&self, _tcx: &ctxt) -> String {
format!("{:?}", *self)
}
}
impl Repr for ast::FloatTy {
fn repr(&self, _tcx: &ctxt) -> String {
format!("{:?}", *self)
}
}
impl<T:Repr> Repr for infer::Bounds<T> {
fn repr(&self, tcx: &ctxt) -> String {
format!("({} <= {})",
self.lb.repr(tcx),
self.ub.repr(tcx))
}
}
impl<K:Repr,V:Repr> Repr for VV<K,V> {
fn repr(&self, tcx: &ctxt) -> String {
match *self {
unify::Redirect(ref k) =>
format!("Redirect({})", k.repr(tcx)),
unify::Root(ref v, r) =>
format!("Root({}, {})", v.repr(tcx), r)
}
}
}
impl Repr for region_inference::VarValue {
fn repr(&self, tcx: &ctxt) -> String {
match *self {
infer::region_inference::NoValue =>
format!("NoValue"),
infer::region_inference::Value(r) =>
format!("Value({})", r.repr(tcx)),
infer::region_inference::ErrorValue =>
format!("ErrorValue"),
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册