summary refs log tree commit diff
path: root/src/librustc/middle/infer
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustc/middle/infer')
-rw-r--r--src/librustc/middle/infer/bivariate.rs145
-rw-r--r--src/librustc/middle/infer/combine.rs146
-rw-r--r--src/librustc/middle/infer/equate.rs27
-rw-r--r--src/librustc/middle/infer/error_reporting.rs32
-rw-r--r--src/librustc/middle/infer/glb.rs47
-rw-r--r--src/librustc/middle/infer/higher_ranked/mod.rs4
-rw-r--r--src/librustc/middle/infer/lub.rs47
-rw-r--r--src/librustc/middle/infer/mod.rs6
-rw-r--r--src/librustc/middle/infer/region_inference/mod.rs2
-rw-r--r--src/librustc/middle/infer/sub.rs48
-rw-r--r--src/librustc/middle/infer/type_variable.rs10
-rw-r--r--src/librustc/middle/infer/unify.rs9
12 files changed, 349 insertions, 174 deletions
diff --git a/src/librustc/middle/infer/bivariate.rs b/src/librustc/middle/infer/bivariate.rs
new file mode 100644
index 00000000000..93c80fb754f
--- /dev/null
+++ b/src/librustc/middle/infer/bivariate.rs
@@ -0,0 +1,145 @@
+// Copyright 2014 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.
+
+//! Applies the "bivariance relationship" to two types and/or regions.
+//! If (A,B) are bivariant then either A <: B or B <: A. It occurs
+//! when type/lifetime parameters are unconstrained. Usually this is
+//! an error, but we permit it in the specific case where a type
+//! parameter is constrained in a where-clause via an associated type.
+//!
+//! There are several ways one could implement bivariance. You could
+//! just do nothing at all, for example, or you could fully verify
+//! that one of the two subtyping relationships hold. We choose to
+//! thread a middle line: we relate types up to regions, but ignore
+//! all region relationships.
+//!
+//! At one point, handling bivariance in this fashion was necessary
+//! for inference, but I'm actually not sure if that is true anymore.
+//! In particular, it might be enough to say (A,B) are bivariant for
+//! all (A,B).
+
+use middle::ty::{BuiltinBounds};
+use middle::ty::{self, Ty};
+use middle::ty::TyVar;
+use middle::infer::combine::*;
+use middle::infer::{cres};
+use middle::infer::type_variable::{BiTo};
+use util::ppaux::{Repr};
+
+use syntax::ast::{Unsafety};
+
+pub struct Bivariate<'f, 'tcx: 'f> {
+    fields: CombineFields<'f, 'tcx>
+}
+
+#[allow(non_snake_case)]
+pub fn Bivariate<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Bivariate<'f, 'tcx> {
+    Bivariate { fields: cf }
+}
+
+impl<'f, 'tcx> Combine<'tcx> for Bivariate<'f, 'tcx> {
+    fn tag(&self) -> String { "Bivariate".to_string() }
+    fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields }
+
+    fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
+                         -> cres<'tcx, Ty<'tcx>>
+    {
+        match v {
+            ty::Invariant => self.equate().tys(a, b),
+            ty::Covariant => self.tys(a, b),
+            ty::Contravariant => self.tys(a, b),
+            ty::Bivariant => self.tys(a, b),
+        }
+    }
+
+    fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region)
+                             -> cres<'tcx, ty::Region>
+    {
+        match v {
+            ty::Invariant => self.equate().regions(a, b),
+            ty::Covariant => self.regions(a, b),
+            ty::Contravariant => self.regions(a, b),
+            ty::Bivariant => self.regions(a, b),
+        }
+    }
+
+    fn regions(&self, a: ty::Region, _: ty::Region) -> cres<'tcx, ty::Region> {
+        Ok(a)
+    }
+
+    fn mts(&self, a: &ty::mt<'tcx>, b: &ty::mt<'tcx>) -> cres<'tcx, ty::mt<'tcx>> {
+        debug!("mts({} <: {})",
+               a.repr(self.fields.infcx.tcx),
+               b.repr(self.fields.infcx.tcx));
+
+        if a.mutbl != b.mutbl { return Err(ty::terr_mutability); }
+        let t = try!(self.tys(a.ty, b.ty));
+        Ok(ty::mt { mutbl: a.mutbl, ty: t })
+    }
+
+    fn unsafeties(&self, a: Unsafety, b: Unsafety) -> cres<'tcx, Unsafety> {
+        if a != b {
+            Err(ty::terr_unsafety_mismatch(expected_found(self, a, b)))
+        } else {
+            Ok(a)
+        }
+    }
+
+    fn builtin_bounds(&self,
+                      a: BuiltinBounds,
+                      b: BuiltinBounds)
+                      -> cres<'tcx, BuiltinBounds>
+    {
+        if a != b {
+            Err(ty::terr_builtin_bounds(expected_found(self, a, b)))
+        } else {
+            Ok(a)
+        }
+    }
+
+    fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
+        debug!("{}.tys({}, {})", self.tag(),
+               a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx));
+        if a == b { return Ok(a); }
+
+        let infcx = self.fields.infcx;
+        let a = infcx.type_variables.borrow().replace_if_possible(a);
+        let b = infcx.type_variables.borrow().replace_if_possible(b);
+        match (&a.sty, &b.sty) {
+            (&ty::ty_infer(TyVar(a_id)), &ty::ty_infer(TyVar(b_id))) => {
+                infcx.type_variables.borrow_mut().relate_vars(a_id, BiTo, b_id);
+                Ok(a)
+            }
+
+            (&ty::ty_infer(TyVar(a_id)), _) => {
+                try!(self.fields.instantiate(b, BiTo, a_id));
+                Ok(a)
+            }
+
+            (_, &ty::ty_infer(TyVar(b_id))) => {
+                try!(self.fields.instantiate(a, BiTo, b_id));
+                Ok(a)
+            }
+
+            _ => {
+                super_tys(self, a, b)
+            }
+        }
+    }
+
+    fn binders<T>(&self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> cres<'tcx, ty::Binder<T>>
+        where T : Combineable<'tcx>
+    {
+        let a1 = ty::erase_late_bound_regions(self.tcx(), a);
+        let b1 = ty::erase_late_bound_regions(self.tcx(), b);
+        let c = try!(Combineable::combine(self, &a1, &b1));
+        Ok(ty::Binder(c))
+    }
+}
diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs
index daa820f43b5..0eeafb767d8 100644
--- a/src/librustc/middle/infer/combine.rs
+++ b/src/librustc/middle/infer/combine.rs
@@ -32,6 +32,7 @@
 // is also useful to track which value is the "expected" value in
 // terms of error reporting.
 
