about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/infer/higher_ranked/mod.rs507
-rw-r--r--src/librustc/infer/lexical_region_resolve/mod.rs41
-rw-r--r--src/librustc/infer/mod.rs86
-rw-r--r--src/librustc/infer/region_constraints/mod.rs31
-rw-r--r--src/librustc/infer/region_constraints/taint.rs85
-rw-r--r--src/librustc/traits/auto_trait.rs8
-rw-r--r--src/librustc/traits/error_reporting.rs9
-rw-r--r--src/librustc/traits/fulfill.rs6
-rw-r--r--src/librustc/traits/project.rs48
-rw-r--r--src/librustc/traits/select.rs122
10 files changed, 144 insertions, 799 deletions
diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs
index 3a3a21d0f1d..709e8c0ba9b 100644
--- a/src/librustc/infer/higher_ranked/mod.rs
+++ b/src/librustc/infer/higher_ranked/mod.rs
@@ -1,31 +1,23 @@
 //! Helper routines for higher-ranked things. See the `doc` module at
 //! the end of the file for details.
 
-use super::{CombinedSnapshot,
-            InferCtxt,
-            HigherRankedType,
-            SubregionOrigin,
-            PlaceholderMap};
 use super::combine::CombineFields;
-use super::region_constraints::{TaintDirections};
+use super::{HigherRankedType, InferCtxt, PlaceholderMap};
 
-use ty::{self, TyCtxt, Binder, TypeFoldable};
-use ty::error::TypeError;
 use ty::relate::{Relate, RelateResult, TypeRelation};
-use syntax_pos::Span;
-use util::nodemap::{FxHashMap, FxHashSet};
-
-pub struct HrMatchResult<U> {
-    pub value: U,
-}
+use ty::{self, Binder, TypeFoldable};
 
 impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
-    pub fn higher_ranked_sub<T>(&mut self, a: &Binder<T>, b: &Binder<T>, a_is_expected: bool)
-                                -> RelateResult<'tcx, Binder<T>>
-        where T: Relate<'tcx>
+    pub fn higher_ranked_sub<T>(
+        &mut self,
+        a: &Binder<T>,
+        b: &Binder<T>,
+        a_is_expected: bool,
+    ) -> RelateResult<'tcx, Binder<T>>
+    where
+        T: Relate<'tcx>,
     {
-        debug!("higher_ranked_sub(a={:?}, b={:?})",
-               a, b);
+        debug!("higher_ranked_sub(a={:?}, b={:?})", a, b);
 
         // Rather than checking the subtype relationship between `a` and `b`
         // as-is, we need to do some extra work here in order to make sure
@@ -35,279 +27,37 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
         // please see the large comment at the end of the file in the (inlined) module
         // `doc`.
 
-        // Start a snapshot so we can examine "all bindings that were
-        // created as part of this type comparison".
-        return self.infcx.commit_if_ok(|snapshot| {
-            let span = self.trace.cause.span;
-
-            // First, we instantiate each bound region in the supertype with a
-            // fresh placeholder region.
-            let (b_prime, placeholder_map) =
-                self.infcx.replace_bound_vars_with_placeholders(b);
-
-            // Next, we instantiate each bound region in the subtype
-            // with a fresh region variable. These region variables --
-            // but no other pre-existing region variables -- can name
-            // the placeholders.
-            let (a_prime, _) = self.infcx.replace_bound_vars_with_fresh_vars(
-                span,
-                HigherRankedType,
-                a
-            );
-
-            debug!("a_prime={:?}", a_prime);
-            debug!("b_prime={:?}", b_prime);
-
-            // Compare types now that bound regions have been replaced.
-            let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?;
-
-            // Presuming type comparison succeeds, we need to check
-            // that the placeholder regions do not "leak".
-            self.infcx.leak_check(!a_is_expected, span, &placeholder_map, snapshot)?;
-
-            // We are finished with the placeholder regions now so pop
-            // them off.
-            self.infcx.pop_placeholders(placeholder_map, snapshot);
-
-            debug!("higher_ranked_sub: OK result={:?}", result);
-
-            Ok(ty::Binder::bind(result))
-        });
-    }
-
-    /// The value consists of a pair `(t, u)` where `t` is the
-    /// *matcher* and `u` is a *value*. The idea is to find a
-    /// substitution `S` such that `S(t) == b`, and then return
-    /// `S(u)`. In other words, find values for the late-bound regions
-    /// in `a` that can make `t == b` and then replace the LBR in `u`
-    /// with those values.
-    ///
-    /// This routine is (as of this writing) used in trait matching,
-    /// particularly projection.
-    ///
-    /// NB. It should not happen that there are LBR appearing in `U`
-    /// that do not appear in `T`. If that happens, those regions are
-    /// unconstrained, and this routine replaces them with `'static`.
-    pub fn higher_ranked_match<T, U>(&mut self,
-                                     a_pair: &Binder<(T, U)>,
-                                     b_match: &T,
-                                     a_is_expected: bool)
-                                     -> RelateResult<'tcx, HrMatchResult<U>>
-        where T: Relate<'tcx>,
-              U: TypeFoldable<'tcx>
-    {
-        debug!("higher_ranked_match(a={:?}, b={:?})",
-               a_pair, b_match);
-
-        // Start a snapshot so we can examine "all bindings that were
-        // created as part of this type comparison".
-        return self.infcx.commit_if_ok(|snapshot| {
-            // First, we instantiate each bound region in the matcher
-            // with a placeholder region.
-            let ((a_match, a_value), placeholder_map) =
-                self.infcx.replace_bound_vars_with_placeholders(a_pair);
+        let span = self.trace.cause.span;
 
-            debug!("higher_ranked_match: a_match={:?}", a_match);
-            debug!("higher_ranked_match: placeholder_map={:?}", placeholder_map);
+        // First, we instantiate each bound region in the supertype with a
+        // fresh placeholder region.
+        let (b_prime, _) = self.infcx.replace_bound_vars_with_placeholders(b);
 
-            // Equate types now that bound regions have been replaced.
-            self.equate(a_is_expected).relate(&a_match, &b_match)?;
+        // Next, we instantiate each bound region in the subtype
+        // with a fresh region variable. These region variables --
+        // but no other pre-existing region variables -- can name
+        // the placeholders.
+        let (a_prime, _) =
+            self.infcx
+                .replace_bound_vars_with_fresh_vars(span, HigherRankedType, a);
 
-            // Map each placeholder region to a vector of other regions that it
-            // must be equated with. (Note that this vector may include other
-            // placeholder regions from `placeholder_map`.)
-            let placeholder_resolution_map: FxHashMap<_, _> =
-                placeholder_map
-                .iter()
-                .map(|(&br, &placeholder)| {
-                    let tainted_regions =
-                        self.infcx.tainted_regions(snapshot,
-                                                   placeholder,
-                                                   TaintDirections::incoming()); // [1]
+        debug!("a_prime={:?}", a_prime);
+        debug!("b_prime={:?}", b_prime);
 
-                    // [1] this routine executes after the placeholder
-                    // regions have been *equated* with something
-                    // else, so examining the incoming edges ought to
-                    // be enough to collect all constraints
+        // Compare types now that bound regions have been replaced.
+        let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?;
 
-                    (placeholder, (br, tainted_regions))
-                })
-                .collect();
+        debug!("higher_ranked_sub: OK result={:?}", result);
 
-            // For each placeholder region, pick a representative -- which can
-            // be any region from the sets above, except for other members of
-            // `placeholder_map`. There should always be a representative if things
-            // are properly well-formed.
-            let placeholder_representatives: FxHashMap<_, _> =
-                placeholder_resolution_map
-                .iter()
-                .map(|(&placeholder, &(_, ref regions))| {
-                    let representative =
-                        regions.iter()
-                               .filter(|&&r| !placeholder_resolution_map.contains_key(r))
-                               .cloned()
-                               .next()
-                               .unwrap_or_else(|| {
-                                   bug!("no representative region for `{:?}` in `{:?}`",
-                                        placeholder, regions)
-                               });
-
-                    (placeholder, representative)
-                })
-                .collect();
-
-            // Equate all the members of each placeholder set with the
-            // representative.
-            for (placeholder, &(_br, ref regions)) in &placeholder_resolution_map {
-                let representative = &placeholder_representatives[placeholder];
-                debug!("higher_ranked_match: \
-                        placeholder={:?} representative={:?} regions={:?}",
-                       placeholder, representative, regions);
-                for region in regions.iter()
-                                     .filter(|&r| !placeholder_resolution_map.contains_key(r))
-                                     .filter(|&r| r != representative)
-                {
-                    let origin = SubregionOrigin::Subtype(self.trace.clone());
-                    self.infcx.borrow_region_constraints()
-                              .make_eqregion(origin,
-                                             *representative,
-                                             *region);
-                }
-            }
-
-            // Replace the placeholder regions appearing in value with
-            // their representatives
-            let a_value =
-                fold_regions_in(
-                    self.tcx(),
-                    &a_value,
-                    |r, _| placeholder_representatives.get(&r).cloned().unwrap_or(r));
-
-            debug!("higher_ranked_match: value={:?}", a_value);
-
-            // We are now done with these placeholder variables.
-            self.infcx.pop_placeholders(placeholder_map, snapshot);
-
-            Ok(HrMatchResult { value: a_value })
-        });
+        Ok(ty::Binder::bind(result))
     }
 }
 
