1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Helper routines for higher-ranked things. See the `doc` module at
12 //! the end of the file for details.
14 use super::{CombinedSnapshot,
19 use super::combine::CombineFields;
20 use super::region_constraints::{TaintDirections};
22 use ty::{self, TyCtxt, Binder, TypeFoldable};
23 use ty::error::TypeError;
24 use ty::relate::{Relate, RelateResult, TypeRelation};
25 use std::collections::BTreeMap;
27 use util::nodemap::{FxHashMap, FxHashSet};
29 pub struct HrMatchResult<U> {
33 impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
34 pub fn higher_ranked_sub<T>(&mut self, a: &Binder<T>, b: &Binder<T>, a_is_expected: bool)
35 -> RelateResult<'tcx, Binder<T>>
38 debug!("higher_ranked_sub(a={:?}, b={:?})",
41 // Rather than checking the subtype relationship between `a` and `b`
42 // as-is, we need to do some extra work here in order to make sure
43 // that function subtyping works correctly with respect to regions
45 // Note: this is a subtle algorithm. For a full explanation,
46 // please see the large comment at the end of the file in the (inlined) module
49 // Start a snapshot so we can examine "all bindings that were
50 // created as part of this type comparison".
51 return self.infcx.commit_if_ok(|snapshot| {
52 let span = self.trace.cause.span;
54 // First, we instantiate each bound region in the supertype with a
55 // fresh placeholder region.
56 let (b_prime, placeholder_map) =
57 self.infcx.replace_late_bound_regions_with_placeholders(b);
59 // Next, we instantiate each bound region in the subtype
60 // with a fresh region variable. These region variables --
61 // but no other pre-existing region variables -- can name
64 self.infcx.replace_late_bound_regions_with_fresh_var(
69 debug!("a_prime={:?}", a_prime);
70 debug!("b_prime={:?}", b_prime);
72 // Compare types now that bound regions have been replaced.
73 let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?;
75 // Presuming type comparison succeeds, we need to check
76 // that the placeholder regions do not "leak".
77 self.infcx.leak_check(!a_is_expected, span, &placeholder_map, snapshot)?;
79 // We are finished with the placeholder regions now so pop
81 self.infcx.pop_placeholders(placeholder_map, snapshot);
83 debug!("higher_ranked_sub: OK result={:?}", result);
85 Ok(ty::Binder::bind(result))
89 /// The value consists of a pair `(t, u)` where `t` is the
90 /// *matcher* and `u` is a *value*. The idea is to find a
91 /// substitution `S` such that `S(t) == b`, and then return
92 /// `S(u)`. In other words, find values for the late-bound regions
93 /// in `a` that can make `t == b` and then replace the LBR in `u`
94 /// with those values.
96 /// This routine is (as of this writing) used in trait matching,
97 /// particularly projection.
99 /// NB. It should not happen that there are LBR appearing in `U`
100 /// that do not appear in `T`. If that happens, those regions are
101 /// unconstrained, and this routine replaces them with `'static`.
102 pub fn higher_ranked_match<T, U>(&mut self,
103 a_pair: &Binder<(T, U)>,
106 -> RelateResult<'tcx, HrMatchResult<U>>
107 where T: Relate<'tcx>,
108 U: TypeFoldable<'tcx>
110 debug!("higher_ranked_match(a={:?}, b={:?})",
113 // Start a snapshot so we can examine "all bindings that were
114 // created as part of this type comparison".
115 return self.infcx.commit_if_ok(|snapshot| {
116 // First, we instantiate each bound region in the matcher
117 // with a placeholder region.
118 let ((a_match, a_value), placeholder_map) =
119 self.infcx.replace_late_bound_regions_with_placeholders(a_pair);
121 debug!("higher_ranked_match: a_match={:?}", a_match);
122 debug!("higher_ranked_match: placeholder_map={:?}", placeholder_map);
124 // Equate types now that bound regions have been replaced.
125 self.equate(a_is_expected).relate(&a_match, &b_match)?;
127 // Map each placeholder region to a vector of other regions that it
128 // must be equated with. (Note that this vector may include other
129 // placeholder regions from `placeholder_map`.)
130 let skol_resolution_map: FxHashMap<_, _> =
133 .map(|(&br, &skol)| {
134 let tainted_regions =
135 self.infcx.tainted_regions(snapshot,
137 TaintDirections::incoming()); // [1]
139 // [1] this routine executes after the placeholder
140 // regions have been *equated* with something
141 // else, so examining the incoming edges ought to
142 // be enough to collect all constraints
144 (skol, (br, tainted_regions))
148 // For each placeholder region, pick a representative -- which can
149 // be any region from the sets above, except for other members of
150 // `placeholder_map`. There should always be a representative if things
151 // are properly well-formed.
152 let skol_representatives: FxHashMap<_, _> =
155 .map(|(&skol, &(_, ref regions))| {
158 .filter(|&&r| !skol_resolution_map.contains_key(r))
162 bug!("no representative region for `{:?}` in `{:?}`",
166 (skol, representative)
170 // Equate all the members of each skolemization set with the
172 for (skol, &(_br, ref regions)) in &skol_resolution_map {
173 let representative = &skol_representatives[skol];
174 debug!("higher_ranked_match: \
175 skol={:?} representative={:?} regions={:?}",
176 skol, representative, regions);
177 for region in regions.iter()
178 .filter(|&r| !skol_resolution_map.contains_key(r))
179 .filter(|&r| r != representative)
181 let origin = SubregionOrigin::Subtype(self.trace.clone());
182 self.infcx.borrow_region_constraints()
183 .make_eqregion(origin,
189 // Replace the placeholder regions appearing in value with
190 // their representatives
195 |r, _| skol_representatives.get(&r).cloned().unwrap_or(r));
197 debug!("higher_ranked_match: value={:?}", a_value);
199 // We are now done with these placeholder variables.
200 self.infcx.pop_placeholders(placeholder_map, snapshot);
202 Ok(HrMatchResult { value: a_value })
206 pub fn higher_ranked_lub<T>(&mut self, a: &Binder<T>, b: &Binder<T>, a_is_expected: bool)
207 -> RelateResult<'tcx, Binder<T>>
208 where T: Relate<'tcx>
210 // Start a snapshot so we can examine "all bindings that were
211 // created as part of this type comparison".
212 return self.infcx.commit_if_ok(|snapshot| {
213 // Instantiate each bound region with a fresh region variable.
214 let span = self.trace.cause.span;
215 let (a_with_fresh, a_map) =
216 self.infcx.replace_late_bound_regions_with_fresh_var(
217 span, HigherRankedType, a);
218 let (b_with_fresh, _) =
219 self.infcx.replace_late_bound_regions_with_fresh_var(
220 span, HigherRankedType, b);
222 // Collect constraints.
224 self.lub(a_is_expected).relate(&a_with_fresh, &b_with_fresh)?;
226 self.infcx.resolve_type_vars_if_possible(&result0);
227 debug!("lub result0 = {:?}", result0);
229 // Generalize the regions appearing in result0 if possible
230 let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot);
231 let span = self.trace.cause.span;
236 |r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn,
237 &new_vars, &a_map, r));
239 debug!("lub({:?},{:?}) = {:?}",
244 Ok(ty::Binder::bind(result1))
247 fn generalize_region<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
249 snapshot: &CombinedSnapshot<'a, 'tcx>,
250 debruijn: ty::DebruijnIndex,
251 new_vars: &[ty::RegionVid],
252 a_map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>,
253 r0: ty::Region<'tcx>)
254 -> ty::Region<'tcx> {
255 // Regions that pre-dated the LUB computation stay as they are.
256 if !is_var_in_set(new_vars, r0) {
257 assert!(!r0.is_late_bound());
258 debug!("generalize_region(r0={:?}): not new variable", r0);
262 let tainted = infcx.tainted_regions(snapshot, r0, TaintDirections::both());
264 // Variables created during LUB computation which are
265 // *related* to regions that pre-date the LUB computation
267 if !tainted.iter().all(|&r| is_var_in_set(new_vars, r)) {
268 debug!("generalize_region(r0={:?}): \
269 non-new-variables found in {:?}",
271 assert!(!r0.is_late_bound());
275 // Otherwise, the variable must be associated with at
276 // least one of the variables representing bound regions
277 // in both A and B. Replace the variable with the "first"
278 // bound region from A that we find it to be associated
280 for (a_br, a_r) in a_map {
281 if tainted.iter().any(|x| x == a_r) {
282 debug!("generalize_region(r0={:?}): \
283 replacing with {:?}, tainted={:?}",
285 return infcx.tcx.mk_region(ty::ReLateBound(debruijn, *a_br));
291 "region {:?} is not associated with any bound region from A!",
296 pub fn higher_ranked_glb<T>(&mut self, a: &Binder<T>, b: &Binder<T>, a_is_expected: bool)
297 -> RelateResult<'tcx, Binder<T>>
298 where T: Relate<'tcx>
300 debug!("higher_ranked_glb({:?}, {:?})",
303 // Make a snapshot so we can examine "all bindings that were
304 // created as part of this type comparison".
305 return self.infcx.commit_if_ok(|snapshot| {
306 // Instantiate each bound region with a fresh region variable.
307 let (a_with_fresh, a_map) =
308 self.infcx.replace_late_bound_regions_with_fresh_var(
309 self.trace.cause.span, HigherRankedType, a);
310 let (b_with_fresh, b_map) =
311 self.infcx.replace_late_bound_regions_with_fresh_var(
312 self.trace.cause.span, HigherRankedType, b);
313 let a_vars = var_ids(self, &a_map);
314 let b_vars = var_ids(self, &b_map);
316 // Collect constraints.
318 self.glb(a_is_expected).relate(&a_with_fresh, &b_with_fresh)?;
320 self.infcx.resolve_type_vars_if_possible(&result0);
321 debug!("glb result0 = {:?}", result0);
323 // Generalize the regions appearing in result0 if possible
324 let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot);
325 let span = self.trace.cause.span;
330 |r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn,
332 &a_map, &a_vars, &b_vars,
335 debug!("glb({:?},{:?}) = {:?}",
340 Ok(ty::Binder::bind(result1))
343 fn generalize_region<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
345 snapshot: &CombinedSnapshot<'a, 'tcx>,
346 debruijn: ty::DebruijnIndex,
347 new_vars: &[ty::RegionVid],
348 a_map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>,
349 a_vars: &[ty::RegionVid],
350 b_vars: &[ty::RegionVid],
351 r0: ty::Region<'tcx>)
352 -> ty::Region<'tcx> {
353 if !is_var_in_set(new_vars, r0) {
354 assert!(!r0.is_late_bound());
358 let tainted = infcx.tainted_regions(snapshot, r0, TaintDirections::both());
362 let mut only_new_vars = true;
364 if is_var_in_set(a_vars, *r) {
366 return fresh_bound_variable(infcx, debruijn);
370 } else if is_var_in_set(b_vars, *r) {
372 return fresh_bound_variable(infcx, debruijn);
376 } else if !is_var_in_set(new_vars, *r) {
377 only_new_vars = false;
381 // NB---I do not believe this algorithm computes
382 // (necessarily) the GLB. As written it can
383 // spuriously fail. In particular, if there is a case
384 // like: |fn(&a)| and fn(fn(&b)), where a and b are
385 // free, it will return fn(&c) where c = GLB(a,b). If
386 // however this GLB is not defined, then the result is
387 // an error, even though something like
388 // "fn<X>(fn(&X))" where X is bound would be a
389 // subtype of both of those.
391 // The problem is that if we were to return a bound
392 // variable, we'd be computing a lower-bound, but not
393 // necessarily the *greatest* lower-bound.
395 // Unfortunately, this problem is non-trivial to solve,
396 // because we do not know at the time of computing the GLB
397 // whether a GLB(a,b) exists or not, because we haven't
398 // run region inference (or indeed, even fully computed
399 // the region hierarchy!). The current algorithm seems to
400 // works ok in practice.
402 if a_r.is_some() && b_r.is_some() && only_new_vars {
403 // Related to exactly one bound variable from each fn:
404 return rev_lookup(infcx, span, a_map, a_r.unwrap());
405 } else if a_r.is_none() && b_r.is_none() {
406 // Not related to bound variables from either fn:
407 assert!(!r0.is_late_bound());
411 return fresh_bound_variable(infcx, debruijn);
415 fn rev_lookup<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
417 a_map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>,
418 r: ty::Region<'tcx>) -> ty::Region<'tcx>
420 for (a_br, a_r) in a_map {
422 return infcx.tcx.mk_region(ty::ReLateBound(ty::INNERMOST, *a_br));
427 "could not find original bound region for {:?}",
431 fn fresh_bound_variable<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
432 debruijn: ty::DebruijnIndex)
433 -> ty::Region<'tcx> {
434 infcx.borrow_region_constraints().new_bound(infcx.tcx, debruijn)
439 fn var_ids<'a, 'gcx, 'tcx>(fields: &CombineFields<'a, 'gcx, 'tcx>,
440 map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
441 -> Vec<ty::RegionVid> {
443 .map(|(_, &r)| match *r {
444 ty::ReVar(r) => { r }
447 fields.trace.cause.span,
448 "found non-region-vid: {:?}",
455 fn is_var_in_set(new_vars: &[ty::RegionVid], r: ty::Region<'_>) -> bool {
457 ty::ReVar(ref v) => new_vars.iter().any(|x| x == v),
462 fn fold_regions_in<'a, 'gcx, 'tcx, T, F>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
466 where T: TypeFoldable<'tcx>,
467 F: FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx>,
469 tcx.fold_regions(unbound_value, &mut false, |region, current_depth| {
470 // we should only be encountering "escaping" late-bound regions here,
471 // because the ones at the current level should have been replaced
472 // with fresh variables
473 assert!(match *region {
474 ty::ReLateBound(..) => false,
478 fldr(region, current_depth)
482 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
483 fn tainted_regions(&self,
484 snapshot: &CombinedSnapshot<'a, 'tcx>,
486 directions: TaintDirections)
487 -> FxHashSet<ty::Region<'tcx>> {
488 self.borrow_region_constraints().tainted(
490 &snapshot.region_constraints_snapshot,
495 fn region_vars_confined_to_snapshot(&self,
496 snapshot: &CombinedSnapshot<'a, 'tcx>)
497 -> Vec<ty::RegionVid>
500 * Returns the set of region variables that do not affect any
501 * types/regions which existed before `snapshot` was
502 * started. This is used in the sub/lub/glb computations. The
503 * idea here is that when we are computing lub/glb of two
504 * regions, we sometimes create intermediate region variables.
505 * Those region variables may touch some of the placeholder or
506 * other "forbidden" regions we created to replace bound
507 * regions, but they don't really represent an "external"
510 * However, sometimes fresh variables are created for other
511 * purposes too, and those *may* represent an external
512 * constraint. In particular, when a type variable is
513 * instantiated, we create region variables for all the
514 * regions that appear within, and if that type variable
515 * pre-existed the snapshot, then those region variables
516 * represent external constraints.
518 * An example appears in the unit test
519 * `sub_free_bound_false_infer`. In this test, we want to
523 * fn(_#0t) <: for<'a> fn(&'a int)
526 * Note that the subtype has a type variable. Because the type
527 * variable can't be instantiated with a region that is bound
528 * in the fn signature, this comparison ought to fail. But if
529 * we're not careful, it will succeed.
531 * The reason is that when we walk through the subtyping
532 * algorithm, we begin by replacing `'a` with a placeholder
533 * variable `'1`. We then have `fn(_#0t) <: fn(&'1 int)`. This
534 * can be made true by unifying `_#0t` with `&'1 int`. In the
535 * process, we create a fresh variable for the placeholder
536 * region, `'$2`, and hence we have that `_#0t == &'$2
537 * int`. However, because `'$2` was created during the sub
538 * computation, if we're not careful we will erroneously
539 * assume it is one of the transient region variables
540 * representing a lub/glb internally. Not good.
542 * To prevent this, we check for type variables which were
543 * unified during the snapshot, and say that any region
544 * variable created during the snapshot but which finds its
545 * way into a type variable is considered to "escape" the
549 let mut region_vars =
550 self.borrow_region_constraints().vars_created_since_snapshot(
551 &snapshot.region_constraints_snapshot);
554 self.type_variables.borrow_mut().types_escaping_snapshot(&snapshot.type_snapshot);
556 let mut escaping_region_vars = FxHashSet();
557 for ty in &escaping_types {
558 self.tcx.collect_regions(ty, &mut escaping_region_vars);
561 region_vars.retain(|®ion_vid| {
562 let r = ty::ReVar(region_vid);
563 !escaping_region_vars.contains(&r)
566 debug!("region_vars_confined_to_snapshot: region_vars={:?} escaping_types={:?}",
573 /// Replace all regions bound by `binder` with placeholder regions and
574 /// return a map indicating which bound-region was replaced with what
575 /// placeholder region. This is the first step of checking subtyping
576 /// when higher-ranked things are involved.
578 /// **Important:** you must call this function from within a snapshot.
579 /// Moreover, before committing the snapshot, you must eventually call
580 /// either `plug_leaks` or `pop_placeholders` to remove the placeholder
581 /// regions. If you rollback the snapshot (or are using a probe), then
582 /// the pop occurs as part of the rollback, so an explicit call is not
583 /// needed (but is also permitted).
585 /// For more information about how skolemization for HRTBs works, see
586 /// the [rustc guide].
588 /// [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/traits/hrtb.html
589 pub fn replace_late_bound_regions_with_placeholders<T>(
591 binder: &ty::Binder<T>,
592 ) -> (T, PlaceholderMap<'tcx>)
594 T : TypeFoldable<'tcx>,
596 let new_universe = self.create_subuniverse();
598 let (result, map) = self.tcx.replace_late_bound_regions(binder, |br| {
599 self.tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
600 universe: new_universe,
605 debug!("replace_late_bound_regions_with_placeholders(binder={:?}, result={:?}, map={:?})",
613 /// Searches the region constraints created since `snapshot` was started
614 /// and checks to determine whether any of the placeholder regions created
615 /// in `placeholder_map` would "escape" -- meaning that they are related to
616 /// other regions in some way. If so, the higher-ranked subtyping doesn't
617 /// hold. See `README.md` for more details.
618 pub fn leak_check(&self,
619 overly_polymorphic: bool,
621 placeholder_map: &PlaceholderMap<'tcx>,
622 snapshot: &CombinedSnapshot<'a, 'tcx>)
623 -> RelateResult<'tcx, ()>
625 debug!("leak_check: placeholder_map={:?}",
628 // If the user gave `-Zno-leak-check`, then skip the leak
629 // check completely. This is wildly unsound and also not
630 // unlikely to cause an ICE or two. It is intended for use
631 // only during a transition period, in which the MIR typeck
632 // uses the "universe-style" check, and the rest of typeck
633 // uses the more conservative leak check. Since the leak
634 // check is more conservative, we can't test the
635 // universe-style check without disabling it.
636 if self.tcx.sess.opts.debugging_opts.no_leak_check {
640 let new_vars = self.region_vars_confined_to_snapshot(snapshot);
641 for (&skol_br, &skol) in placeholder_map {
642 // The inputs to a placeholder variable can only
643 // be itself or other new variables.
644 let incoming_taints = self.tainted_regions(snapshot,
646 TaintDirections::both());
647 for &tainted_region in &incoming_taints {
648 // Each placeholder should only be relatable to itself
650 match *tainted_region {
652 if new_vars.contains(&vid) {
657 if tainted_region == skol { continue; }
661 debug!("{:?} (which replaced {:?}) is tainted by {:?}",
666 return Err(if overly_polymorphic {
667 debug!("Overly polymorphic!");
668 TypeError::RegionsOverlyPolymorphic(skol_br, tainted_region)
670 debug!("Not as polymorphic!");
671 TypeError::RegionsInsufficientlyPolymorphic(skol_br, tainted_region)
679 /// This code converts from placeholder regions back to late-bound
680 /// regions. It works by replacing each region in the taint set of a
681 /// placeholder region with a bound-region. The bound region will be bound
682 /// by the outer-most binder in `value`; the caller must ensure that there is
683 /// such a binder and it is the right place.
685 /// This routine is only intended to be used when the leak-check has
686 /// passed; currently, it's used in the trait matching code to create
687 /// a set of nested obligations frmo an impl that matches against
688 /// something higher-ranked. More details can be found in
689 /// `librustc/middle/traits/README.md`.
691 /// As a brief example, consider the obligation `for<'a> Fn(&'a int)
692 /// -> &'a int`, and the impl:
694 /// impl<A,R> Fn<A,R> for SomethingOrOther
698 /// Here we will have replaced `'a` with a placeholder region
699 /// `'0`. This means that our substitution will be `{A=>&'0
700 /// int, R=>&'0 int}`.
702 /// When we apply the substitution to the bounds, we will wind up with
703 /// `&'0 int : Clone` as a predicate. As a last step, we then go and
704 /// replace `'0` with a late-bound region `'a`. The depth is matched
705 /// to the depth of the predicate, in this case 1, so that the final
706 /// predicate is `for<'a> &'a int : Clone`.
707 pub fn plug_leaks<T>(&self,
708 placeholder_map: PlaceholderMap<'tcx>,
709 snapshot: &CombinedSnapshot<'a, 'tcx>,
711 where T : TypeFoldable<'tcx>
713 debug!("plug_leaks(placeholder_map={:?}, value={:?})",
717 if placeholder_map.is_empty() {
721 // Compute a mapping from the "taint set" of each placeholder
722 // region back to the `ty::BoundRegion` that it originally
723 // represented. Because `leak_check` passed, we know that
724 // these taint sets are mutually disjoint.
725 let inv_placeholder_map: FxHashMap<ty::Region<'tcx>, ty::BoundRegion> =
728 .flat_map(|(&skol_br, &skol)| {
729 self.tainted_regions(snapshot, skol, TaintDirections::both())
731 .map(move |tainted_region| (tainted_region, skol_br))
735 debug!("plug_leaks: inv_placeholder_map={:?}",
736 inv_placeholder_map);
738 // Remove any instantiated type variables from `value`; those can hide
739 // references to regions from the `fold_regions` code below.
740 let value = self.resolve_type_vars_if_possible(&value);
742 // Map any skolemization byproducts back to a late-bound
743 // region. Put that late-bound region at whatever the outermost
744 // binder is that we encountered in `value`. The caller is
745 // responsible for ensuring that (a) `value` contains at least one
746 // binder and (b) that binder is the one we want to use.
747 let result = self.tcx.fold_regions(&value, &mut false, |r, current_depth| {
748 match inv_placeholder_map.get(&r) {
751 // It is the responsibility of the caller to ensure
752 // that each placeholder region appears within a
753 // binder. In practice, this routine is only used by
754 // trait checking, and all of the placeholder regions
755 // appear inside predicates, which always have
756 // binders, so this assert is satisfied.
757 assert!(current_depth > ty::INNERMOST);
759 // since leak-check passed, this placeholder region
760 // should only have incoming edges from variables
761 // (which ought not to escape the snapshot, but we
762 // don't check that) or itself
765 ty::ReVar(_) => true,
766 ty::RePlaceholder(index) => index.name == *br,
769 "leak-check would have us replace {:?} with {:?}",
772 self.tcx.mk_region(ty::ReLateBound(
773 current_depth.shifted_out(1),
780 self.pop_placeholders(placeholder_map, snapshot);
782 debug!("plug_leaks: result={:?}", result);
787 /// Pops the placeholder regions found in `placeholder_map` from the region
788 /// inference context. Whenever you create placeholder regions via
789 /// `replace_late_bound_regions_with_placeholders`, they must be popped before you
790 /// commit the enclosing snapshot (if you do not commit, e.g. within a
791 /// probe or as a result of an error, then this is not necessary, as
792 /// popping happens as part of the rollback).
794 /// Note: popping also occurs implicitly as part of `leak_check`.
795 pub fn pop_placeholders(
797 placeholder_map: PlaceholderMap<'tcx>,
798 snapshot: &CombinedSnapshot<'a, 'tcx>,
800 debug!("pop_placeholders({:?})", placeholder_map);
801 let skol_regions: FxHashSet<_> = placeholder_map.values().cloned().collect();
802 self.borrow_region_constraints()
805 &snapshot.region_constraints_snapshot,
807 self.universe.set(snapshot.universe);
808 if !placeholder_map.is_empty() {
809 self.projection_cache.borrow_mut().rollback_placeholder(
810 &snapshot.projection_cache_snapshot);