+use super::bivariate::Bivariate;
 use super::equate::Equate;
 use super::glb::Glb;
 use super::lub::Lub;
@@ -39,7 +40,7 @@ use super::sub::Sub;
 use super::unify::InferCtxtMethodsForSimplyUnifiableTypes;
 use super::{InferCtxt, cres};
 use super::{MiscVariable, TypeTrace};
-use super::type_variable::{RelationDir, EqTo, SubtypeOf, SupertypeOf};
+use super::type_variable::{RelationDir, BiTo, EqTo, SubtypeOf, SupertypeOf};
 
 use middle::subst;
 use middle::subst::{ErasedRegions, NonerasedRegions, Substs};
@@ -48,7 +49,7 @@ use middle::ty::{IntType, UintType};
 use middle::ty::{BuiltinBounds};
 use middle::ty::{self, Ty};
 use middle::ty_fold;
-use middle::ty_fold::{TypeFoldable};
+use middle::ty_fold::{TypeFolder, TypeFoldable};
 use util::ppaux::Repr;
 
 use std::rc::Rc;
@@ -58,41 +59,32 @@ use syntax::abi;
 use syntax::codemap::Span;
 
 pub trait Combine<'tcx> : Sized {
-    fn infcx<'a>(&'a self) -> &'a InferCtxt<'a, 'tcx>;
     fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { self.infcx().tcx }
     fn tag(&self) -> String;
-    fn a_is_expected(&self) -> bool;
-    fn trace(&self) -> TypeTrace<'tcx>;
 
-    fn equate<'a>(&'a self) -> Equate<'a, 'tcx>;
-    fn sub<'a>(&'a self) -> Sub<'a, 'tcx>;
-    fn lub<'a>(&'a self) -> Lub<'a, 'tcx>;
-    fn glb<'a>(&'a self) -> Glb<'a, 'tcx>;
+    fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx>;
+
+    fn infcx<'a>(&'a self) -> &'a InferCtxt<'a, 'tcx> { self.fields().infcx }
+    fn a_is_expected(&self) -> bool { self.fields().a_is_expected }
+    fn trace(&self) -> TypeTrace<'tcx> { self.fields().trace.clone() }
+    fn equate<'a>(&'a self) -> Equate<'a, 'tcx> { self.fields().equate() }
+    fn bivariate<'a>(&'a self) -> Bivariate<'a, 'tcx> { self.fields().bivariate() }
+
+    fn sub<'a>(&'a self) -> Sub<'a, 'tcx> { self.fields().sub() }
+    fn lub<'a>(&'a self) -> Lub<'a, 'tcx> { Lub(self.fields().clone()) }
+    fn glb<'a>(&'a self) -> Glb<'a, 'tcx> { Glb(self.fields().clone()) }
 
     fn mts(&self, a: &ty::mt<'tcx>, b: &ty::mt<'tcx>) -> cres<'tcx, ty::mt<'tcx>>;