-fn fold_regions_in<'a, 'gcx, 'tcx, T, F>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                                         unbound_value: &T,
-                                         mut fldr: F)
-                                         -> T
-    where T: TypeFoldable<'tcx>,
-          F: FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx>,
-{
-    tcx.fold_regions(unbound_value, &mut false, |region, current_depth| {
-        // we should only be encountering "escaping" late-bound regions here,
-        // because the ones at the current level should have been replaced
-        // with fresh variables
-        assert!(match *region {
-            ty::ReLateBound(..) => false,
-            _ => true
-        });
-
-        fldr(region, current_depth)
-    })
-}
-
 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
-    fn tainted_regions(&self,
-                       snapshot: &CombinedSnapshot<'a, 'tcx>,
-                       r: ty::Region<'tcx>,
-                       directions: TaintDirections)
-                       -> FxHashSet<ty::Region<'tcx>> {
-        self.borrow_region_constraints().tainted(
-            self.tcx,
-            &snapshot.region_constraints_snapshot,
-            r,
-            directions)
-    }
-
-    fn region_vars_confined_to_snapshot(&self,
-                                        snapshot: &CombinedSnapshot<'a, 'tcx>)
-                                        -> 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 placeholder 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
-         * algorithm, we begin by replacing `'a` with a placeholder
-         * variable `'1`. We then have `fn(_#0t) <: fn(&'1 int)`. This
-         * can be made true by unifying `_#0t` with `&'1 int`. In the
-         * process, we create a fresh variable for the placeholder
-         * region, `'$2`, and hence we have that `_#0t == &'$2
-         * int`. However, because `'$2` 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.borrow_region_constraints().vars_created_since_snapshot(
-                &snapshot.region_constraints_snapshot);
-
-        let escaping_types =
-            self.type_variables.borrow_mut().types_escaping_snapshot(&snapshot.type_snapshot);
-
-        let mut escaping_region_vars = FxHashSet::default();
-        for ty in &escaping_types {
-            self.tcx.collect_regions(ty, &mut escaping_region_vars);
-        }
-
-        region_vars.retain(|&region_vid| {
-            let r = ty::ReVar(region_vid);
-            !escaping_region_vars.contains(&r)
-        });
-
-        debug!("region_vars_confined_to_snapshot: region_vars={:?} escaping_types={:?}",
-               region_vars,
-               escaping_types);
-
-        region_vars
-    }
-
     /// Replace all regions (resp. types) bound by `binder` with placeholder
     /// regions (resp. types) and return a map indicating which bound-region
-    /// was replaced with what placeholder region. This is the first step of
-    /// checking subtyping when higher-ranked things are involved.
+    /// placeholder region. This is the first step of checking subtyping
+    /// when higher-ranked things are involved.
     ///
     /// **Important:** you must call this function from within a snapshot.
     /// Moreover, before committing the snapshot, you must eventually call
@@ -354,201 +104,4 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
         (result, map)
     }
