From b68fad670bb3612cac26e50751e4fd9150e59977 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 7 Sep 2018 20:11:23 -0400 Subject: [PATCH] universe transition Remove the leak-check and its associated machinery. Replace with making the solver aware of universes. --- src/librustc/infer/higher_ranked/mod.rs | 507 ++---------------- .../infer/lexical_region_resolve/mod.rs | 41 +- src/librustc/infer/mod.rs | 86 +-- src/librustc/infer/region_constraints/mod.rs | 31 -- .../infer/region_constraints/taint.rs | 85 --- src/librustc/traits/auto_trait.rs | 8 +- src/librustc/traits/error_reporting.rs | 9 +- src/librustc/traits/fulfill.rs | 6 +- src/librustc/traits/project.rs | 48 +- src/librustc/traits/select.rs | 122 ++--- 10 files changed, 144 insertions(+), 799 deletions(-) delete mode 100644 src/librustc/infer/region_constraints/taint.rs diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index 3a3a21d0f1d4a..709e8c0ba9b24 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 { - pub value: U, -} +use ty::{self, Binder, TypeFoldable}; impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { - pub fn higher_ranked_sub(&mut self, a: &Binder, b: &Binder, a_is_expected: bool) - -> RelateResult<'tcx, Binder> - where T: Relate<'tcx> + pub fn higher_ranked_sub( + &mut self, + a: &Binder, + b: &Binder, + a_is_expected: bool, + ) -> RelateResult<'tcx, Binder> + 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(&mut self, - a_pair: &Binder<(T, U)>, - b_match: &T, - a_is_expected: bool) - -> RelateResult<'tcx, HrMatchResult> - 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> { - 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 - { - /*! - * 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(|®ion_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 Fn 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(&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::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 de64800ee8d35..bbab17f951659 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 9a5e707b57d89..3b9affa6ffb50 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> >::Output = &'a u32 - /// - /// and a target trait-ref like: - /// - /// > - /// - /// 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>> { - 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 89086e66dffbf..b29eb67dfa225 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> { - 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 6743f37972ae5..0000000000000 --- 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>, -} - -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> { - 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 f96c4e9014b36..92004ece26d00 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 0e63ef666c75a..21352ac1053a8 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 219e971b3c927..2e00d4d4b7c3b 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 952b37b89f2d4..732ca70dc78c5 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 2576578f4c294..f5e96286d184e 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::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> = self.infcx.in_snapshot(|snapshot| { + let trait_obligations: Vec> = 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>, ()> { 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> { 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 } }