-    fn contratys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>>;
+
+    fn tys_with_variance(&self, variance: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
+                         -> cres<'tcx, Ty<'tcx>>;
+
     fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>>;
 
-    fn tps(&self,
-           _: subst::ParamSpace,
-           as_: &[Ty<'tcx>],
-           bs: &[Ty<'tcx>])
-           -> cres<'tcx, Vec<Ty<'tcx>>> {
-        // FIXME -- In general, we treat variance a bit wrong
-        // here. For historical reasons, we treat tps and Self
-        // as invariant. This is overly conservative.
-
-        if as_.len() != bs.len() {
-            return Err(ty::terr_ty_param_size(expected_found(self,
-                                                             as_.len(),
-                                                             bs.len())));
-        }
+    fn regions_with_variance(&self, variance: ty::Variance, a: ty::Region, b: ty::Region)
+                             -> cres<'tcx, ty::Region>;
 
-        try!(as_.iter().zip(bs.iter())
-                .map(|(a, b)| self.equate().tys(*a, *b))
-                .collect::<cres<Vec<Ty>>>());
-        Ok(as_.to_vec())
-    }
+    fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region>;
 
     fn substs(&self,
               item_def_id: ast::DefId,
@@ -100,6 +92,11 @@ pub trait Combine<'tcx> : Sized {
               b_subst: &subst::Substs<'tcx>)
               -> cres<'tcx, subst::Substs<'tcx>>
     {
+        debug!("substs: item_def_id={} a_subst={} b_subst={}",
+               item_def_id.repr(self.infcx().tcx),
+               a_subst.repr(self.infcx().tcx),
+               b_subst.repr(self.infcx().tcx));
+
         let variances = if self.infcx().tcx.variance_computed.get() {
             Some(ty::item_variances(self.infcx().tcx, item_def_id))
         } else {
@@ -119,7 +116,8 @@ pub trait Combine<'tcx> : Sized {
         for &space in &subst::ParamSpace::all() {
             let a_tps = a_subst.types.get_slice(space);
             let b_tps = b_subst.types.get_slice(space);
-            let tps = try!(self.tps(space, a_tps, b_tps));
+            let t_variances = variances.map(|v| v.types.get_slice(space));
+            let tps = try!(relate_type_params(self, t_variances, a_tps, b_tps));
             substs.types.replace(space, tps);
         }
 
@@ -132,20 +130,7 @@ pub trait Combine<'tcx> : Sized {
                 for &space in &subst::ParamSpace::all() {
                     let a_regions = a.get_slice(space);
                     let b_regions = b.get_slice(space);
-
-                    let mut invariance = Vec::new();
-                    let r_variances = match variances {
-                        Some(variances) => {
-                            variances.regions.get_slice(space)
-                        }
-                        None => {
-                            for _ in a_regions {
-                                invariance.push(ty::Invariant);
-                            }
-                            &invariance[]
-                        }
-                    };
-
+                    let r_variances = variances.map(|v| v.regions.get_slice(space));
                     let regions = try!(relate_region_params(self,
                                                             r_variances,
                                                             a_regions,
@@ -157,13 +142,34 @@ pub trait Combine<'tcx> : Sized {
 
         return Ok(substs);
 
+        fn relate_type_params<'tcx, C: Combine<'tcx>>(this: &C,
+                                                      variances: Option<&[ty::Variance]>,
+                                                      a_tys: &[Ty<'tcx>],
+                                                      b_tys: &[Ty<'tcx>])
+                                                      -> cres<'tcx, Vec<Ty<'tcx>>>
+        {
+            if a_tys.len() != b_tys.len() {
+                return Err(ty::terr_ty_param_size(expected_found(this,
+                                                                 a_tys.len(),
+                                                                 b_tys.len())));
+            }
+
+            range(0, a_tys.len()).map(|i| {
+                let a_ty = a_tys[i];
+                let b_ty = b_tys[i];
+                let v = variances.map_or(ty::Invariant, |v| v[i]);
+                this.tys_with_variance(v, a_ty, b_ty)
+            }).collect()
+        }
+
         fn relate_region_params<'tcx, C: Combine<'tcx>>(this: &C,
-                                                        variances: &[ty::Variance],
+                                                        variances: Option<&[ty::Variance]>,
                                                         a_rs: &[ty::Region],
                                                         b_rs: &[ty::Region])
-                                                        -> cres<'tcx, Vec<ty::Region>> {
+                                                        -> cres<'tcx, Vec<ty::Region>>
+        {
             let tcx = this.infcx().tcx;
-            let num_region_params = variances.len();
+            let num_region_params = a_rs.len();
 
             debug!("relate_region_params(\
                    a_rs={}, \
@@ -173,22 +179,18 @@ pub trait Combine<'tcx> : Sized {
                    b_rs.repr(tcx),
                    variances.repr(tcx));
 
-            assert_eq!(num_region_params, a_rs.len());
+            assert_eq!(num_region_params,
+                       variances.map_or(num_region_params,
+                                        |v| v.len()));
+
             assert_eq!(num_region_params, b_rs.len());
-            let mut rs = vec!();
-            for i in 0..num_region_params {
+
+            (0..a_rs.len()).map(|i| {
                 let a_r = a_rs[i];
                 let b_r = b_rs[i];
-                let variance = variances[i];
-                let r = match variance {
-                    ty::Invariant => this.equate().regions(a_r, b_r),
-                    ty::Covariant => this.regions(a_r, b_r),
-                    ty::Contravariant => this.contraregions(a_r, b_r),
-                    ty::Bivariant => Ok(a_r),
-                };
-                rs.push(try!(r));
-            }
-            Ok(rs)
+                let variance = variances.map_or(ty::Invariant, |v| v[i]);
+                this.regions_with_variance(variance, a_r, b_r)
+            }).collect()
         }
     }
 
@@ -241,7 +243,7 @@ pub trait Combine<'tcx> : Sized {
     }
 
     fn args(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
-        self.contratys(a, b).and_then(|t| Ok(t))
+        self.tys_with_variance(ty::Contravariant, a, b).and_then(|t| Ok(t))
     }
 
     fn unsafeties(&self, a: Unsafety, b: Unsafety) -> cres<'tcx, Unsafety>;
@@ -309,7 +311,7 @@ pub trait Combine<'tcx> : Sized {
                           b: &ty::ExistentialBounds<'tcx>)
                           -> cres<'tcx, ty::ExistentialBounds<'tcx>>
     {
-        let r = try!(self.contraregions(a.region_bound, b.region_bound));
+        let r = try!(self.regions_with_variance(ty::Contravariant, a.region_bound, b.region_bound));
         let nb = try!(self.builtin_bounds(a.builtin_bounds, b.builtin_bounds));
         let pb = try!(self.projection_bounds(&a.projection_bounds, &b.projection_bounds));
         Ok(ty::ExistentialBounds { region_bound: r,
@@ -322,11 +324,6 @@ pub trait Combine<'tcx> : Sized {
                       b: ty::BuiltinBounds)
                       -> cres<'tcx, ty::BuiltinBounds>;
 
-    fn contraregions(&self, a: ty::Region, b: ty::Region)
-                  -> cres<'tcx, ty::Region>;
-
-    fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region>;
-
     fn trait_refs(&self,
                   a: &ty::TraitRef<'tcx>,
                   b: &ty::TraitRef<'tcx>)
@@ -540,7 +537,8 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C,
       }
 
       (&ty::ty_rptr(a_r, ref a_mt), &ty::ty_rptr(b_r, ref b_mt)) => {
-            let r = try!(this.contraregions(*a_r, *b_r));
+            let r = try!(this.regions_with_variance(ty::Contravariant, *a_r, *b_r));
+
             // FIXME(14985)  If we have mutable references to trait objects, we
             // used to use covariant subtyping. I have preserved this behaviour,
             // even though it is probably incorrect. So don't go down the usual
@@ -644,6 +642,10 @@ impl<'f, 'tcx> CombineFields<'f, 'tcx> {
         Equate((*self).clone())
     }
 
+    fn bivariate(&self) -> Bivariate<'f, 'tcx> {
+        Bivariate((*self).clone())
+    }
+
     fn sub(&self) -> Sub<'f, 'tcx> {
         Sub((*self).clone())
     }
@@ -697,7 +699,7 @@ impl<'f, 'tcx> CombineFields<'f, 'tcx> {
                         EqTo => {
                             self.generalize(a_ty, b_vid, false)
                         }
-                        SupertypeOf | SubtypeOf => {
+                        BiTo | SupertypeOf | SubtypeOf => {
                             self.generalize(a_ty, b_vid, true)
                         }
                     });
@@ -721,6 +723,10 @@ impl<'f, 'tcx> CombineFields<'f, 'tcx> {
             // to associate causes/spans with each of the relations in
             // the stack to get this right.
             match dir {
+                BiTo => {
+                    try!(self.bivariate().tys(a_ty, b_ty));
+                }
+
                 EqTo => {
                     try!(self.equate().tys(a_ty, b_ty));
                 }
@@ -730,7 +736,7 @@ impl<'f, 'tcx> CombineFields<'f, 'tcx> {
                 }
 
                 SupertypeOf => {
-                    try!(self.sub().contratys(a_ty, b_ty));
+                    try!(self.sub().tys_with_variance(ty::Contravariant, a_ty, b_ty));
                 }
             }
         }
diff --git a/src/librustc/middle/infer/equate.rs b/src/librustc/middle/infer/equate.rs
index f0bde222864..7194e20b0cf 100644
--- a/src/librustc/middle/infer/equate.rs
+++ b/src/librustc/middle/infer/equate.rs
@@ -13,11 +13,7 @@ use middle::ty::{self, Ty};
 use middle::ty::TyVar;
 use middle::infer::combine::*;
 use middle::infer::{cres};
-use middle::infer::glb::Glb;
-use middle::infer::InferCtxt;
-use middle::infer::lub::Lub;
-use middle::infer::sub::Sub;
-use middle::infer::{TypeTrace, Subtype};
+use middle::infer::{Subtype};
 use middle::infer::type_variable::{EqTo};
 use util::ppaux::{Repr};
 
@@ -33,21 +29,20 @@ pub fn Equate<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Equate<'f, 'tcx> {
 }
 
 impl<'f, 'tcx> Combine<'tcx> for Equate<'f, 'tcx> {
-    fn infcx<'a>(&'a self) -> &'a InferCtxt<'a, 'tcx> { self.fields.infcx }
-    fn tag(&self) -> String { "eq".to_string() }
-    fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
-    fn trace(&self) -> TypeTrace<'tcx> { self.fields.trace.clone() }
+    fn tag(&self) -> String { "Equate".to_string() }
+    fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields }
 
-    fn equate<'a>(&'a self) -> Equate<'a, 'tcx> { Equate(self.fields.clone()) }
-    fn sub<'a>(&'a self) -> Sub<'a, 'tcx> { Sub(self.fields.clone()) }
-    fn lub<'a>(&'a self) -> Lub<'a, 'tcx> { Lub(self.fields.clone()) }
-    fn glb<'a>(&'a self) -> Glb<'a, 'tcx> { Glb(self.fields.clone()) }
-
-    fn contratys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
+    fn tys_with_variance(&self, _: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
+                         -> cres<'tcx, Ty<'tcx>>
+    {
+        // Once we're equating, it doesn't matter what the variance is.
         self.tys(a, b)
     }
 
-    fn contraregions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> {
+    fn regions_with_variance(&self, _: ty::Variance, a: ty::Region, b: ty::Region)
+                             -> cres<'tcx, ty::Region>
+    {
+        // Once we're equating, it doesn't matter what the variance is.
         self.regions(a, b)
     }
 
diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs
index 72b33613c66..53032f9b9ac 100644
--- a/src/librustc/middle/infer/error_reporting.rs
+++ b/src/librustc/middle/infer/error_reporting.rs
@@ -200,9 +200,9 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
                                 ref trace_origins,
                                 ref same_regions) => {
                     if !same_regions.is_empty() {
-                        self.report_processed_errors(&var_origins[],
-                                                     &trace_origins[],
-                                                     &same_regions[]);
+                        self.report_processed_errors(&var_origins[..],
+                                                     &trace_origins[..],
+                                                     &same_regions[..]);
                     }
                 }
             }
@@ -675,6 +675,17 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
                     sup,
                     "");
             }
+            infer::Operand(span) => {
+                self.tcx.sess.span_err(
+                    span,
+                    "lifetime of operand does not outlive \
+                     the operation");
+                note_and_explain_region(
+                    self.tcx,
+                    "the operand is only valid for ",
+                    sup,
+                    "");
+            }
             infer::AddrOf(span) => {
                 self.tcx.sess.span_err(
                     span,
@@ -824,7 +835,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
         let parent = self.tcx.map.get_parent(scope_id);
         let parent_node = self.tcx.map.find(parent);
         let taken = lifetimes_in_scope(self.tcx, scope_id);
-        let life_giver = LifeGiver::with_taken(&taken[]);
+        let life_giver = LifeGiver::with_taken(&taken[..]);
         let node_inner = match parent_node {
             Some(ref node) => match *node {
                 ast_map::NodeItem(ref item) => {
@@ -924,7 +935,7 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> {
 
     fn rebuild(&self)
                -> (ast::FnDecl, Option<ast::ExplicitSelf_>, ast::Generics) {
-        let mut expl_self_opt = self.expl_self_opt.map(|x| x.clone());
+        let mut expl_self_opt = self.expl_self_opt.cloned();
         let mut inputs = self.fn_decl.inputs.clone();
         let mut output = self.fn_decl.output.clone();
         let mut ty_params = self.generics.ty_params.clone();
@@ -942,7 +953,7 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> {
             }
             expl_self_opt = self.rebuild_expl_self(expl_self_opt, lifetime,
                                                    &anon_nums, &region_names);
-            inputs = self.rebuild_args_ty(&inputs[], lifetime,
+            inputs = self.rebuild_args_ty(&inputs[..], lifetime,
                                           &anon_nums, &region_names);
             output = self.rebuild_output(&output, lifetime, &anon_nums, &region_names);
             ty_params = self.rebuild_ty_params(ty_params, lifetime,
@@ -1426,7 +1437,7 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> {
                                               opt_explicit_self, generics);
         let msg = format!("consider using an explicit lifetime \
                            parameter as shown: {}", suggested_fn);
-        self.tcx.sess.span_help(span, &msg[]);
+        self.tcx.sess.span_help(span, &msg[..]);
     }
 
     fn report_inference_failure(&self,
@@ -1593,6 +1604,11 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> {
                     span,
                     "...so that return value is valid for the call");
             }
+            infer::Operand(span) => {
+                self.tcx.sess.span_err(
+                    span,
+                    "...so that operand is valid for operation");
+            }
             infer::AddrOf(span) => {
                 self.tcx.sess.span_note(
                     span,
@@ -1771,7 +1787,7 @@ impl LifeGiver {
             s.push_str(&num_to_string(self.counter.get())[]);
             if !self.taken.contains(&s) {
                 lifetime = name_to_dummy_lifetime(
-                                    token::str_to_ident(&s[]).name);
+                                    token::str_to_ident(&s[..]).name);
                 self.generated.borrow_mut().push(lifetime);
                 break;
             }
diff --git a/src/librustc/middle/infer/glb.rs b/src/librustc/middle/infer/glb.rs
index ff0c2d92f45..33303808e84 100644
--- a/src/librustc/middle/infer/glb.rs
+++ b/src/librustc/middle/infer/glb.rs
@@ -10,12 +10,9 @@
 
 use super::combine::*;
 use super::lattice::*;
-use super::equate::Equate;
 use super::higher_ranked::HigherRankedRelations;
-use super::lub::Lub;
-use super::sub::Sub;
-use super::{cres, InferCtxt};
-use super::{TypeTrace, Subtype};
+use super::{cres};
+use super::Subtype;
 
 use middle::ty::{BuiltinBounds};
 use middle::ty::{self, Ty};
@@ -34,15 +31,30 @@ pub fn Glb<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Glb<'f, 'tcx> {
 }
 
 impl<'f, 'tcx> Combine<'tcx> for Glb<'f, 'tcx> {
-    fn infcx<'a>(&'a self) -> &'a InferCtxt<'a, 'tcx> { self.fields.infcx }
-    fn tag(&self) -> String { "glb".to_string() }
-    fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
-    fn trace(&self) -> TypeTrace<'tcx> { self.fields.trace.clone() }
+    fn tag(&self) -> String { "Glb".to_string() }
+    fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields }
 
-    fn equate<'a>(&'a self) -> Equate<'a, 'tcx> { Equate(self.fields.clone()) }
-    fn sub<'a>(&'a self) -> Sub<'a, 'tcx> { Sub(self.fields.clone()) }
-    fn lub<'a>(&'a self) -> Lub<'a, 'tcx> { Lub(self.fields.clone()) }
-    fn glb<'a>(&'a self) -> Glb<'a, 'tcx> { Glb(self.fields.clone()) }
+    fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
+                         -> cres<'tcx, Ty<'tcx>>
+    {
+        match v {
+            ty::Invariant => self.equate().tys(a, b),
+            ty::Covariant => self.tys(a, b),
+            ty::Bivariant => self.bivariate().tys(a, b),
+            ty::Contravariant => self.lub().tys(a, b),
+        }
+    }
+
+    fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region)
+                             -> cres<'tcx, ty::Region>
+    {
+        match v {
+            ty::Invariant => self.equate().regions(a, b),
+            ty::Covariant => self.regions(a, b),
+            ty::Bivariant => self.bivariate().regions(a, b),
+            ty::Contravariant => self.lub().regions(a, b),
+        }
+    }
 
     fn mts(&self, a: &ty::mt<'tcx>, b: &ty::mt<'tcx>) -> cres<'tcx, ty::mt<'tcx>> {
         let tcx = self.fields.infcx.tcx;
@@ -75,10 +87,6 @@ impl<'f, 'tcx> Combine<'tcx> for Glb<'f, 'tcx> {
         }
     }
 
-    fn contratys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
-        self.lub().tys(a, b)
-    }
-
     fn unsafeties(&self, a: Unsafety, b: Unsafety) -> cres<'tcx, Unsafety> {
         match (a, b) {
           (Unsafety::Normal, _) | (_, Unsafety::Normal) => Ok(Unsafety::Normal),
@@ -104,11 +112,6 @@ impl<'f, 'tcx> Combine<'tcx> for Glb<'f, 'tcx> {
         Ok(self.fields.infcx.region_vars.glb_regions(Subtype(self.trace()), a, b))
     }
 
-    fn contraregions(&self, a: ty::Region, b: ty::Region)
-                    -> cres<'tcx, ty::Region> {
-        self.lub().regions(a, b)
-    }
-
     fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
         super_lattice_tys(self, a, b)
     }
diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs
index 4469e27a5b0..a729156c88b 100644
--- a/src/librustc/middle/infer/higher_ranked/mod.rs
+++ b/src/librustc/middle/infer/higher_ranked/mod.rs
@@ -31,7 +31,7 @@ pub trait HigherRankedRelations<'tcx> {
         where T : Combineable<'tcx>;
 }
 
-trait InferCtxtExt<'tcx> {
+trait InferCtxtExt {
     fn tainted_regions(&self, snapshot: &CombinedSnapshot, r: ty::Region) -> Vec<ty::Region>;
 
     fn region_vars_confined_to_snapshot(&self,
@@ -371,7 +371,7 @@ fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>,
     }))
 }
 
-impl<'a,'tcx> InferCtxtExt<'tcx> for InferCtxt<'a,'tcx> {
+impl<'a,'tcx> InferCtxtExt for InferCtxt<'a,'tcx> {
     fn tainted_regions(&self, snapshot: &CombinedSnapshot, r: ty::Region) -> Vec<ty::Region> {
         self.region_vars.tainted(&snapshot.region_vars_snapshot, r)
     }
diff --git a/src/librustc/middle/infer/lub.rs b/src/librustc/middle/infer/lub.rs
index 204560e87ee..3570effa9fa 100644
--- a/src/librustc/middle/infer/lub.rs
+++ b/src/librustc/middle/infer/lub.rs
@@ -9,13 +9,10 @@
 // except according to those terms.
 
 use super::combine::*;
-use super::equate::Equate;
-use super::glb::Glb;
 use super::higher_ranked::HigherRankedRelations;
 use super::lattice::*;
-use super::sub::Sub;
-use super::{cres, InferCtxt};
-use super::{TypeTrace, Subtype};
+use super::{cres};
+use super::{Subtype};
 
 use middle::ty::{BuiltinBounds};
 use middle::ty::{self, Ty};
@@ -34,15 +31,30 @@ pub fn Lub<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Lub<'f, 'tcx> {
 }
 
 impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> {
-    fn infcx<'a>(&'a self) -> &'a InferCtxt<'a, 'tcx> { self.fields.infcx }
-    fn tag(&self) -> String { "lub".to_string() }
-    fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
-    fn trace(&self) -> TypeTrace<'tcx> { self.fields.trace.clone() }
+    fn tag(&self) -> String { "Lub".to_string() }
+    fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields }
 
-    fn equate<'a>(&'a self) -> Equate<'a, 'tcx> { Equate(self.fields.clone()) }
-    fn sub<'a>(&'a self) -> Sub<'a, 'tcx> { Sub(self.fields.clone()) }
-    fn lub<'a>(&'a self) -> Lub<'a, 'tcx> { Lub(self.fields.clone()) }
-    fn glb<'a>(&'a self) -> Glb<'a, 'tcx> { Glb(self.fields.clone()) }
+    fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
+                         -> cres<'tcx, Ty<'tcx>>
+    {
+        match v {
+            ty::Invariant => self.equate().tys(a, b),
+            ty::Covariant => self.tys(a, b),
+            ty::Bivariant => self.bivariate().tys(a, b),
+            ty::Contravariant => self.glb().tys(a, b),
+        }
+    }
+
+    fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region)
+                             -> cres<'tcx, ty::Region>
+    {
+        match v {
+            ty::Invariant => self.equate().regions(a, b),
+            ty::Covariant => self.regions(a, b),
+            ty::Bivariant => self.bivariate().regions(a, b),
+            ty::Contravariant => self.glb().regions(a, b),
+        }
+    }
 
     fn mts(&self, a: &ty::mt<'tcx>, b: &ty::mt<'tcx>) -> cres<'tcx, ty::mt<'tcx>> {
         let tcx = self.tcx();
@@ -70,10 +82,6 @@ impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> {
         }
     }
 