-
-    /// Searches the region constraints created since `snapshot` was started
-    /// and checks to determine whether any of the placeholder regions created
-    /// in `placeholder_map` would "escape" -- meaning that they are related to
-    /// other regions in some way. If so, the higher-ranked subtyping doesn't
-    /// hold. See `README.md` for more details.
-    pub fn leak_check(&self,
-                      overly_polymorphic: bool,
-                      _span: Span,
-                      placeholder_map: &PlaceholderMap<'tcx>,
-                      snapshot: &CombinedSnapshot<'a, 'tcx>)
-                      -> RelateResult<'tcx, ()>
-    {
-        debug!("leak_check: placeholder_map={:?}",
-               placeholder_map);
-
-        // If the user gave `-Zno-leak-check`, then skip the leak
-        // check completely. This is wildly unsound and also not
-        // unlikely to cause an ICE or two. It is intended for use
-        // only during a transition period, in which the MIR typeck
-        // uses the "universe-style" check, and the rest of typeck
-        // uses the more conservative leak check.  Since the leak
-        // check is more conservative, we can't test the
-        // universe-style check without disabling it.
-        if self.tcx.sess.opts.debugging_opts.no_leak_check {
-            return Ok(());
-        }
-
-        let new_vars = self.region_vars_confined_to_snapshot(snapshot);
-        for (&placeholder_br, &placeholder) in placeholder_map {
-            // The inputs to a placeholder variable can only
-            // be itself or other new variables.
-            let incoming_taints = self.tainted_regions(snapshot,
-                                                       placeholder,
-                                                       TaintDirections::both());
-            for &tainted_region in &incoming_taints {
-                // Each placeholder should only be relatable to itself
-                // or new variables:
-                match *tainted_region {
-                    ty::ReVar(vid) => {
-                        if new_vars.contains(&vid) {
-                            continue;
-                        }
-                    }
-                    _ => {
-                        if tainted_region == placeholder { continue; }
-                    }
-                };
-
-                debug!("{:?} (which replaced {:?}) is tainted by {:?}",
-                       placeholder,
-                       placeholder_br,
-                       tainted_region);
-
-                return Err(if overly_polymorphic {
-                    debug!("Overly polymorphic!");
-                    TypeError::RegionsOverlyPolymorphic(placeholder_br, tainted_region)
-                } else {
-                    debug!("Not as polymorphic!");
-                    TypeError::RegionsInsufficientlyPolymorphic(placeholder_br, tainted_region)
-                })
-            }
-        }
-
-        Ok(())
-    }
-
-    /// This code converts from placeholder regions back to late-bound
-    /// regions. It works by replacing each region in the taint set of a
-    /// placeholder region with a bound-region. The bound region will be bound
-    /// by the outer-most binder in `value`; the caller must ensure that there is
-    /// such a binder and it is the right place.
-    ///
-    /// This routine is only intended to be used when the leak-check has
-    /// passed; currently, it's used in the trait matching code to create
-    /// a set of nested obligations from an impl that matches against
-    /// something higher-ranked.  More details can be found in
-    /// `librustc/middle/traits/README.md`.
-    ///
-    /// As a brief example, consider the obligation `for<'a> Fn(&'a int)
-    /// -> &'a int`, and the impl:
-    ///
-    ///     impl<A,R> Fn<A,R> for SomethingOrOther
-    ///         where A : Clone
-    ///     { ... }
-    ///
-    /// Here we will have replaced `'a` with a placeholder region
-    /// `'0`. This means that our substitution will be `{A=>&'0
-    /// int, R=>&'0 int}`.
-    ///
-    /// When we apply the substitution to the bounds, we will wind up with
-    /// `&'0 int : Clone` as a predicate. As a last step, we then go and
-    /// replace `'0` with a late-bound region `'a`.  The depth is matched
-    /// to the depth of the predicate, in this case 1, so that the final
-    /// predicate is `for<'a> &'a int : Clone`.
-    pub fn plug_leaks<T>(&self,
-                         placeholder_map: PlaceholderMap<'tcx>,
-                         snapshot: &CombinedSnapshot<'a, 'tcx>,
-                         value: T) -> T
-        where T : TypeFoldable<'tcx>
-    {
-        debug!("plug_leaks(placeholder_map={:?}, value={:?})",
-               placeholder_map,
-               value);
-
-        if placeholder_map.is_empty() {
-            return value;
-        }
-
-        // Compute a mapping from the "taint set" of each placeholder
-        // region back to the `ty::BoundRegion` that it originally
-        // represented. Because `leak_check` passed, we know that
-        // these taint sets are mutually disjoint.
-        let inv_placeholder_map: FxHashMap<ty::Region<'tcx>, ty::BoundRegion> =
-            placeholder_map
-            .iter()
-            .flat_map(|(&placeholder_br, &placeholder)| {
-                self.tainted_regions(snapshot, placeholder, TaintDirections::both())
-                    .into_iter()
-                    .map(move |tainted_region| (tainted_region, placeholder_br))
-            })
-            .collect();
-
-        debug!("plug_leaks: inv_placeholder_map={:?}",
-               inv_placeholder_map);
-
-        // Remove any instantiated type variables from `value`; those can hide
-        // references to regions from the `fold_regions` code below.
-        let value = self.resolve_type_vars_if_possible(&value);
-
-        // Map any placeholder byproducts back to a late-bound
-        // region. Put that late-bound region at whatever the outermost
-        // binder is that we encountered in `value`. The caller is
-        // responsible for ensuring that (a) `value` contains at least one
-        // binder and (b) that binder is the one we want to use.
-        let result = self.tcx.fold_regions(&value, &mut false, |r, current_depth| {
-            match inv_placeholder_map.get(&r) {
-                None => r,
-                Some(br) => {
-                    // It is the responsibility of the caller to ensure
-                    // that each placeholder region appears within a
-                    // binder. In practice, this routine is only used by
-                    // trait checking, and all of the placeholder regions
-                    // appear inside predicates, which always have
-                    // binders, so this assert is satisfied.
-                    assert!(current_depth > ty::INNERMOST);
-
-                    // since leak-check passed, this placeholder region
-                    // should only have incoming edges from variables
-                    // (which ought not to escape the snapshot, but we
-                    // don't check that) or itself
-                    assert!(
-                        match *r {
-                            ty::ReVar(_) => true,
-                            ty::RePlaceholder(index) => index.name == *br,
-                            _ => false,
-                        },
-                        "leak-check would have us replace {:?} with {:?}",
-                        r, br);
-
-                    self.tcx.mk_region(ty::ReLateBound(
-                        current_depth.shifted_out(1),
-                        br.clone(),
-                    ))
-                }
-            }
-        });
-
-        self.pop_placeholders(placeholder_map, snapshot);
-
-        debug!("plug_leaks: result={:?}", result);
-
-        result
-    }
-
-    /// Pops the placeholder regions found in `placeholder_map` from the region
-    /// inference context. Whenever you create placeholder regions via
-    /// `replace_bound_vars_with_placeholders`, they must be popped before you
-    /// commit the enclosing snapshot (if you do not commit, e.g., within a
-    /// probe or as a result of an error, then this is not necessary, as
-    /// popping happens as part of the rollback).
-    ///
-    /// Note: popping also occurs implicitly as part of `leak_check`.
-    pub fn pop_placeholders(
-        &self,
-        placeholder_map: PlaceholderMap<'tcx>,
-        snapshot: &CombinedSnapshot<'a, 'tcx>,
-    ) {
-        debug!("pop_placeholders({:?})", placeholder_map);
-        let placeholder_regions: FxHashSet<_> = placeholder_map.values().cloned().collect();
-        self.borrow_region_constraints().pop_placeholders(&placeholder_regions);
-        self.universe.set(snapshot.universe);
-        if !placeholder_map.is_empty() {
-            self.projection_cache.borrow_mut().rollback_placeholder(
-                &snapshot.projection_cache_snapshot);
-        }
-    }
 }
