about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2014-12-01 10:11:59 -0500
committerNiko Matsakis <niko@alum.mit.edu>2014-12-19 03:29:29 -0500
commit3efc9d2c55af6e58dd96c5814260bacc2b582ef3 (patch)
tree0c9d4717d2ef6cb41fc29d666da5f81c01ddf7e3
parent514dfdbf12b71758c7abc3219ae1a3936e4d59d9 (diff)
downloadrust-3efc9d2c55af6e58dd96c5814260bacc2b582ef3.tar.gz
rust-3efc9d2c55af6e58dd96c5814260bacc2b582ef3.zip
Fix bug in higher-ranked code that would sometimes leak skolemized regions and/or cause incorrect results.
-rw-r--r--src/librustc/middle/infer/coercion.rs10
-rw-r--r--src/librustc/middle/infer/combine.rs36
-rw-r--r--src/librustc/middle/infer/error_reporting.rs4
-rw-r--r--src/librustc/middle/infer/higher_ranked/doc.rs28
-rw-r--r--src/librustc/middle/infer/higher_ranked/mod.rs363
-rw-r--r--src/librustc/middle/infer/mod.rs49
-rw-r--r--src/librustc/middle/infer/region_inference/mod.rs27
-rw-r--r--src/librustc/middle/infer/resolve.rs35
-rw-r--r--src/librustc/middle/infer/type_variable.rs46
-rw-r--r--src/librustc/middle/ty_fold.rs11
-rw-r--r--src/librustc/util/snapshot_vec.rs8
-rw-r--r--src/librustc_driver/test.rs42
-rw-r--r--src/librustc_typeck/check/closure.rs4
-rw-r--r--src/librustc_typeck/check/method/mod.rs2
-rw-r--r--src/librustc_typeck/check/mod.rs10
-rw-r--r--src/librustc_typeck/check/vtable.rs19
-rw-r--r--src/test/compile-fail/bad-match.rs3
17 files changed, 456 insertions, 241 deletions
diff --git a/src/librustc/middle/infer/coercion.rs b/src/librustc/middle/infer/coercion.rs
index e268160a42b..43d99ecb427 100644
--- a/src/librustc/middle/infer/coercion.rs
+++ b/src/librustc/middle/infer/coercion.rs
@@ -286,7 +286,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                             let ty = ty::mk_rptr(self.get_ref().infcx.tcx,
                                                  r_borrow,
                                                  ty::mt{ty: ty, mutbl: mt_b.mutbl});