-    fn contratys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
-        self.glb().tys(a, b)
-    }
-
     fn unsafeties(&self, a: Unsafety, b: Unsafety) -> cres<'tcx, Unsafety> {
         match (a, b) {
           (Unsafety::Unsafe, _) | (_, Unsafety::Unsafe) => Ok(Unsafety::Unsafe),
@@ -90,11 +98,6 @@ impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> {
         Ok(a.intersection(b))
     }
 
-    fn contraregions(&self, a: ty::Region, b: ty::Region)
-                    -> cres<'tcx, ty::Region> {
-        self.glb().regions(a, b)
-    }
-
     fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> {
         debug!("{}.regions({}, {})",
                self.tag(),
diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs
index 00e377d65fe..b0576ff55ff 100644
--- a/src/librustc/middle/infer/mod.rs
+++ b/src/librustc/middle/infer/mod.rs
@@ -45,6 +45,7 @@ use self::lub::Lub;
 use self::unify::{UnificationTable, InferCtxtMethodsForSimplyUnifiableTypes};
 use self::error_reporting::ErrorReporting;
 
+pub mod bivariate;
 pub mod combine;
 pub mod equate;
 pub mod error_reporting;
@@ -209,6 +210,9 @@ pub enum SubregionOrigin<'tcx> {
     // Region in return type of invoked fn must enclose call
     CallReturn(Span),
 
+    // Operands must be in scope
+    Operand(Span),
+
     // Region resulting from a `&` expr must enclose the `&` expr
     AddrOf(Span),
 
@@ -1194,6 +1198,7 @@ impl<'tcx> SubregionOrigin<'tcx> {
             CallRcvr(a) => a,
             CallArg(a) => a,
             CallReturn(a) => a,
+            Operand(a) => a,
             AddrOf(a) => a,
             AutoBorrow(a) => a,
             SafeDestructor(a) => a,
@@ -1257,6 +1262,7 @@ impl<'tcx> Repr<'tcx> for SubregionOrigin<'tcx> {
             CallRcvr(a) => format!("CallRcvr({})", a.repr(tcx)),
             CallArg(a) => format!("CallArg({})", a.repr(tcx)),
             CallReturn(a) => format!("CallReturn({})", a.repr(tcx)),
+            Operand(a) => format!("Operand({})", a.repr(tcx)),
             AddrOf(a) => format!("AddrOf({})", a.repr(tcx)),
             AutoBorrow(a) => format!("AutoBorrow({})", a.repr(tcx)),
             SafeDestructor(a) => format!("SafeDestructor({})", a.repr(tcx)),
diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs
index 5cdfdcc7c9b..b4fd34f206f 100644
--- a/src/librustc/middle/infer/region_inference/mod.rs
+++ b/src/librustc/middle/infer/region_inference/mod.rs
@@ -977,7 +977,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
         self.expansion(&mut var_data);
         self.contraction(&mut var_data);
         let values =
-            self.extract_values_and_collect_conflicts(&var_data[],
+            self.extract_values_and_collect_conflicts(&var_data[..],
                                                       errors);
         self.collect_concrete_region_errors(&values, errors);
         values
diff --git a/src/librustc/middle/infer/sub.rs b/src/librustc/middle/infer/sub.rs
index 1e0d14544ff..33da3092b2a 100644
--- a/src/librustc/middle/infer/sub.rs
+++ b/src/librustc/middle/infer/sub.rs
@@ -10,12 +10,8 @@
 
 use super::combine::*;
 use super::{cres, CresCompare};
-use super::equate::Equate;
-use super::glb::Glb;
 use super::higher_ranked::HigherRankedRelations;
-use super::InferCtxt;
-use super::lub::Lub;
-use super::{TypeTrace, Subtype};
+use super::{Subtype};
 use super::type_variable::{SubtypeOf, SupertypeOf};
 
 use middle::ty::{BuiltinBounds};
@@ -37,28 +33,30 @@ pub fn Sub<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Sub<'f, 'tcx> {
 }
 
 impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> {
-    fn infcx<'a>(&'a self) -> &'a InferCtxt<'a, 'tcx> { self.fields.infcx }
-    fn tag(&self) -> String { "sub".to_string() }
-    fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
-    fn trace(&self) -> TypeTrace<'tcx> { self.fields.trace.clone() }
-
-    fn equate<'a>(&'a self) -> Equate<'a, 'tcx> { Equate(self.fields.clone()) }
-    fn sub<'a>(&'a self) -> Sub<'a, 'tcx> { Sub(self.fields.clone()) }
-    fn lub<'a>(&'a self) -> Lub<'a, 'tcx> { Lub(self.fields.clone()) }
-    fn glb<'a>(&'a self) -> Glb<'a, 'tcx> { Glb(self.fields.clone()) }
-
-    fn contratys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
-        Sub(self.fields.switch_expected()).tys(b, a)
+    fn tag(&self) -> String { "Sub".to_string() }
+    fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields }
+
+    fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>)
+                         -> cres<'tcx, Ty<'tcx>>
+    {
+        match v {
+            ty::Invariant => self.equate().tys(a, b),
+            ty::Covariant => self.tys(a, b),
+            ty::Bivariant => self.bivariate().tys(a, b),
+            ty::Contravariant => Sub(self.fields.switch_expected()).tys(b, a),
+        }
     }
 