diff --git a/src/librustc/infer/lexical_region_resolve/mod.rs b/src/librustc/infer/lexical_region_resolve/mod.rs
index de64800ee8d..bbab17f9516 100644
--- a/src/librustc/infer/lexical_region_resolve/mod.rs
+++ b/src/librustc/infer/lexical_region_resolve/mod.rs
@@ -215,23 +215,41 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
     ) -> bool {
         debug!("expand_node({:?}, {:?} == {:?})", a_region, b_vid, b_data);
 
-        // Check if this relationship is implied by a given.
         match *a_region {
+            // Check if this relationship is implied by a given.
             ty::ReEarlyBound(_) | ty::ReFree(_) => if self.data.givens.contains(&(a_region, b_vid))
             {
                 debug!("given");
                 return false;
             },
+
             _ => {}
         }
 
+
         match *b_data {
             VarValue::Value(cur_region) => {
-                let lub = self.lub_concrete_regions(a_region, cur_region);
+                let mut lub = self.lub_concrete_regions(a_region, cur_region);
                 if lub == cur_region {
                     return false;
                 }
 
+                // Watch out for `'b: !1` relationships, where the
+                // universe of `'b` can't name the placeholder `!1`. In
+                // that case, we have to grow `'b` to be `'static` for the
+                // relationship to hold. This is obviously a kind of sub-optimal
+                // choice -- in the future, when we incorporate a knowledge
+                // of the parameter environment, we might be able to find a
+                // tighter bound than `'static`.
+                //
+                // (This might e.g. arise from being asked to prove `for<'a> { 'b: 'a }`.)
+                let b_universe = self.var_infos[b_vid].universe;
+                if let ty::RePlaceholder(p) = lub {
+                    if b_universe.cannot_name(p.universe) {
+                        lub = self.tcx().types.re_static;
+                    }
+                }
+
                 debug!(
                     "Expanding value of {:?} from {:?} to {:?}",
                     b_vid, cur_region, lub
@@ -554,10 +572,22 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
         lower_bounds.sort_by_key(region_order_key);
         upper_bounds.sort_by_key(region_order_key);
 
+        let node_universe = self.var_infos[node_idx].universe;
+
         for lower_bound in &lower_bounds {
+            let effective_lower_bound = if let ty::RePlaceholder(p) = lower_bound.region {
+                if node_universe.cannot_name(p.universe) {
+                    self.tcx().types.re_static
+                } else {
+                    lower_bound.region
+                }
+            } else {
+                lower_bound.region
+            };
+
             for upper_bound in &upper_bounds {
                 if !self.region_rels
-                    .is_subregion_of(lower_bound.region, upper_bound.region)
+                    .is_subregion_of(effective_lower_bound, upper_bound.region)
                 {
                     let origin = self.var_infos[node_idx].origin.clone();
                     debug!(
@@ -580,9 +610,10 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
         span_bug!(
             self.var_infos[node_idx].origin.span(),
             "collect_error_for_expanding_node() could not find \
-             error for var {:?}, lower_bounds={:?}, \
-             upper_bounds={:?}",
+             error for var {:?} in universe {:?}, lower_bounds={:#?}, \
+             upper_bounds={:#?}",
             node_idx,
+            node_universe,
             lower_bounds,
             upper_bounds
         );
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 9a5e707b57d..3b9affa6ffb 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -32,7 +32,6 @@ use ty::{FloatVid, IntVid, TyVid};
 use util::nodemap::FxHashMap;
 
 use self::combine::CombineFields;
-use self::higher_ranked::HrMatchResult;
 use self::lexical_region_resolve::LexicalRegionResolutions;
 use self::outlives::env::OutlivesEnvironment;
 use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, VerifyBound};
@@ -948,39 +947,32 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             return None;
         }
 
-        Some(self.commit_if_ok(|snapshot| {
-            let (
-                ty::SubtypePredicate {
-                    a_is_expected,
-                    a,
-                    b,
-                },
-                placeholder_map,
-            ) = self.replace_bound_vars_with_placeholders(predicate);
+        let (
+            ty::SubtypePredicate {
+                a_is_expected,
+                a,
+                b,
+            },
+            _,
+        ) = self.replace_bound_vars_with_placeholders(predicate);
 
-            let cause_span = cause.span;
-            let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?;
-            self.leak_check(false, cause_span, &placeholder_map, snapshot)?;
-            self.pop_placeholders(placeholder_map, snapshot);
-            Ok(ok.unit())
-        }))
+        Some(
+            self.at(cause, param_env)
+                .sub_exp(a_is_expected, a, b)
+                .map(|ok| ok.unit()),
+        )
     }
 
     pub fn region_outlives_predicate(
         &self,
         cause: &traits::ObligationCause<'tcx>,
         predicate: &ty::PolyRegionOutlivesPredicate<'tcx>,
-    ) -> UnitResult<'tcx> {
-        self.commit_if_ok(|snapshot| {
-            let (ty::OutlivesPredicate(r_a, r_b), placeholder_map) =
-                self.replace_bound_vars_with_placeholders(predicate);
-            let origin = SubregionOrigin::from_obligation_cause(cause, || {
-                RelateRegionParamBound(cause.span)
-            });
-            self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
-            self.leak_check(false, cause.span, &placeholder_map, snapshot)?;
-            Ok(self.pop_placeholders(placeholder_map, snapshot))
-        })
+    ) {
+        let (ty::OutlivesPredicate(r_a, r_b), _) =
+            self.replace_bound_vars_with_placeholders(predicate);
+        let origin =
+            SubregionOrigin::from_obligation_cause(cause, || RelateRegionParamBound(cause.span));
+        self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
     }
 
     pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid {
@@ -1389,46 +1381,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         self.tcx.replace_bound_vars(value, fld_r, fld_t)
     }
 
-    /// Given a higher-ranked projection predicate like:
-    ///
-    ///     for<'a> <T as Fn<&'a u32>>::Output = &'a u32
-    ///
-    /// and a target trait-ref like:
-    ///
-    ///     <T as Fn<&'x u32>>
-    ///
-    /// find a substitution `S` for the higher-ranked regions (here,
-    /// `['a => 'x]`) such that the predicate matches the trait-ref,
-    /// and then return the value (here, `&'a u32`) but with the
-    /// substitution applied (hence, `&'x u32`).
-    ///
-    /// See `higher_ranked_match` in `higher_ranked/mod.rs` for more
-    /// details.
-    pub fn match_poly_projection_predicate(
-        &self,
-        cause: ObligationCause<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        match_a: ty::PolyProjectionPredicate<'tcx>,
-        match_b: ty::TraitRef<'tcx>,
-    ) -> InferResult<'tcx, HrMatchResult<Ty<'tcx>>> {
-        let match_pair = match_a.map_bound(|p| (p.projection_ty.trait_ref(self.tcx), p.ty));
-        let trace = TypeTrace {
-            cause,
-            values: TraitRefs(ExpectedFound::new(
-                true,
-                match_pair.skip_binder().0,
-                match_b,
-            )),
-        };
-
-        let mut combine = self.combine_fields(trace, param_env);
-        let result = combine.higher_ranked_match(&match_pair, &match_b, true)?;
-        Ok(InferOk {
-            value: result,
-            obligations: combine.obligations,
-        })
-    }
-
     /// See `verify_generic_bound` method in `region_constraints`
     pub fn verify_generic_bound(
         &self,
diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs
index 89086e66dff..b29eb67dfa2 100644
--- a/src/librustc/infer/region_constraints/mod.rs
+++ b/src/librustc/infer/region_constraints/mod.rs
@@ -17,8 +17,6 @@ use ty::{Region, RegionVid};
 use std::collections::BTreeMap;
 use std::{cmp, fmt, mem, u32};
 
-mod taint;
-
 #[derive(Default)]
 pub struct RegionConstraintCollector<'tcx> {
     /// For each `RegionVid`, the corresponding `RegionVariableOrigin`.
@@ -826,35 +824,6 @@ impl<'tcx> RegionConstraintCollector<'tcx> {
             .collect()
     }
 
-    /// Computes all regions that have been related to `r0` since the
-    /// mark `mark` was made---`r0` itself will be the first
-    /// entry. The `directions` parameter controls what kind of
-    /// relations are considered. For example, one can say that only
-    /// "incoming" edges to `r0` are desired, in which case one will
-    /// get the set of regions `{r|r <= r0}`. This is used when
-    /// checking whether placeholder regions are being improperly
-    /// related to other regions.
-    pub fn tainted(
-        &self,
-        tcx: TyCtxt<'_, '_, 'tcx>,
-        mark: &RegionSnapshot,
-        r0: Region<'tcx>,
-        directions: TaintDirections,
-    ) -> FxHashSet<ty::Region<'tcx>> {
-        debug!(
-            "tainted(mark={:?}, r0={:?}, directions={:?})",
-            mark, r0, directions
-        );
-
-        // `result_set` acts as a worklist: we explore all outgoing
-        // edges and add any new regions we find to result_set.  This
-        // is not a terribly efficient implementation.
-        let mut taint_set = taint::TaintSet::new(directions, r0);
-        taint_set.fixed_point(tcx, &self.undo_log[mark.length..], &self.data.verifys);
-        debug!("tainted: result={:?}", taint_set);
-        return taint_set.into_set();
-    }
-
     pub fn region_constraints_added_in_snapshot(&self, mark: &RegionSnapshot) -> bool {
         self.undo_log[mark.length..]
             .iter()
diff --git a/src/librustc/infer/region_constraints/taint.rs b/src/librustc/infer/region_constraints/taint.rs
deleted file mode 100644
index 6743f37972a..00000000000
--- a/src/librustc/infer/region_constraints/taint.rs
+++ /dev/null
@@ -1,85 +0,0 @@
-use super::*;
-
-#[derive(Debug)]
-pub(super) struct TaintSet<'tcx> {
-    directions: TaintDirections,
-    regions: FxHashSet<ty::Region<'tcx>>,
-}
-
-impl<'tcx> TaintSet<'tcx> {
-    pub(super) fn new(directions: TaintDirections, initial_region: ty::Region<'tcx>) -> Self {
-        let mut regions = FxHashSet::default();
-        regions.insert(initial_region);
-        TaintSet {
-            directions: directions,
-            regions: regions,
-        }
-    }
-
-    pub(super) fn fixed_point(
-        &mut self,
-        tcx: TyCtxt<'_, '_, 'tcx>,
-        undo_log: &[UndoLog<'tcx>],
-        verifys: &[Verify<'tcx>],
-    ) {
-        let mut prev_len = 0;
-        while prev_len < self.len() {
-            debug!(
-                "tainted: prev_len = {:?} new_len = {:?}",
-                prev_len,
-                self.len()
-            );
-
-            prev_len = self.len();
-
-            for undo_entry in undo_log {
-                match undo_entry {
-                    &AddConstraint(Constraint::VarSubVar(a, b)) => {
-                        self.add_edge(tcx.mk_region(ReVar(a)), tcx.mk_region(ReVar(b)));
-                    }
-                    &AddConstraint(Constraint::RegSubVar(a, b)) => {
-                        self.add_edge(a, tcx.mk_region(ReVar(b)));
-                    }
-                    &AddConstraint(Constraint::VarSubReg(a, b)) => {
-                        self.add_edge(tcx.mk_region(ReVar(a)), b);
-                    }
-                    &AddConstraint(Constraint::RegSubReg(a, b)) => {
-                        self.add_edge(a, b);
-                    }
-                    &AddGiven(a, b) => {
-                        self.add_edge(a, tcx.mk_region(ReVar(b)));
-                    }
-                    &AddVerify(i) => {
-                        span_bug!(
-                            verifys[i].origin.span(),
-                            "we never add verifications while doing higher-ranked things",
-                        )
-                    }
-                    &Purged | &AddCombination(..) | &AddVar(..) => {}
-                }
-            }
-        }
-    }
-
-    pub(super) fn into_set(self) -> FxHashSet<ty::Region<'tcx>> {
-        self.regions
-    }
-
-    fn len(&self) -> usize {
-        self.regions.len()
-    }
-
-    fn add_edge(&mut self, source: ty::Region<'tcx>, target: ty::Region<'tcx>) {
-        if self.directions.incoming {
-            if self.regions.contains(&target) {
-                self.regions.insert(source);
-            }
-        }
-
-        if self.directions.outgoing {
-            if self.regions.contains(&source) {
-                self.regions.insert(target);
-            }
-        }
-    }
-}
diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs
index f96c4e9014b..92004ece26d 100644
--- a/src/librustc/traits/auto_trait.rs
+++ b/src/librustc/traits/auto_trait.rs
@@ -771,13 +771,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
                     }
                 }
                 &ty::Predicate::RegionOutlives(ref binder) => {
-                    if select
-                        .infcx()
-                        .region_outlives_predicate(&dummy_cause, binder)
-                        .is_err()
-                    {
-                        return false;
-                    }
+                    let () = select.infcx().region_outlives_predicate(&dummy_cause, binder);
                 }
                 &ty::Predicate::TypeOutlives(ref binder) => {
                     match (
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 0e63ef666c7..21352ac1053 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -728,12 +728,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                     }
 
                     ty::Predicate::RegionOutlives(ref predicate) => {
-                        let predicate = self.resolve_type_vars_if_possible(predicate);
-                        let err = self.region_outlives_predicate(&obligation.cause,
-                                                                 &predicate).err().unwrap();
-                        struct_span_err!(self.tcx.sess, span, E0279,
-                            "the requirement `{}` is not satisfied (`{}`)",
-                            predicate, err)
+                        // These errors should show up as region
+                        // inference failures.
+                        panic!("region outlives {:?} failed", predicate);
                     }
 
                     ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index 219e971b3c9..2e00d4d4b7c 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -331,10 +331,8 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
             }
 
             ty::Predicate::RegionOutlives(ref binder) => {
-                match self.selcx.infcx().region_outlives_predicate(&obligation.cause, binder) {
-                    Ok(()) => ProcessResult::Changed(vec![]),
-                    Err(_) => ProcessResult::Error(CodeSelectionError(Unimplemented)),
-                }
+                let () = self.selcx.infcx().region_outlives_predicate(&obligation.cause, binder);
+                ProcessResult::Changed(vec![])
             }
 
             ty::Predicate::TypeOutlives(ref binder) => {
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index 952b37b89f2..732ca70dc78 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -13,7 +13,7 @@ use super::{VtableImplData, VtableClosureData, VtableGeneratorData, VtableFnPoin
 use super::util;
 
 use hir::def_id::DefId;
-use infer::{InferCtxt, InferOk};
+use infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
 use infer::type_variable::TypeVariableOrigin;
 use mir::interpret::ConstValue;
 use mir::interpret::{GlobalId};
@@ -192,28 +192,12 @@ pub fn poly_project_and_unify_type<'cx, 'gcx, 'tcx>(
            obligation);
 
     let infcx = selcx.infcx();
-    infcx.commit_if_ok(|snapshot| {
-        let (placeholder_predicate, placeholder_map) =
+    infcx.commit_if_ok(|_| {
+        let (placeholder_predicate, _) =
             infcx.replace_bound_vars_with_placeholders(&obligation.predicate);
 
-        let skol_obligation = obligation.with(placeholder_predicate);
-        let r = match project_and_unify_type(selcx, &skol_obligation) {
-            Ok(result) => {
-                let span = obligation.cause.span;
-                match infcx.leak_check(false, span, &placeholder_map, snapshot) {
-                    Ok(()) => Ok(infcx.plug_leaks(placeholder_map, snapshot, result)),
-                    Err(e) => {
-                        debug!("poly_project_and_unify_type: leak check encountered error {:?}", e);
-                        Err(MismatchedProjectionTypes { err: e })
-                    }
-                }
-            }
-            Err(e) => {
-                Err(e)
-            }
-        };
-
-        r
+        let placeholder_obligation = obligation.with(placeholder_predicate);
+        project_and_unify_type(selcx, &placeholder_obligation)
     })
 }
 
@@ -1443,17 +1427,25 @@ fn confirm_callable_candidate<'cx, 'gcx, 'tcx>(
 fn confirm_param_env_candidate<'cx, 'gcx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
-    poly_projection: ty::PolyProjectionPredicate<'tcx>)
+    poly_cache_entry: ty::PolyProjectionPredicate<'tcx>)
     -> Progress<'tcx>
 {
     let infcx = selcx.infcx();
-    let cause = obligation.cause.clone();
+    let cause = &obligation.cause;
     let param_env = obligation.param_env;
-    let trait_ref = obligation.predicate.trait_ref(infcx.tcx);
-    match infcx.match_poly_projection_predicate(cause, param_env, poly_projection, trait_ref) {
-        Ok(InferOk { value: ty_match, obligations }) => {
+
+    let (cache_entry, _) =
+        infcx.replace_bound_vars_with_fresh_vars(
+            cause.span,
+            LateBoundRegionConversionTime::HigherRankedType,
+            &poly_cache_entry);
+
+    let cache_trait_ref = cache_entry.projection_ty.trait_ref(infcx.tcx);
+    let obligation_trait_ref = obligation.predicate.trait_ref(infcx.tcx);
+    match infcx.at(cause, param_env).eq(cache_trait_ref, obligation_trait_ref) {
+        Ok(InferOk { value: _, obligations }) => {
             Progress {
-                ty: ty_match.value,
+                ty: cache_entry.ty,
                 obligations,
             }
         }
@@ -1463,7 +1455,7 @@ fn confirm_param_env_candidate<'cx, 'gcx, 'tcx>(
                 "Failed to unify obligation `{:?}` \
                  with poly_projection `{:?}`: {:?}",
                 obligation,
-                poly_projection,
+                poly_cache_entry,
                 e);
         }
     }
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 2576578f4c2..f5e96286d18 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -29,7 +29,7 @@ use super::{
 
 use dep_graph::{DepKind, DepNodeIndex};
 use hir::def_id::DefId;
-use infer::{self, InferCtxt, InferOk, TypeFreshener};
+use infer::{InferCtxt, InferOk, TypeFreshener};
 use middle::lang_items;
 use mir::interpret::GlobalId;
 use ty::fast_reject;
@@ -44,7 +44,6 @@ use rustc_target::spec::abi::Abi;
 use std::cmp;
 use std::fmt;
 use std::iter;
-use std::mem;
 use std::rc::Rc;
 use util::nodemap::{FxHashMap, FxHashSet};
 
@@ -1633,8 +1632,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             _ => return,
         }
 
-        let result = self.infcx.probe(|snapshot| {
-            self.match_projection_obligation_against_definition_bounds(obligation, snapshot)
+        let result = self.infcx.probe(|_| {
+            self.match_projection_obligation_against_definition_bounds(obligation)
         });
 
         if result {
@@ -1645,16 +1644,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
     fn match_projection_obligation_against_definition_bounds(
         &mut self,
         obligation: &TraitObligation<'tcx>,
-        snapshot: &infer::CombinedSnapshot<'cx, 'tcx>,
     ) -> bool {
         let poly_trait_predicate = self.infcx()
             .resolve_type_vars_if_possible(&obligation.predicate);
-        let (skol_trait_predicate, placeholder_map) = self.infcx()
+        let (skol_trait_predicate, _) = self.infcx()
             .replace_bound_vars_with_placeholders(&poly_trait_predicate);
         debug!(
             "match_projection_obligation_against_definition_bounds: \
-             skol_trait_predicate={:?} placeholder_map={:?}",
-            skol_trait_predicate, placeholder_map
+             skol_trait_predicate={:?}",
+            skol_trait_predicate,
         );
 
         let (def_id, substs) = match skol_trait_predicate.trait_ref.self_ty().sty {
@@ -1691,8 +1689,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                         obligation,
                         bound.clone(),
                         skol_trait_predicate.trait_ref.clone(),
-                        &placeholder_map,
-                        snapshot,
                     )
                 })
             });
@@ -1710,12 +1706,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                     obligation,
                     bound,
                     skol_trait_predicate.trait_ref.clone(),
-                    &placeholder_map,
-                    snapshot,
                 );
 
-                self.infcx.pop_placeholders(placeholder_map, snapshot);
-
                 assert!(result);
                 true
             }
@@ -1727,20 +1719,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         obligation: &TraitObligation<'tcx>,
         trait_bound: ty::PolyTraitRef<'tcx>,
         skol_trait_ref: ty::TraitRef<'tcx>,
-        placeholder_map: &infer::PlaceholderMap<'tcx>,
-        snapshot: &infer::CombinedSnapshot<'cx, 'tcx>,
     ) -> bool {
         debug_assert!(!skol_trait_ref.has_escaping_bound_vars());
-        if self.infcx
+        self.infcx
             .at(&obligation.cause, obligation.param_env)
             .sup(ty::Binder::dummy(skol_trait_ref), trait_bound)
-            .is_err()
-        {
-            return false;
-        }
-
-        self.infcx
-            .leak_check(false, obligation.cause.span, placeholder_map, snapshot)
             .is_ok()
     }
 
@@ -1942,14 +1925,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             obligation.predicate.def_id(),
             obligation.predicate.skip_binder().trait_ref.self_ty(),
             |impl_def_id| {
-                self.infcx.probe(|snapshot| {
-                    if let Ok(placeholder_map) = self.match_impl(impl_def_id, obligation, snapshot)
+                self.infcx.probe(|_| {
+                    if let Ok(_substs) = self.match_impl(impl_def_id, obligation)
                     {
                         candidates.vec.push(ImplCandidate(impl_def_id));
-
-                        // N.B., we can safely drop the placeholder map
-                        // since we are in a probe.
-                        mem::drop(placeholder_map);
                     }
                 });
             },
@@ -2607,8 +2586,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                 // binder moved -\
                 let ty: ty::Binder<Ty<'tcx>> = ty::Binder::bind(ty); // <----/
 
-                self.infcx.in_snapshot(|snapshot| {
-                    let (skol_ty, placeholder_map) = self.infcx
+                self.infcx.in_snapshot(|_| {
+                    let (skol_ty, _) = self.infcx
                         .replace_bound_vars_with_placeholders(&ty);
                     let Normalized {
                         value: normalized_ty,
@@ -2629,8 +2608,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                         &[],
                     );
                     obligations.push(skol_obligation);
-                    self.infcx
-                        .plug_leaks(placeholder_map, snapshot, obligations)
+                    obligations
                 })
             })
             .collect()
@@ -2721,9 +2699,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
     }
 
     fn confirm_projection_candidate(&mut self, obligation: &TraitObligation<'tcx>) {
-        self.infcx.in_snapshot(|snapshot| {
+        self.infcx.in_snapshot(|_| {
             let result =
-                self.match_projection_obligation_against_definition_bounds(obligation, snapshot);
+                self.match_projection_obligation_against_definition_bounds(obligation);
             assert!(result);
         })
     }
@@ -2840,9 +2818,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             nested,
         );
 
-        let trait_obligations: Vec<PredicateObligation<'_>> = self.infcx.in_snapshot(|snapshot| {
+        let trait_obligations: Vec<PredicateObligation<'_>> = self.infcx.in_snapshot(|_| {
             let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
-            let (trait_ref, placeholder_map) = self.infcx
+            let (trait_ref, _) = self.infcx
                 .replace_bound_vars_with_placeholders(&poly_trait_ref);
             let cause = obligation.derived_cause(ImplDerivedObligation);
             self.impl_or_trait_obligations(
@@ -2851,8 +2829,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                 obligation.param_env,
                 trait_def_id,
                 &trait_ref.substs,
-                placeholder_map,
-                snapshot,
             )
         });
 
@@ -2877,8 +2853,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
 
         // First, create the substitutions by matching the impl again,
         // this time not in a probe.
-        self.infcx.in_snapshot(|snapshot| {
-            let (substs, placeholder_map) = self.rematch_impl(impl_def_id, obligation, snapshot);
+        self.infcx.in_snapshot(|_| {
+            let substs = self.rematch_impl(impl_def_id, obligation);
             debug!("confirm_impl_candidate: substs={:?}", substs);
             let cause = obligation.derived_cause(ImplDerivedObligation);
             self.vtable_impl(
@@ -2887,8 +2863,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                 cause,
                 obligation.recursion_depth + 1,
                 obligation.param_env,
-                placeholder_map,
-                snapshot,
             )
         })
     }
@@ -2900,12 +2874,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         cause: ObligationCause<'tcx>,
         recursion_depth: usize,
         param_env: ty::ParamEnv<'tcx>,
-        placeholder_map: infer::PlaceholderMap<'tcx>,
-        snapshot: &infer::CombinedSnapshot<'cx, 'tcx>,
     ) -> VtableImplData<'tcx, PredicateObligation<'tcx>> {
         debug!(
-            "vtable_impl(impl_def_id={:?}, substs={:?}, recursion_depth={}, placeholder_map={:?})",
-            impl_def_id, substs, recursion_depth, placeholder_map
+            "vtable_impl(impl_def_id={:?}, substs={:?}, recursion_depth={})",
+            impl_def_id, substs, recursion_depth,
         );
 
         let mut impl_obligations = self.impl_or_trait_obligations(
@@ -2914,8 +2886,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             param_env,
             impl_def_id,
             &substs.value,
-            placeholder_map,
-            snapshot,
         );
 
         debug!(
@@ -3044,8 +3014,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             obligation, alias_def_id
         );
 
-        self.infcx.in_snapshot(|snapshot| {
-            let (predicate, placeholder_map) = self.infcx
+        self.infcx.in_snapshot(|_| {
+            let (predicate, _) = self.infcx()
                 .replace_bound_vars_with_placeholders(&obligation.predicate);
             let trait_ref = predicate.trait_ref;
             let trait_def_id = trait_ref.def_id;
@@ -3057,8 +3027,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                 obligation.param_env,
                 trait_def_id,
                 &substs,
-                placeholder_map,
-                snapshot,
             );
 
             debug!(
@@ -3473,13 +3441,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         &mut self,
         impl_def_id: DefId,
         obligation: &TraitObligation<'tcx>,
-        snapshot: &infer::CombinedSnapshot<'cx, 'tcx>,
-    ) -> (
-        Normalized<'tcx, &'tcx Substs<'tcx>>,
-        infer::PlaceholderMap<'tcx>,
-    ) {
-        match self.match_impl(impl_def_id, obligation, snapshot) {
-            Ok((substs, placeholder_map)) => (substs, placeholder_map),
+    ) -> Normalized<'tcx, &'tcx Substs<'tcx>> {
+        match self.match_impl(impl_def_id, obligation) {
+            Ok(substs) => substs,
             Err(()) => {
                 bug!(
                     "Impl {:?} was matchable against {:?} but now is not",
@@ -3494,14 +3458,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         &mut self,
         impl_def_id: DefId,
         obligation: &TraitObligation<'tcx>,
-        snapshot: &infer::CombinedSnapshot<'cx, 'tcx>,
-    ) -> Result<
-        (
-            Normalized<'tcx, &'tcx Substs<'tcx>>,
-            infer::PlaceholderMap<'tcx>,
-        ),
-        (),
-    > {
+    ) -> Result<Normalized<'tcx, &'tcx Substs<'tcx>>, ()> {
         let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap();
 
         // Before we create the substitutions and everything, first
@@ -3511,7 +3468,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             return Err(());
         }
 
-        let (skol_obligation, placeholder_map) = self.infcx()
+        let (skol_obligation, _) = self.infcx()
             .replace_bound_vars_with_placeholders(&obligation.predicate);
         let skol_obligation_trait_ref = skol_obligation.trait_ref;
 
@@ -3543,22 +3500,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{}`", e))?;
         nested_obligations.extend(obligations);
 
-        if let Err(e) =
-            self.infcx
-                .leak_check(false, obligation.cause.span, &placeholder_map, snapshot)
-        {
-            debug!("match_impl: failed leak check due to `{}`", e);
-            return Err(());
-        }
-
         debug!("match_impl: success impl_substs={:?}", impl_substs);
-        Ok((
-            Normalized {
-                value: impl_substs,
-                obligations: nested_obligations,
-            },
-            placeholder_map,
-        ))
+        Ok(Normalized {
+            value: impl_substs,
+            obligations: nested_obligations,
+        })
     }
 
     fn fast_reject_trait_refs(
@@ -3714,8 +3660,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         param_env: ty::ParamEnv<'tcx>,
         def_id: DefId,         // of impl or trait
         substs: &Substs<'tcx>, // for impl or trait
-        placeholder_map: infer::PlaceholderMap<'tcx>,
-        snapshot: &infer::CombinedSnapshot<'cx, 'tcx>,
     ) -> Vec<PredicateObligation<'tcx>> {
         debug!("impl_or_trait_obligations(def_id={:?})", def_id);
         let tcx = self.tcx();
@@ -3777,8 +3721,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             let mut seen = FxHashSet::default();
             predicates.retain(|i| seen.insert(i.clone()));
         }
-        self.infcx()
-            .plug_leaks(placeholder_map, snapshot, predicates)
+
+        predicates
     }
 }