-                            try!(self.get_ref().infcx.try(|| sub.tys(ty, b)));
+                            try!(self.get_ref().infcx.try(|_| sub.tys(ty, b)));
                             debug!("Success, coerced with AutoDerefRef(1, \
                                     AutoPtr(AutoUnsize({})))", kind);
                             Ok(Some(AdjustDerefRef(AutoDerefRef {
@@ -309,7 +309,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
 
                             let ty = ty::mk_ptr(self.get_ref().infcx.tcx,
                                                  ty::mt{ty: ty, mutbl: mt_b.mutbl});
-                            try!(self.get_ref().infcx.try(|| sub.tys(ty, b)));
+                            try!(self.get_ref().infcx.try(|_| sub.tys(ty, b)));
                             debug!("Success, coerced with AutoDerefRef(1, \
                                     AutoPtr(AutoUnsize({})))", kind);
                             Ok(Some(AdjustDerefRef(AutoDerefRef {
@@ -327,7 +327,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                     match self.unsize_ty(t_a, sty_a, t_b) {
                         Some((ty, kind)) => {
                             let ty = ty::mk_uniq(self.get_ref().infcx.tcx, ty);
-                            try!(self.get_ref().infcx.try(|| sub.tys(ty, b)));
+                            try!(self.get_ref().infcx.try(|_| sub.tys(ty, b)));
                             debug!("Success, coerced with AutoDerefRef(1, \
                                     AutoUnsizeUniq({}))", kind);
                             Ok(Some(AdjustDerefRef(AutoDerefRef {
@@ -384,7 +384,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                     let mut result = None;
                     let mut tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate();
                     for (i, (tp_a, tp_b)) in tps {
-                        if self.get_ref().infcx.try(|| sub.tys(*tp_a, *tp_b)).is_ok() {
+                        if self.get_ref().infcx.try(|_| sub.tys(*tp_a, *tp_b)).is_ok() {
                             continue;
                         }
                         match
@@ -397,7 +397,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                                 let mut new_substs = substs_a.clone();
                                 new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp;
                                 let ty = ty::mk_struct(tcx, did_a, new_substs);
-                                if self.get_ref().infcx.try(|| sub.tys(ty, ty_b)).is_err() {
+                                if self.get_ref().infcx.try(|_| sub.tys(ty, ty_b)).is_err() {
                                     debug!("Unsized type parameter '{}', but still \
                                             could not match types {} and {}",
                                            ppaux::ty_to_string(tcx, *tp_a),
diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs
index 26bba55594b..1b72a572e9e 100644
--- a/src/librustc/middle/infer/combine.rs
+++ b/src/librustc/middle/infer/combine.rs
@@ -706,14 +706,38 @@ impl<'cx, 'tcx> ty_fold::TypeFolder<'tcx> for Generalizer<'cx, 'tcx> {
 
     fn fold_region(&mut self, r: ty::Region) -> ty::Region {
         match r {
-            ty::ReLateBound(..) | ty::ReEarlyBound(..) => r,
-            _ if self.make_region_vars => {
-                // FIXME: This is non-ideal because we don't give a
-                // very descriptive origin for this region variable.
-                self.infcx.next_region_var(MiscVariable(self.span))
+            // Never make variables for regions bound within the type itself.
+            ty::ReLateBound(..) => { return r; }
+
+            // Early-bound regions should really have been substituted away before
+            // we get to this point.
+            ty::ReEarlyBound(..) => {
+                self.tcx().sess.span_bug(
+                    self.span,
+                    format!("Encountered early bound region when generalizing: {}",
+                            r.repr(self.tcx()))[]);
+            }
+
+            // Always make a fresh region variable for skolemized regions;
+            // the higher-ranked decision procedures rely on this.
+            ty::ReInfer(ty::ReSkolemized(..)) => { }
+
+            // For anything else, we make a region variable, unless we
+            // are *equating*, in which case it's just wasteful.
+            ty::ReEmpty |
+            ty::ReStatic |
+            ty::ReScope(..) |
+            ty::ReInfer(ty::ReVar(..)) |
+            ty::ReFree(..) => {
+                if !self.make_region_vars {
+                    return r;
+                }
             }
-            _ => r,
         }
+
+        // FIXME: This is non-ideal because we don't give a
+        // very descriptive origin for this region variable.
+        self.infcx.next_region_var(MiscVariable(self.span))
     }
 }
 
diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs
index ab685dd5dbc..e1473847c23 100644
--- a/src/librustc/middle/infer/error_reporting.rs
+++ b/src/librustc/middle/infer/error_reporting.rs
@@ -1640,7 +1640,7 @@ pub trait Resolvable<'tcx> {
 
 impl<'tcx> Resolvable<'tcx> for Ty<'tcx> {
     fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) -> Ty<'tcx> {
-        infcx.resolve_type_vars_if_possible(*self)
+        infcx.resolve_type_vars_if_possible(self)
     }
     fn contains_error(&self) -> bool {
         ty::type_is_error(*self)
@@ -1650,7 +1650,7 @@ impl<'tcx> Resolvable<'tcx> for Ty<'tcx> {
 impl<'tcx> Resolvable<'tcx> for Rc<ty::TraitRef<'tcx>> {
     fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>)
                    -> Rc<ty::TraitRef<'tcx>> {
-        Rc::new(infcx.resolve_type_vars_in_trait_ref_if_possible(&**self))
+        Rc::new(infcx.resolve_type_vars_if_possible(&**self))
     }
     fn contains_error(&self) -> bool {
         ty::trait_ref_contains_error(&**self)
diff --git a/src/librustc/middle/infer/higher_ranked/doc.rs b/src/librustc/middle/infer/higher_ranked/doc.rs
index 2bad3616a05..f6f254c0e8d 100644
--- a/src/librustc/middle/infer/higher_ranked/doc.rs
+++ b/src/librustc/middle/infer/higher_ranked/doc.rs
@@ -249,19 +249,21 @@
 //! in T and try to, in some cases, replace them with bound regions to
 //! yield the final result.
 //!
-//! To decide whether to replace a region `R` that appears in `T` with a
-//! bound region, the algorithms make use of two bits of information.
-//! First is a set `V` that contains all region variables created as part
-//! of the LUB/GLB computation. `V` will contain the region variables
-//! created to replace the bound regions in the input types, but it also
-//! contains 'intermediate' variables created to represent the LUB/GLB of
-//! individual regions.  Basically, when asked to compute the LUB/GLB of a
-//! region variable with another region, the inferencer cannot oblige
-//! immediately since the values of that variables are not known.
-//! Therefore, it creates a new variable that is related to the two
-//! regions.  For example, the LUB of two variables `$x` and `$y` is a
-//! fresh variable `$z` that is constrained such that `$x <= $z` and `$y
-//! <= $z`.  So `V` will contain these intermediate variables as well.
+//! To decide whether to replace a region `R` that appears in `T` with
+//! a bound region, the algorithms make use of two bits of
+//! information.  First is a set `V` that contains all region
+//! variables created as part of the LUB/GLB computation (roughly; see
+//! `region_vars_confined_to_snapshot()` for full details). `V` will
+//! contain the region variables created to replace the bound regions
+//! in the input types, but it also contains 'intermediate' variables
+//! created to represent the LUB/GLB of individual regions.
+//! Basically, when asked to compute the LUB/GLB of a region variable
+//! with another region, the inferencer cannot oblige immediately
+//! since the values of that variables are not known.  Therefore, it
+//! creates a new variable that is related to the two regions.  For
+//! example, the LUB of two variables `$x` and `$y` is a fresh
+//! variable `$z` that is constrained such that `$x <= $z` and `$y <=
+//! $z`.  So `V` will contain these intermediate variables as well.
 //!
 //! The other important factor in deciding how to replace a region in T is
 //! the function `Tainted($r)` which, for a region variable, identifies
diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs
index be053afcca4..0a2049bef48 100644
--- a/src/librustc/middle/infer/higher_ranked/mod.rs
+++ b/src/librustc/middle/infer/higher_ranked/mod.rs
@@ -11,14 +11,13 @@
 //! Helper routines for higher-ranked things. See the `doc` module at
 //! the end of the file for details.
 
-use super::{combine, cres, InferCtxt, HigherRankedType};
+use super::{combine, CombinedSnapshot, cres, InferCtxt, HigherRankedType};
 use super::combine::Combine;
-use super::region_inference::{RegionMark};
 
 use middle::ty::{mod, Ty, replace_late_bound_regions};
 use middle::ty_fold::{mod, HigherRankedFoldable, TypeFoldable};
 use syntax::codemap::Span;
-use util::nodemap::FnvHashMap;
+use util::nodemap::{FnvHashMap, FnvHashSet};
 use util::ppaux::{bound_region_to_string, Repr};
 
 pub trait HigherRankedCombineable<'tcx>: HigherRankedFoldable<'tcx> +
@@ -37,6 +36,14 @@ pub trait HigherRankedRelations<'tcx> {
         where T : HigherRankedCombineable<'tcx>;
 }
 
+trait InferCtxtExt<'tcx> {
+    fn tainted_regions(&self, snapshot: &CombinedSnapshot, r: ty::Region) -> Vec<ty::Region>;
+
+    fn region_vars_confined_to_snapshot(&self,
+                                        snapshot: &CombinedSnapshot)
+                                        -> Vec<ty::RegionVid>;
+}
+
 impl<'tcx,C> HigherRankedRelations<'tcx> for C
     where C : Combine<'tcx>
 {
@@ -54,114 +61,115 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C
         // please see the large comment at the end of the file in the (inlined) module
         // `doc`.
 
-        // Make a mark so we can examine "all bindings that were
+        // Start a snapshot so we can examine "all bindings that were
         // created as part of this type comparison".
-        let mark = self.infcx().region_vars.mark();
-
-        // First, we instantiate each bound region in the subtype with a fresh
-        // region variable.
-        let (a_prime, _) =
-            self.infcx().replace_late_bound_regions_with_fresh_var(
-                self.trace().origin.span(),
-                HigherRankedType,
-                a);
-
-        // Second, we instantiate each bound region in the supertype with a
-        // fresh concrete region.
-        let (b_prime, skol_map) = {
-            replace_late_bound_regions(self.tcx(), b, |br, _| {
-                let skol = self.infcx().region_vars.new_skolemized(br);
-                debug!("Bound region {} skolemized to {}",
-                       bound_region_to_string(self.tcx(), "", false, br),
-                       skol);
-                skol
-            })
-        };
-
-        debug!("a_prime={}", a_prime.repr(self.tcx()));
-        debug!("b_prime={}", b_prime.repr(self.tcx()));
-
-        // Compare types now that bound regions have been replaced.
-        let result = try!(HigherRankedCombineable::super_combine(self, &a_prime, &b_prime));
-
-        // Presuming type comparison succeeds, we need to check
-        // that the skolemized regions do not "leak".
-        let new_vars =
-            self.infcx().region_vars.vars_created_since_mark(mark);
-        for (&skol_br, &skol) in skol_map.iter() {
-            let tainted = self.infcx().region_vars.tainted(mark, skol);
-            for tainted_region in tainted.iter() {
-                // Each skolemized should only be relatable to itself
-                // or new variables:
-                match *tainted_region {
-                    ty::ReInfer(ty::ReVar(ref vid)) => {
-                        if new_vars.iter().any(|x| x == vid) { continue; }
-                    }
-                    _ => {
-                        if *tainted_region == skol { continue; }
+        return self.infcx().try(|snapshot| {
+            // First, we instantiate each bound region in the subtype with a fresh
+            // region variable.
+            let (a_prime, _) =
+                self.infcx().replace_late_bound_regions_with_fresh_var(
+                    self.trace().origin.span(),
+                    HigherRankedType,
+                    a);
+
+            // Second, we instantiate each bound region in the supertype with a
+            // fresh concrete region.
+            let (b_prime, skol_map) = {
+                replace_late_bound_regions(self.tcx(), b, |br, _| {
+                    let skol = self.infcx().region_vars.new_skolemized(br);
+                    debug!("Bound region {} skolemized to {}",
+                           bound_region_to_string(self.tcx(), "", false, br),
+                           skol);
+                    skol
+                })
+            };
+
+            debug!("a_prime={}", a_prime.repr(self.tcx()));
+            debug!("b_prime={}", b_prime.repr(self.tcx()));
+
+            // Compare types now that bound regions have been replaced.
+            let result = try!(HigherRankedCombineable::super_combine(self, &a_prime, &b_prime));
+
+            // Presuming type comparison succeeds, we need to check
+            // that the skolemized regions do not "leak".
+            let new_vars = self.infcx().region_vars_confined_to_snapshot(snapshot);
+            for (&skol_br, &skol) in skol_map.iter() {
+                let tainted = self.infcx().tainted_regions(snapshot, skol);
+                for tainted_region in tainted.iter() {
+                    // Each skolemized should only be relatable to itself
+                    // or new variables:
+                    match *tainted_region {
+                        ty::ReInfer(ty::ReVar(ref vid)) => {
+                            if new_vars.iter().any(|x| x == vid) { continue; }
+                        }
+                        _ => {
+                            if *tainted_region == skol { continue; }
+                        }
+                    };
+
+                    // 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));
                     }
-                };
-
-                // 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));
                 }
             }
-        }
 
-        debug!("higher_ranked_sub: OK result={}",
-               result.repr(self.tcx()));
+            debug!("higher_ranked_sub: OK result={}",
+                   result.repr(self.tcx()));
 
-        return Ok(result);
+            Ok(result)
+        });
     }
 
     fn higher_ranked_lub<T>(&self, a: &T, b: &T) -> cres<'tcx, T>
         where T : HigherRankedCombineable<'tcx>
     {
-        // Make a mark so we can examine "all bindings that were
+        // Start a snapshot so we can examine "all bindings that were
         // created as part of this type comparison".
-        let mark = self.infcx().region_vars.mark();
-
-        // Instantiate each bound region with a fresh region variable.
-        let span = self.trace().origin.span();
-        let (a_with_fresh, a_map) =
-            self.infcx().replace_late_bound_regions_with_fresh_var(
-                span, HigherRankedType, a);
-        let (b_with_fresh, _) =
-            self.infcx().replace_late_bound_regions_with_fresh_var(
-                span, HigherRankedType, b);
-
-        // Collect constraints.
-        let result0 =
-            try!(HigherRankedCombineable::super_combine(self, &a_with_fresh, &b_with_fresh));
-        debug!("lub result0 = {}", result0.repr(self.tcx()));
-
-        // Generalize the regions appearing in result0 if possible
-        let new_vars = self.infcx().region_vars.vars_created_since_mark(mark);
-        let span = self.trace().origin.span();
-        let result1 =
-            fold_regions_in(
-                self.tcx(),
-                &result0,
-                |r, debruijn| generalize_region(self.infcx(), span, mark, debruijn,
-                                                new_vars.as_slice(), &a_map, r));
-
-        debug!("lub({},{}) = {}",
-               a.repr(self.tcx()),
-               b.repr(self.tcx()),
-               result1.repr(self.tcx()));
-
-        return Ok(result1);
+        return self.infcx().try(|snapshot| {
+            // Instantiate each bound region with a fresh region variable.
+            let span = self.trace().origin.span();
+            let (a_with_fresh, a_map) =
+                self.infcx().replace_late_bound_regions_with_fresh_var(
+                    span, HigherRankedType, a);
+            let (b_with_fresh, _) =
+                self.infcx().replace_late_bound_regions_with_fresh_var(
+                    span, HigherRankedType, b);
+
+            // Collect constraints.
+            let result0 =
+                try!(HigherRankedCombineable::super_combine(self, &a_with_fresh, &b_with_fresh));
+            let result0 =
+                self.infcx().resolve_type_vars_if_possible(&result0);
+            debug!("lub result0 = {}", result0.repr(self.tcx()));
+
+            // Generalize the regions appearing in result0 if possible
+            let new_vars = self.infcx().region_vars_confined_to_snapshot(snapshot);
+            let span = self.trace().origin.span();
+            let result1 =
+                fold_regions_in(
+                    self.tcx(),
+                    &result0,
+                    |r, debruijn| generalize_region(self.infcx(), span, snapshot, debruijn,
+                                                    new_vars.as_slice(), &a_map, r));
+
+            debug!("lub({},{}) = {}",
+                   a.repr(self.tcx()),
+                   b.repr(self.tcx()),
+                   result1.repr(self.tcx()));
+
+            Ok(result1)
+        });
 
         fn generalize_region(infcx: &InferCtxt,
                              span: Span,
-                             mark: RegionMark,
+                             snapshot: &CombinedSnapshot,
                              debruijn: ty::DebruijnIndex,
                              new_vars: &[ty::RegionVid],
                              a_map: &FnvHashMap<ty::BoundRegion, ty::Region>,
@@ -174,7 +182,7 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C
                 return r0;
             }
 
-            let tainted = infcx.region_vars.tainted(mark, r0);
+            let tainted = infcx.tainted_regions(snapshot, r0);
 
             // Variables created during LUB computation which are
             // *related* to regions that pre-date the LUB computation
@@ -215,47 +223,49 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C
         debug!("{}.higher_ranked_glb({}, {})",
                self.tag(), a.repr(self.tcx()), b.repr(self.tcx()));
 
-        // Make a mark so we can examine "all bindings that were
+        // Make a snapshot so we can examine "all bindings that were
         // created as part of this type comparison".
-        let mark = self.infcx().region_vars.mark();
-
-        // Instantiate each bound region with a fresh region variable.
-        let (a_with_fresh, a_map) =
-            self.infcx().replace_late_bound_regions_with_fresh_var(
-                self.trace().origin.span(), HigherRankedType, a);
-        let (b_with_fresh, b_map) =
-            self.infcx().replace_late_bound_regions_with_fresh_var(
-                self.trace().origin.span(), HigherRankedType, b);
-        let a_vars = var_ids(self, &a_map);
-        let b_vars = var_ids(self, &b_map);
-
-        // Collect constraints.
-        let result0 =
-            try!(HigherRankedCombineable::super_combine(self, &a_with_fresh, &b_with_fresh));
-        debug!("glb result0 = {}", result0.repr(self.tcx()));
-
-        // Generalize the regions appearing in fn_ty0 if possible
-        let new_vars = self.infcx().region_vars.vars_created_since_mark(mark);
-        let span = self.trace().origin.span();
-        let result1 =
-            fold_regions_in(
-                self.tcx(),
-                &result0,
-                |r, debruijn| generalize_region(self.infcx(), span, mark, debruijn,
-                                                new_vars.as_slice(),
-                                                &a_map, a_vars.as_slice(), b_vars.as_slice(),
-                                                r));
-
-        debug!("glb({},{}) = {}",
-               a.repr(self.tcx()),
-               b.repr(self.tcx()),
-               result1.repr(self.tcx()));
-
-        return Ok(result1);
+        return self.infcx().try(|snapshot| {
+            // Instantiate each bound region with a fresh region variable.
+            let (a_with_fresh, a_map) =
+                self.infcx().replace_late_bound_regions_with_fresh_var(
+                    self.trace().origin.span(), HigherRankedType, a);
+            let (b_with_fresh, b_map) =
+                self.infcx().replace_late_bound_regions_with_fresh_var(
+                    self.trace().origin.span(), HigherRankedType, b);
+            let a_vars = var_ids(self, &a_map);
+            let b_vars = var_ids(self, &b_map);
+
+            // Collect constraints.
+            let result0 =
+                try!(HigherRankedCombineable::super_combine(self, &a_with_fresh, &b_with_fresh));
+            let result0 =
+                self.infcx().resolve_type_vars_if_possible(&result0);
+            debug!("glb result0 = {}", result0.repr(self.tcx()));
+
+            // Generalize the regions appearing in fn_ty0 if possible
+            let new_vars = self.infcx().region_vars_confined_to_snapshot(snapshot);
+            let span = self.trace().origin.span();
+            let result1 =
+                fold_regions_in(
+                    self.tcx(),
+                    &result0,
+                    |r, debruijn| generalize_region(self.infcx(), span, snapshot, debruijn,
+                                                    new_vars.as_slice(),
+                                                    &a_map, a_vars.as_slice(), b_vars.as_slice(),
+                                                    r));
+
+            debug!("glb({},{}) = {}",
+                   a.repr(self.tcx()),
+                   b.repr(self.tcx()),
+                   result1.repr(self.tcx()));
+
+            Ok(result1)
+        });
 
         fn generalize_region(infcx: &InferCtxt,
                              span: Span,
-                             mark: RegionMark,
+                             snapshot: &CombinedSnapshot,
                              debruijn: ty::DebruijnIndex,
                              new_vars: &[ty::RegionVid],
                              a_map: &FnvHashMap<ty::BoundRegion, ty::Region>,
@@ -267,7 +277,7 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C
                 return r0;
             }
 
-            let tainted = infcx.region_vars.tainted(mark, r0);
+            let tainted = infcx.tainted_regions(snapshot, r0);
 
             let mut a_r = None;
             let mut b_r = None;
@@ -443,3 +453,86 @@ fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>, value: &T, mut fldr: F) ->
     }))
 }
 
+impl<'a,'tcx> InferCtxtExt<'tcx> 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)
+    }
+
+    fn region_vars_confined_to_snapshot(&self,
+                                        snapshot: &CombinedSnapshot)
+                                        -> Vec<ty::RegionVid>
+    {
+        /*!
+         * Returns the set of region variables that do not affect any
+         * types/regions which existed before `snapshot` was
+         * started. This is used in the sub/lub/glb computations. The
+         * idea here is that when we are computing lub/glb of two
+         * regions, we sometimes create intermediate region variables.
+         * Those region variables may touch some of the skolemized or
+         * other "forbidden" regions we created to replace bound
+         * regions, but they don't really represent an "external"
+         * constraint.
+         *
+         * However, sometimes fresh variables are created for other
+         * purposes too, and those *may* represent an external
+         * constraint. In particular, when a type variable is
+         * instantiated, we create region variables for all the
+         * regions that appear within, and if that type variable
+         * pre-existed the snapshot, then those region variables
+         * represent external constraints.
+         *
+         * An example appears in the unit test
+         * `sub_free_bound_false_infer`.  In this test, we want to
+         * know whether
+         *
+         * ```rust
+         * fn(_#0t) <: for<'a> fn(&'a int)
+         * ```
+         *
+         * Note that the subtype has a type variable. Because the type
+         * variable can't be instantiated with a region that is bound
+         * in the fn signature, this comparison ought to fail. But if
+         * we're not careful, it will succeed.
+         *
+         * The reason is that when we walk through the subtyping
+         * algorith, we begin by replacing `'a` with a skolemized
+         * variable `'0`. We then have `fn(_#0t) <: fn(&'0 int)`. This
+         * can be made true by unifying `_#0t` with `&'0 int`. In the
+         * process, we create a fresh variable for the skolemized
+         * region, `'$0`, and hence we have that `_#0t == &'$0
+         * int`. However, because `'$0` was created during the sub
+         * computation, if we're not careful we will erroneously
+         * assume it is one of the transient region variables
+         * representing a lub/glb internally. Not good.
+         *
+         * To prevent this, we check for type variables which were
+         * unified during the snapshot, and say that any region
+         * variable created during the snapshot but which finds its
+         * way into a type variable is considered to "escape" the
+         * snapshot.
+         */
+
+        let mut region_vars =
+            self.region_vars.vars_created_since_snapshot(&snapshot.region_vars_snapshot);
+
+        let escaping_types =
+            self.type_variables.borrow().types_escaping_snapshot(&snapshot.type_snapshot);
+
+        let escaping_region_vars: FnvHashSet<_> =
+            escaping_types
+            .iter()
+            .flat_map(|&t| ty_fold::collect_regions(self.tcx, &t).into_iter())
+            .collect();
+
+        region_vars.retain(|&region_vid| {
+            let r = ty::ReInfer(ty::ReVar(region_vid));
+            !escaping_region_vars.contains(&r)
+        });
+
+        debug!("region_vars_confined_to_snapshot: region_vars={} escaping_types={}",
+               region_vars.repr(self.tcx),
+               escaping_types.repr(self.tcx));
+
+        region_vars
+    }
+}
diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs
index 14153907ee7..4ad7af713bd 100644
--- a/src/librustc/middle/infer/mod.rs
+++ b/src/librustc/middle/infer/mod.rs
@@ -520,6 +520,7 @@ pub fn uok<'tcx>() -> ures<'tcx> {
     Ok(())
 }
 
+#[must_use = "once you start a snapshot, you should always consume it"]
 pub struct CombinedSnapshot {
     type_snapshot: type_variable::Snapshot,
     int_snapshot: unify::Snapshot<ty::IntVid>,
@@ -629,16 +630,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     pub fn commit_if_ok<T, E, F>(&self, f: F) -> Result<T, E> where
         F: FnOnce() -> Result<T, E>
     {
-        self.commit_unconditionally(move || self.try(move || f()))
+        self.commit_unconditionally(move || self.try(move |_| f()))
     }
 
     /// Execute `f`, unroll bindings on panic
     pub fn try<T, E, F>(&self, f: F) -> Result<T, E> where
-        F: FnOnce() -> Result<T, E>
+        F: FnOnce(&CombinedSnapshot) -> Result<T, E>
     {
         debug!("try()");
         let snapshot = self.start_snapshot();
-        let r = f();
+        let r = f(&snapshot);
         debug!("try() -- r.is_ok() = {}", r.is_ok());
         match r {
             Ok(_) => {
@@ -821,7 +822,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
     pub fn ty_to_string(&self, t: Ty<'tcx>) -> String {
         ty_to_string(self.tcx,
-                     self.resolve_type_vars_if_possible(t))
+                     self.resolve_type_vars_if_possible(&t))
     }
 
     pub fn tys_to_string(&self, ts: &[Ty<'tcx>]) -> String {
@@ -830,7 +831,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     }
 
     pub fn trait_ref_to_string(&self, t: &Rc<ty::TraitRef<'tcx>>) -> String {
-        let t = self.resolve_type_vars_in_trait_ref_if_possible(&**t);
+        let t = self.resolve_type_vars_if_possible(&**t);
         trait_ref_to_string(self.tcx, &t)
     }
 
@@ -867,35 +868,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         }
     }
 
-    pub fn resolve_type_vars_if_possible(&self, typ: Ty<'tcx>) -> Ty<'tcx> {
-        match resolve_type(self,
-                           None,
-                           typ, resolve_nested_tvar | resolve_ivar) {
-          Ok(new_type) => new_type,
-          Err(_) => typ
-        }
-    }
-
-    pub fn resolve_type_vars_in_trait_ref_if_possible(&self,
-                                                      trait_ref: &ty::TraitRef<'tcx>)
-                                                      -> ty::TraitRef<'tcx> {
-        // make up a dummy type just to reuse/abuse the resolve machinery
-        let dummy0 = ty::mk_trait(self.tcx,
-                                  (*trait_ref).clone(),
-                                  ty::region_existential_bound(ty::ReStatic));
-        let dummy1 = self.resolve_type_vars_if_possible(dummy0);
-        match dummy1.sty {
-            ty::ty_trait(box ty::TyTrait { ref principal, .. }) => {
-                (*principal).clone()
-            }
-            _ => {
-                self.tcx.sess.bug(
-                    format!("resolve_type_vars_if_possible() yielded {} \
-                             when supplied with {}",
-                            self.ty_to_string(dummy0),
-                            self.ty_to_string(dummy1)).as_slice());
-            }
-        }
+    pub fn resolve_type_vars_if_possible<T:TypeFoldable<'tcx>>(&self, value: &T) -> T {
+        let mut r = resolve::DeepTypeResolver::new(self);
+        value.fold_with(&mut r)
     }
 
     // [Note-Type-error-reporting]
@@ -929,9 +904,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     {
         debug!("hi! expected_ty = {}, actual_ty = {}", expected_ty, actual_ty);
 
-        let resolved_expected = expected_ty.map(|e_ty| {
-            self.resolve_type_vars_if_possible(e_ty)
-        });
+        let resolved_expected = expected_ty.map(|e_ty| self.resolve_type_vars_if_possible(&e_ty));
 
         match resolved_expected {
             Some(t) if ty::type_is_error(t) => (),
@@ -958,7 +931,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                                  err: Option<&ty::type_err<'tcx>>) where
         M: FnOnce(String) -> String,
     {
-        let actual_ty = self.resolve_type_vars_if_possible(actual_ty);
+        let actual_ty = self.resolve_type_vars_if_possible(&actual_ty);
 
         // Don't report an error if actual type is ty_err.
         if ty::type_is_error(actual_ty) {
diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs
index ca2860ae6b3..fef87c92067 100644
--- a/src/librustc/middle/infer/region_inference/mod.rs
+++ b/src/librustc/middle/infer/region_inference/mod.rs
@@ -81,7 +81,6 @@ impl Copy for TwoRegions {}
 pub enum UndoLogEntry {
     OpenSnapshot,
     CommitedSnapshot,
-    Mark,
     AddVar(RegionVid),
     AddConstraint(Constraint),
     AddVerify(uint),
@@ -225,19 +224,11 @@ pub struct RegionVarBindings<'a, 'tcx: 'a> {
 }
 
 #[deriving(Show)]
+#[allow(missing_copy_implementations)]
 pub struct RegionSnapshot {
     length: uint
 }
 
-impl Copy for RegionSnapshot {}
-
-#[deriving(Show)]
-pub struct RegionMark {
-    length: uint
-}
-
-impl Copy for RegionMark {}
-
 impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
     pub fn new(tcx: &'a ty::ctxt<'tcx>) -> RegionVarBindings<'a, 'tcx> {
         RegionVarBindings {
@@ -266,13 +257,6 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
         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, snapshot: RegionSnapshot) {
         debug!("RegionVarBindings: commit({})", snapshot.length);
         assert!(self.undo_log.borrow().len() > snapshot.length);
@@ -296,7 +280,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
                 OpenSnapshot => {
                     panic!("Failure to observe stack discipline");
                 }
-                Mark | CommitedSnapshot => { }
+                CommitedSnapshot => { }
                 AddVar(vid) => {
                     let mut var_origins = self.var_origins.borrow_mut();
                     var_origins.pop().unwrap();
@@ -597,8 +581,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
         ReInfer(ReVar(c))
     }
 
-    pub fn vars_created_since_mark(&self, mark: RegionMark)
-                                   -> Vec<RegionVid>
+    pub fn vars_created_since_snapshot(&self, mark: &RegionSnapshot)
+                                       -> Vec<RegionVid>
     {
         self.undo_log.borrow()
             .slice_from(mark.length)
@@ -613,7 +597,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
     /// Computes all regions that have been related to `r0` in any 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.
-    pub fn tainted(&self, mark: RegionMark, r0: Region) -> Vec<Region> {
+    pub fn tainted(&self, mark: &RegionSnapshot, r0: Region) -> Vec<Region> {
         debug!("tainted(mark={}, r0={})", mark, r0.repr(self.tcx));
         let _indenter = indenter();
 
@@ -668,7 +652,6 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
                         }
                     }
                     &AddCombination(..) |
-                    &Mark |
                     &AddVar(..) |
                     &OpenSnapshot |
                     &CommitedSnapshot => {
diff --git a/src/librustc/middle/infer/resolve.rs b/src/librustc/middle/infer/resolve.rs
index eaf363ffc74..5edf78a474b 100644
--- a/src/librustc/middle/infer/resolve.rs
+++ b/src/librustc/middle/infer/resolve.rs
@@ -258,3 +258,38 @@ impl<'a, 'tcx> ResolveState<'a, 'tcx> {
         }
     }
 }
+
+///////////////////////////////////////////////////////////////////////////
+/// DEEP TYPE RESOLVER
+///
+/// This kind of resolver can be used at any time. It simply replaces
+/// type variables that have been unified with the things they have
+/// been unified with (similar to `shallow_resolve`, but deep). This is
+/// useful for printing messages etc but also required at various
+/// points for correctness.
+pub struct DeepTypeResolver<'a, 'tcx:'a> {
+    infcx: &'a InferCtxt<'a, 'tcx>,
+}
+
+impl<'a, 'tcx> DeepTypeResolver<'a, 'tcx> {
+    pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> DeepTypeResolver<'a, 'tcx> {
+        DeepTypeResolver { infcx: infcx }
+    }
+}
+
+impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for DeepTypeResolver<'a, 'tcx> {
+    fn tcx(&self) -> &ty::ctxt<'tcx> {
+        self.infcx.tcx
+    }
+
+    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+        if !ty::type_has_ty_infer(t) {
+            t // micro-optimize -- if there is nothing in this type that this fold affects...
+        } else {
+            let t0 = self.infcx.shallow_resolve(t);
+            ty_fold::super_fold_ty(self, t0)
+        }
+    }
+}
+
+
diff --git a/src/librustc/middle/infer/type_variable.rs b/src/librustc/middle/infer/type_variable.rs
index 766e930486c..0d7f542535c 100644
--- a/src/librustc/middle/infer/type_variable.rs
+++ b/src/librustc/middle/infer/type_variable.rs
@@ -13,7 +13,9 @@ use self::TypeVariableValue::*;
 use self::UndoEntry::*;
 
 use middle::ty::{mod, Ty};
+use std::cmp::min;
 use std::mem;
+use std::uint;
 use util::snapshot_vec as sv;
 
 pub struct TypeVariableTable<'tcx> {
@@ -78,7 +80,6 @@ impl<'tcx> TypeVariableTable<'tcx> {
     ///
     /// Precondition: neither `a` nor `b` are known.
     pub fn relate_vars(&mut self, a: ty::TyVid, dir: RelationDir, b: ty::TyVid) {
-
         if a != b {
             self.relations(a).push((dir, b));
             self.relations(b).push((dir.opposite(), a));
@@ -151,6 +152,49 @@ impl<'tcx> TypeVariableTable<'tcx> {
     pub fn commit(&mut self, s: Snapshot) {
         self.values.commit(s.snapshot);
     }
+
+    pub fn types_escaping_snapshot(&self, s: &Snapshot) -> Vec<Ty<'tcx>> {
+        /*!
+         * Find the set of type variables that existed *before* `s`
+         * but which have only been unified since `s` started, and
+         * return the types with which they were unified. So if we had
+         * a type variable `V0`, then we started the snapshot, then we
+         * created a type variable `V1`, unifed `V0` with `T0`, and
+         * unified `V1` with `T1`, this function would return `{T0}`.
+         */
+
+        let mut new_elem_threshold = uint::MAX;
+        let mut escaping_types = Vec::new();
+        let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot);
+        debug!("actions_since_snapshot.len() = {}", actions_since_snapshot.len());
+        for action in actions_since_snapshot.iter() {
+            match *action {
+                sv::UndoLog::NewElem(index) => {
+                    // if any new variables were created during the
+                    // snapshot, remember the lower index (which will
+                    // always be the first one we see). Note that this
+                    // action must precede those variables being
+                    // specified.
+                    new_elem_threshold = min(new_elem_threshold, index);
+                    debug!("NewElem({}) new_elem_threshold={}", index, new_elem_threshold);
+                }
+
+                sv::UndoLog::Other(SpecifyVar(vid, _)) => {
+                    if vid.index < new_elem_threshold {
+                        // quick check to see if this variable was
+                        // created since the snapshot started or not.
+                        let escaping_type = self.probe(vid).unwrap();
+                        escaping_types.push(escaping_type);
+                    }
+                    debug!("SpecifyVar({}) new_elem_threshold={}", vid, new_elem_threshold);
+                }
+
+                _ => { }
+            }
+        }
+
+        escaping_types
+    }
 }
 
 impl<'tcx> sv::SnapshotVecDelegate<TypeVariableData<'tcx>,UndoEntry> for Delegate {
diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs
index 4877512ce58..3da9fba0ee8 100644
--- a/src/librustc/middle/ty_fold.rs
+++ b/src/librustc/middle/ty_fold.rs
@@ -790,6 +790,17 @@ impl<'a, 'tcx, F> RegionFolder<'a, 'tcx, F> where F: FnMut(ty::Region, uint) ->
     }
 }
 
+pub fn collect_regions<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> Vec<ty::Region>
+    where T : TypeFoldable<'tcx>
+{
+    let mut vec = Vec::new();
+    {
+        let mut folder = RegionFolder::new(tcx, |r, _| { vec.push(r); r });
+        value.fold_with(&mut folder);
+    }
+    vec
+}
+
 impl<'a, 'tcx, F> TypeFolder<'tcx> for RegionFolder<'a, 'tcx, F> where
     F: FnMut(ty::Region, uint) -> ty::Region,
 {
diff --git a/src/librustc/util/snapshot_vec.rs b/src/librustc/util/snapshot_vec.rs
index e80e8dc5351..749c39d7a6b 100644
--- a/src/librustc/util/snapshot_vec.rs
+++ b/src/librustc/util/snapshot_vec.rs
@@ -23,7 +23,7 @@ use self::UndoLog::*;
 use std::mem;
 
 #[deriving(PartialEq)]
-enum UndoLog<T,U> {
+pub enum UndoLog<T,U> {
     /// Indicates where a snapshot started.
     OpenSnapshot,
 
@@ -113,6 +113,12 @@ impl<T,U,D:SnapshotVecDelegate<T,U>> SnapshotVec<T,U,D> {
         Snapshot { length: length }
     }
 
+    pub fn actions_since_snapshot(&self,
+                                  snapshot: &Snapshot)
+                                  -> &[UndoLog<T,U>] {
+        self.undo_log[snapshot.length..]
+    }
+
     fn assert_open_snapshot(&self, snapshot: &Snapshot) {
         // Or else there was a failure to follow a stack discipline:
         assert!(self.undo_log.len() > snapshot.length);
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 943650ce8a6..14d36432afa 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -503,6 +503,26 @@ fn sub_free_bound_false_infer() {
 }
 
 #[test]
+fn lub_free_bound_infer() {
+    //! Test result of:
+    //!
+    //!     LUB(fn(_#1), for<'b> fn(&'b int))
+    //!
+    //! This should yield `fn(&'_ int)`. We check
+    //! that it yields `fn(&'x int)` for some free `'x`,
+    //! anyhow.
+
+    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
+        let t_infer1 = env.infcx.next_ty_var();
+        let t_rptr_bound1 = env.t_rptr_late_bound(1);
+        let t_rptr_free1 = env.t_rptr_free(0, 1);
+        env.check_lub(env.t_fn(&[t_infer1], ty::mk_int()),
+                      env.t_fn(&[t_rptr_bound1], ty::mk_int()),
+                      env.t_fn(&[t_rptr_free1], ty::mk_int()));
+    });
+}
+
+#[test]
 fn lub_bound_bound() {
     test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
         let t_rptr_bound1 = env.t_rptr_late_bound(1);
@@ -606,6 +626,28 @@ fn glb_bound_free() {
 }
 
 #[test]
+fn glb_bound_free_infer() {
+    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
+        let t_rptr_bound1 = env.t_rptr_late_bound(1);
+        let t_infer1 = env.infcx.next_ty_var();
+
+        // compute GLB(fn(_) -> int, for<'b> fn(&'b int) -> int),
+        // which should yield for<'b> fn(&'b int) -> int
+        env.check_glb(env.t_fn(&[t_rptr_bound1], ty::mk_int()),
+                      env.t_fn(&[t_infer1], ty::mk_int()),
+                      env.t_fn(&[t_rptr_bound1], ty::mk_int()));
+
+        // as a side-effect, computing GLB should unify `_` with
+        // `&'_ int`
+        let t_resolve1 = env.infcx.shallow_resolve(t_infer1);
+        match t_resolve1.sty {
+            ty::ty_rptr(..) => { }
+            _ => { panic!("t_resolve1={}", t_resolve1.repr(env.infcx.tcx)); }
+        }
+    })
+}
+
+#[test]
 fn glb_bound_static() {
     test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
         let t_rptr_bound1 = env.t_rptr_late_bound(1);
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index e3fec2c8b1d..a4fee8573c5 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -196,7 +196,7 @@ fn deduce_unboxed_closure_expectations_from_trait_ref<'a,'tcx>(
     debug!("found object type {}", kind);
 
     let arg_param_ty = *trait_ref.substs.types.get(subst::TypeSpace, 0);
-    let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(arg_param_ty);
+    let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(&arg_param_ty);
     debug!("arg_param_ty {}", arg_param_ty.repr(tcx));
 
     let input_tys = match arg_param_ty.sty {
@@ -206,7 +206,7 @@ fn deduce_unboxed_closure_expectations_from_trait_ref<'a,'tcx>(
     debug!("input_tys {}", input_tys.repr(tcx));
 
     let ret_param_ty = *trait_ref.substs.types.get(subst::TypeSpace, 1);
-    let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(ret_param_ty);
+    let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(&ret_param_ty);
     debug!("ret_param_ty {}", ret_param_ty.repr(tcx));
 
     let fn_sig = ty::FnSig {
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index d97a9c9e39b..ac7bc81b2f8 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -100,7 +100,7 @@ pub fn lookup<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
            call_expr.repr(fcx.tcx()),
            self_expr.repr(fcx.tcx()));
 
-    let self_ty = fcx.infcx().resolve_type_vars_if_possible(self_ty);
+    let self_ty = fcx.infcx().resolve_type_vars_if_possible(&self_ty);
     let pick = try!(probe::probe(fcx, span, method_name, self_ty, call_expr.id));
     Ok(confirm::confirm(fcx, span, self_expr, call_expr, self_ty, pick, supplied_method_types))
 }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index def82ecd6c8..ea33153f3b1 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1638,7 +1638,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     pub fn default_diverging_type_variables_to_nil(&self) {
         for (_, &ref ty) in self.inh.node_types.borrow_mut().iter_mut() {
-            if self.infcx().type_var_diverges(self.infcx().resolve_type_vars_if_possible(*ty)) {
+            if self.infcx().type_var_diverges(self.infcx().resolve_type_vars_if_possible(ty)) {
                 demand::eqtype(self, codemap::DUMMY_SP, *ty, ty::mk_nil(self.tcx()));
             }
         }
@@ -2486,7 +2486,7 @@ fn lookup_method_for_for_loop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     let method_type = match method {
         Some(ref method) => method.ty,
         None => {
-            let true_expr_type = fcx.infcx().resolve_type_vars_if_possible(expr_type);
+            let true_expr_type = fcx.infcx().resolve_type_vars_if_possible(&expr_type);
 
             if !ty::type_is_error(true_expr_type) {
                 let ty_string = fcx.infcx().ty_to_string(true_expr_type);
@@ -3976,7 +3976,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
         vtable::select_new_fcx_obligations(fcx);
 
         debug!("ExprForLoop each item has type {}",
-               fcx.infcx().resolve_type_vars_if_possible(typ).repr(fcx.tcx()));
+               fcx.infcx().resolve_type_vars_if_possible(&typ).repr(fcx.tcx()));
 
         let pcx = pat_ctxt {
             fcx: fcx,
@@ -4371,11 +4371,11 @@ impl<'tcx> Expectation<'tcx> {
             }
             ExpectCastableToType(t) => {
                 ExpectCastableToType(
-                    fcx.infcx().resolve_type_vars_if_possible(t))
+                    fcx.infcx().resolve_type_vars_if_possible(&t))
             }
             ExpectHasType(t) => {
                 ExpectHasType(
-                    fcx.infcx().resolve_type_vars_if_possible(t))
+                    fcx.infcx().resolve_type_vars_if_possible(&t))
             }
         }
     }
diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs
index 415a3d53fb2..664705c89ab 100644
--- a/src/librustc_typeck/check/vtable.rs
+++ b/src/librustc_typeck/check/vtable.rs
@@ -331,7 +331,7 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             match obligation.trait_ref {
                 ty::Predicate::Trait(ref trait_ref) => {
                     let trait_ref =
-                        fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(&**trait_ref);
+                        fcx.infcx().resolve_type_vars_if_possible(&**trait_ref);
                     fcx.tcx().sess.span_err(
                         obligation.cause.span,
                         format!(
@@ -341,8 +341,8 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                 }
 
                 ty::Predicate::Equate(a, b) => {
-                    let a = fcx.infcx().resolve_type_vars_if_possible(a);
-                    let b = fcx.infcx().resolve_type_vars_if_possible(b);
+                    let a = fcx.infcx().resolve_type_vars_if_possible(&a);
+                    let b = fcx.infcx().resolve_type_vars_if_possible(&b);
                     fcx.tcx().sess.span_err(
                         obligation.cause.span,
                         format!(
@@ -373,8 +373,7 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             match obligation.trait_ref {
                 ty::Predicate::Trait(ref trait_ref) => {
                     let trait_ref =
-                        fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(
-                            &**trait_ref);
+                        fcx.infcx().resolve_type_vars_if_possible(&**trait_ref);
                     if !ty::type_is_error(trait_ref.self_ty()) {
                         fcx.tcx().sess.span_err(
                             obligation.cause.span,
@@ -387,8 +386,8 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                 }
 
                 ty::Predicate::Equate(a, b) => {
-                    let a = fcx.infcx().resolve_type_vars_if_possible(a);
-                    let b = fcx.infcx().resolve_type_vars_if_possible(b);
+                    let a = fcx.infcx().resolve_type_vars_if_possible(&a);
+                    let b = fcx.infcx().resolve_type_vars_if_possible(&b);
                     let err = infer::can_mk_eqty(fcx.infcx(), a, b).unwrap_err();
                     fcx.tcx().sess.span_err(
                         obligation.cause.span,
@@ -413,10 +412,10 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         }
         OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, ref e) => {
             let expected_trait_ref =
-                fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(
+                fcx.infcx().resolve_type_vars_if_possible(
                     &**expected_trait_ref);
             let actual_trait_ref =
-                fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(
+                fcx.infcx().resolve_type_vars_if_possible(
                     &**actual_trait_ref);
             if !ty::type_is_error(actual_trait_ref.self_ty()) {
                 fcx.tcx().sess.span_err(
@@ -443,7 +442,7 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 
     let trait_ref = match obligation.trait_ref {
         ty::Predicate::Trait(ref trait_ref) => {
-            fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(&**trait_ref)
+            fcx.infcx().resolve_type_vars_if_possible(&**trait_ref)
         }
         _ => {
             fcx.tcx().sess.span_bug(
diff --git a/src/test/compile-fail/bad-match.rs b/src/test/compile-fail/bad-match.rs
index 39c3ed3e2a3..728b577df1d 100644
--- a/src/test/compile-fail/bad-match.rs
+++ b/src/test/compile-fail/bad-match.rs
@@ -14,3 +14,6 @@ fn main() {
   let int x = 5;
   match x;
 }
+
+fn main() {
+}