-    fn contraregions(&self, a: ty::Region, b: ty::Region)
-                     -> cres<'tcx, ty::Region> {
-                         let opp = CombineFields {
-                             a_is_expected: !self.fields.a_is_expected,
-                             ..self.fields.clone()
-                         };
-                         Sub(opp).regions(b, a)
-                     }
+    fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region)
+                             -> cres<'tcx, ty::Region>
+    {
+        match v {
+            ty::Invariant => self.equate().regions(a, b),
+            ty::Covariant => self.regions(a, b),
+            ty::Bivariant => self.bivariate().regions(a, b),
+            ty::Contravariant => Sub(self.fields.switch_expected()).regions(b, a),
+        }
+    }
 
     fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> {
         debug!("{}.regions({}, {})",
diff --git a/src/librustc/middle/infer/type_variable.rs b/src/librustc/middle/infer/type_variable.rs
index 9b8a4a84412..a856137af09 100644
--- a/src/librustc/middle/infer/type_variable.rs
+++ b/src/librustc/middle/infer/type_variable.rs
@@ -14,6 +14,7 @@ use self::UndoEntry::*;
 
 use middle::ty::{self, Ty};
 use std::cmp::min;
+use std::marker::PhantomData;
 use std::mem;
 use std::u32;
 use util::snapshot_vec as sv;
@@ -42,13 +43,13 @@ enum UndoEntry {
     Relate(ty::TyVid, ty::TyVid),
 }
 
-struct Delegate<'tcx>;
+struct Delegate<'tcx>(PhantomData<&'tcx ()>);
 
 type Relation = (RelationDir, ty::TyVid);
 
 #[derive(Copy, PartialEq, Debug)]
 pub enum RelationDir {
-    SubtypeOf, SupertypeOf, EqTo
+    SubtypeOf, SupertypeOf, EqTo, BiTo
 }
 
 impl RelationDir {
@@ -56,14 +57,15 @@ impl RelationDir {
         match self {
             SubtypeOf => SupertypeOf,
             SupertypeOf => SubtypeOf,
-            EqTo => EqTo
+            EqTo => EqTo,
+            BiTo => BiTo,
         }
     }
 }
 
 impl<'tcx> TypeVariableTable<'tcx> {
     pub fn new() -> TypeVariableTable<'tcx> {
-        TypeVariableTable { values: sv::SnapshotVec::new(Delegate) }
+        TypeVariableTable { values: sv::SnapshotVec::new(Delegate(PhantomData)) }
     }
 
     fn relations<'a>(&'a mut self, a: ty::TyVid) -> &'a mut Vec<Relation> {
diff --git a/src/librustc/middle/infer/unify.rs b/src/librustc/middle/infer/unify.rs
index 235f3f994c6..0675cec6f69 100644
--- a/src/librustc/middle/infer/unify.rs
+++ b/src/librustc/middle/infer/unify.rs
@@ -18,6 +18,7 @@ use middle::infer::{uok, ures};
 use middle::infer::InferCtxt;
 use std::cell::RefCell;
 use std::fmt::Debug;
+use std::marker::PhantomData;
 use syntax::ast;
 use util::snapshot_vec as sv;
 
@@ -79,7 +80,7 @@ pub struct UnificationTable<K:UnifyKey> {
 /// made during the snapshot may either be *committed* or *rolled back*.
 pub struct Snapshot<K:UnifyKey> {
     // Link snapshot to the key type `K` of the table.
-    marker: marker::CovariantType<K>,
+    marker: marker::PhantomData<K>,
     snapshot: sv::Snapshot,
 }
 
@@ -92,7 +93,7 @@ pub struct Node<K:UnifyKey> {
 }
 
 #[derive(Copy)]
-pub struct Delegate<K>;
+pub struct Delegate<K>(PhantomData<K>);
 
 // We can't use V:LatticeValue, much as I would like to,
 // because frequently the pattern is that V=Option<U> for some
@@ -102,14 +103,14 @@ pub struct Delegate<K>;
 impl<K:UnifyKey> UnificationTable<K> {
     pub fn new() -> UnificationTable<K> {
         UnificationTable {
-            values: sv::SnapshotVec::new(Delegate),
+            values: sv::SnapshotVec::new(Delegate(PhantomData)),
         }
     }
 
     /// Starts a new snapshot. Each snapshot must be either
     /// rolled back or committed in a "LIFO" (stack) order.
     pub fn snapshot(&mut self) -> Snapshot<K> {
-        Snapshot { marker: marker::CovariantType::<K>,
+        Snapshot { marker: marker::PhantomData::<K>,
                    snapshot: self.values.start_snapshot() }
     }