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,
20 use super::combine::CombineFields;
21 use super::region_inference::{TaintDirections};
23 use ty::{self, TyCtxt, Binder, TypeFoldable};
24 use ty::error::TypeError;
25 use ty::relate::{Relate, RelateResult, TypeRelation};
27 use util::nodemap::{FnvHashMap, FnvHashSet};
29 pub struct HrMatchResult<U> {
32 /// Normally, when we do a higher-ranked match operation, we
33 /// expect all higher-ranked regions to be constrained as part of
34 /// the match operation. However, in the transition period for
35 /// #32330, it can happen that we sometimes have unconstrained
36 /// regions that get instantiated with fresh variables. In that
37 /// case, we collect the set of unconstrained bound regions here
38 /// and replace them with fresh variables.
39 pub unconstrained_regions: Vec<ty::BoundRegion>,
42 impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
43 pub fn higher_ranked_sub<T>(&self, a: &Binder<T>, b: &Binder<T>)
44 -> RelateResult<'tcx, Binder<T>>
47 debug!("higher_ranked_sub(a={:?}, b={:?})",
50 // Rather than checking the subtype relationship between `a` and `b`
51 // as-is, we need to do some extra work here in order to make sure
52 // that function subtyping works correctly with respect to regions
54 // Note: this is a subtle algorithm. For a full explanation,
55 // please see the large comment at the end of the file in the (inlined) module
58 // Start a snapshot so we can examine "all bindings that were
59 // created as part of this type comparison".
60 return self.infcx.commit_if_ok(|snapshot| {
61 let span = self.trace.origin.span();
63 // First, we instantiate each bound region in the subtype with a fresh
66 self.infcx.replace_late_bound_regions_with_fresh_var(
71 // Second, we instantiate each bound region in the supertype with a
72 // fresh concrete region.
73 let (b_prime, skol_map) =
74 self.infcx.skolemize_late_bound_regions(b, snapshot);
76 debug!("a_prime={:?}", a_prime);
77 debug!("b_prime={:?}", b_prime);
79 // Compare types now that bound regions have been replaced.
80 let result = self.sub().relate(&a_prime, &b_prime)?;
82 // Presuming type comparison succeeds, we need to check
83 // that the skolemized regions do not "leak".
84 self.infcx.leak_check(!self.a_is_expected, span, &skol_map, snapshot)?;
86 // We are finished with the skolemized regions now so pop
88 self.infcx.pop_skolemized(skol_map, snapshot);
90 debug!("higher_ranked_sub: OK result={:?}", result);
92 Ok(ty::Binder(result))
96 /// The value consists of a pair `(t, u)` where `t` is the
97 /// *matcher* and `u` is a *value*. The idea is to find a
98 /// substitution `S` such that `S(t) == b`, and then return
99 /// `S(u)`. In other words, find values for the late-bound regions
100 /// in `a` that can make `t == b` and then replace the LBR in `u`
101 /// with those values.
103 /// This routine is (as of this writing) used in trait matching,
104 /// particularly projection.
106 /// NB. It should not happen that there are LBR appearing in `U`
107 /// that do not appear in `T`. If that happens, those regions are
108 /// unconstrained, and this routine replaces them with `'static`.
109 pub fn higher_ranked_match<T, U>(&self,
111 a_pair: &Binder<(T, U)>,
113 -> RelateResult<'tcx, HrMatchResult<U>>
114 where T: Relate<'tcx>,
115 U: TypeFoldable<'tcx>
117 debug!("higher_ranked_match(a={:?}, b={:?})",
120 // Start a snapshot so we can examine "all bindings that were
121 // created as part of this type comparison".
122 return self.infcx.commit_if_ok(|snapshot| {
123 // First, we instantiate each bound region in the matcher
124 // with a skolemized region.
125 let ((a_match, a_value), skol_map) =
126 self.infcx.skolemize_late_bound_regions(a_pair, snapshot);
128 debug!("higher_ranked_match: a_match={:?}", a_match);
129 debug!("higher_ranked_match: skol_map={:?}", skol_map);
131 // Equate types now that bound regions have been replaced.
132 try!(self.equate().relate(&a_match, &b_match));
134 // Map each skolemized region to a vector of other regions that it
135 // must be equated with. (Note that this vector may include other
136 // skolemized regions from `skol_map`.)
137 let skol_resolution_map: FnvHashMap<_, _> =
140 .map(|(&br, &skol)| {
141 let tainted_regions =
142 self.infcx.tainted_regions(snapshot,
144 TaintDirections::incoming()); // [1]
146 // [1] this routine executes after the skolemized
147 // regions have been *equated* with something
148 // else, so examining the incoming edges ought to
149 // be enough to collect all constraints
151 (skol, (br, tainted_regions))
155 // For each skolemized region, pick a representative -- which can
156 // be any region from the sets above, except for other members of
157 // `skol_map`. There should always be a representative if things
158 // are properly well-formed.
159 let mut unconstrained_regions = vec![];
160 let skol_representatives: FnvHashMap<_, _> =
163 .map(|(&skol, &(br, ref regions))| {
166 .filter(|r| !skol_resolution_map.contains_key(r))
169 .unwrap_or_else(|| { // [1]
170 unconstrained_regions.push(br);
171 self.infcx.next_region_var(
172 LateBoundRegion(span, br, HigherRankedType))
175 // [1] There should always be a representative,
176 // unless the higher-ranked region did not appear
177 // in the values being matched. We should reject
178 // as ill-formed cases that can lead to this, but
179 // right now we sometimes issue warnings (see
182 (skol, representative)
186 // Equate all the members of each skolemization set with the
188 for (skol, &(_br, ref regions)) in &skol_resolution_map {
189 let representative = &skol_representatives[skol];
190 debug!("higher_ranked_match: \
191 skol={:?} representative={:?} regions={:?}",
192 skol, representative, regions);
193 for region in regions.iter()
194 .filter(|&r| !skol_resolution_map.contains_key(r))
195 .filter(|&r| r != representative)
197 let origin = SubregionOrigin::Subtype(self.trace.clone());
198 self.infcx.region_vars.make_eqregion(origin,
204 // Replace the skolemized regions appearing in value with
205 // their representatives
210 |r, _| skol_representatives.get(&r).cloned().unwrap_or(r));
212 debug!("higher_ranked_match: value={:?}", a_value);
214 // We are now done with these skolemized variables.
215 self.infcx.pop_skolemized(skol_map, snapshot);
219 unconstrained_regions: unconstrained_regions,
224 pub fn higher_ranked_lub<T>(&self, a: &Binder<T>, b: &Binder<T>)
225 -> RelateResult<'tcx, Binder<T>>
226 where T: Relate<'tcx>
228 // Start a snapshot so we can examine "all bindings that were
229 // created as part of this type comparison".
230 return self.infcx.commit_if_ok(|snapshot| {
231 // Instantiate each bound region with a fresh region variable.
232 let span = self.trace.origin.span();
233 let (a_with_fresh, a_map) =
234 self.infcx.replace_late_bound_regions_with_fresh_var(
235 span, HigherRankedType, a);
236 let (b_with_fresh, _) =
237 self.infcx.replace_late_bound_regions_with_fresh_var(
238 span, HigherRankedType, b);
240 // Collect constraints.
242 self.lub().relate(&a_with_fresh, &b_with_fresh)?;
244 self.infcx.resolve_type_vars_if_possible(&result0);
245 debug!("lub result0 = {:?}", result0);
247 // Generalize the regions appearing in result0 if possible
248 let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot);
249 let span = self.trace.origin.span();
254 |r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn,
255 &new_vars, &a_map, r));
257 debug!("lub({:?},{:?}) = {:?}",
262 Ok(ty::Binder(result1))
265 fn generalize_region<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
267 snapshot: &CombinedSnapshot,
268 debruijn: ty::DebruijnIndex,
269 new_vars: &[ty::RegionVid],
270 a_map: &FnvHashMap<ty::BoundRegion, ty::Region>,
273 // Regions that pre-dated the LUB computation stay as they are.
274 if !is_var_in_set(new_vars, r0) {
275 assert!(!r0.is_bound());
276 debug!("generalize_region(r0={:?}): not new variable", r0);
280 let tainted = infcx.tainted_regions(snapshot, r0, TaintDirections::both());
282 // Variables created during LUB computation which are
283 // *related* to regions that pre-date the LUB computation
285 if !tainted.iter().all(|r| is_var_in_set(new_vars, *r)) {
286 debug!("generalize_region(r0={:?}): \
287 non-new-variables found in {:?}",
289 assert!(!r0.is_bound());
293 // Otherwise, the variable must be associated with at
294 // least one of the variables representing bound regions
295 // in both A and B. Replace the variable with the "first"
296 // bound region from A that we find it to be associated
298 for (a_br, a_r) in a_map {
299 if tainted.iter().any(|x| x == a_r) {
300 debug!("generalize_region(r0={:?}): \
301 replacing with {:?}, tainted={:?}",
303 return ty::ReLateBound(debruijn, *a_br);
309 "region {:?} is not associated with any bound region from A!",
314 pub fn higher_ranked_glb<T>(&self, a: &Binder<T>, b: &Binder<T>)
315 -> RelateResult<'tcx, Binder<T>>
316 where T: Relate<'tcx>
318 debug!("higher_ranked_glb({:?}, {:?})",
321 // Make a snapshot so we can examine "all bindings that were
322 // created as part of this type comparison".
323 return self.infcx.commit_if_ok(|snapshot| {
324 // Instantiate each bound region with a fresh region variable.
325 let (a_with_fresh, a_map) =
326 self.infcx.replace_late_bound_regions_with_fresh_var(
327 self.trace.origin.span(), HigherRankedType, a);
328 let (b_with_fresh, b_map) =
329 self.infcx.replace_late_bound_regions_with_fresh_var(
330 self.trace.origin.span(), HigherRankedType, b);
331 let a_vars = var_ids(self, &a_map);
332 let b_vars = var_ids(self, &b_map);
334 // Collect constraints.
336 self.glb().relate(&a_with_fresh, &b_with_fresh)?;
338 self.infcx.resolve_type_vars_if_possible(&result0);
339 debug!("glb result0 = {:?}", result0);
341 // Generalize the regions appearing in result0 if possible
342 let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot);
343 let span = self.trace.origin.span();
348 |r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn,
350 &a_map, &a_vars, &b_vars,
353 debug!("glb({:?},{:?}) = {:?}",
358 Ok(ty::Binder(result1))
361 fn generalize_region<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
363 snapshot: &CombinedSnapshot,
364 debruijn: ty::DebruijnIndex,
365 new_vars: &[ty::RegionVid],
366 a_map: &FnvHashMap<ty::BoundRegion, ty::Region>,
367 a_vars: &[ty::RegionVid],
368 b_vars: &[ty::RegionVid],
369 r0: ty::Region) -> ty::Region {
370 if !is_var_in_set(new_vars, r0) {
371 assert!(!r0.is_bound());
375 let tainted = infcx.tainted_regions(snapshot, r0, TaintDirections::both());
379 let mut only_new_vars = true;
381 if is_var_in_set(a_vars, *r) {
383 return fresh_bound_variable(infcx, debruijn);
387 } else if is_var_in_set(b_vars, *r) {
389 return fresh_bound_variable(infcx, debruijn);
393 } else if !is_var_in_set(new_vars, *r) {
394 only_new_vars = false;
398 // NB---I do not believe this algorithm computes
399 // (necessarily) the GLB. As written it can
400 // spuriously fail. In particular, if there is a case
401 // like: |fn(&a)| and fn(fn(&b)), where a and b are
402 // free, it will return fn(&c) where c = GLB(a,b). If
403 // however this GLB is not defined, then the result is
404 // an error, even though something like
405 // "fn<X>(fn(&X))" where X is bound would be a
406 // subtype of both of those.
408 // The problem is that if we were to return a bound
409 // variable, we'd be computing a lower-bound, but not
410 // necessarily the *greatest* lower-bound.
412 // Unfortunately, this problem is non-trivial to solve,
413 // because we do not know at the time of computing the GLB
414 // whether a GLB(a,b) exists or not, because we haven't
415 // run region inference (or indeed, even fully computed
416 // the region hierarchy!). The current algorithm seems to
417 // works ok in practice.
419 if a_r.is_some() && b_r.is_some() && only_new_vars {
420 // Related to exactly one bound variable from each fn:
421 return rev_lookup(span, a_map, a_r.unwrap());
422 } else if a_r.is_none() && b_r.is_none() {
423 // Not related to bound variables from either fn:
424 assert!(!r0.is_bound());
428 return fresh_bound_variable(infcx, debruijn);
432 fn rev_lookup(span: Span,
433 a_map: &FnvHashMap<ty::BoundRegion, ty::Region>,
434 r: ty::Region) -> ty::Region
436 for (a_br, a_r) in a_map {
438 return ty::ReLateBound(ty::DebruijnIndex::new(1), *a_br);
443 "could not find original bound region for {:?}",
447 fn fresh_bound_variable(infcx: &InferCtxt, debruijn: ty::DebruijnIndex) -> ty::Region {
448 infcx.region_vars.new_bound(debruijn)
453 fn var_ids<'a, 'gcx, 'tcx>(fields: &CombineFields<'a, 'gcx, 'tcx>,
454 map: &FnvHashMap<ty::BoundRegion, ty::Region>)
455 -> Vec<ty::RegionVid> {
457 .map(|(_, r)| match *r {
458 ty::ReVar(r) => { r }
461 fields.trace.origin.span(),
462 "found non-region-vid: {:?}",
469 fn is_var_in_set(new_vars: &[ty::RegionVid], r: ty::Region) -> bool {
471 ty::ReVar(ref v) => new_vars.iter().any(|x| x == v),
476 fn fold_regions_in<'a, 'gcx, 'tcx, T, F>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
480 where T: TypeFoldable<'tcx>,
481 F: FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region,
483 tcx.fold_regions(unbound_value, &mut false, |region, current_depth| {
484 // we should only be encountering "escaping" late-bound regions here,
485 // because the ones at the current level should have been replaced
486 // with fresh variables
487 assert!(match region {
488 ty::ReLateBound(..) => false,
492 fldr(region, ty::DebruijnIndex::new(current_depth))
496 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
497 fn tainted_regions(&self,
498 snapshot: &CombinedSnapshot,
500 directions: TaintDirections)
501 -> FnvHashSet<ty::Region> {
502 self.region_vars.tainted(&snapshot.region_vars_snapshot, r, directions)
505 fn region_vars_confined_to_snapshot(&self,
506 snapshot: &CombinedSnapshot)
507 -> Vec<ty::RegionVid>
510 * Returns the set of region variables that do not affect any
511 * types/regions which existed before `snapshot` was
512 * started. This is used in the sub/lub/glb computations. The
513 * idea here is that when we are computing lub/glb of two
514 * regions, we sometimes create intermediate region variables.
515 * Those region variables may touch some of the skolemized or
516 * other "forbidden" regions we created to replace bound
517 * regions, but they don't really represent an "external"
520 * However, sometimes fresh variables are created for other
521 * purposes too, and those *may* represent an external
522 * constraint. In particular, when a type variable is
523 * instantiated, we create region variables for all the
524 * regions that appear within, and if that type variable
525 * pre-existed the snapshot, then those region variables
526 * represent external constraints.
528 * An example appears in the unit test
529 * `sub_free_bound_false_infer`. In this test, we want to
533 * fn(_#0t) <: for<'a> fn(&'a int)
536 * Note that the subtype has a type variable. Because the type
537 * variable can't be instantiated with a region that is bound
538 * in the fn signature, this comparison ought to fail. But if
539 * we're not careful, it will succeed.
541 * The reason is that when we walk through the subtyping
542 * algorith, we begin by replacing `'a` with a skolemized
543 * variable `'1`. We then have `fn(_#0t) <: fn(&'1 int)`. This
544 * can be made true by unifying `_#0t` with `&'1 int`. In the
545 * process, we create a fresh variable for the skolemized
546 * region, `'$2`, and hence we have that `_#0t == &'$2
547 * int`. However, because `'$2` was created during the sub
548 * computation, if we're not careful we will erroneously
549 * assume it is one of the transient region variables
550 * representing a lub/glb internally. Not good.
552 * To prevent this, we check for type variables which were
553 * unified during the snapshot, and say that any region
554 * variable created during the snapshot but which finds its
555 * way into a type variable is considered to "escape" the
559 let mut region_vars =
560 self.region_vars.vars_created_since_snapshot(&snapshot.region_vars_snapshot);
563 self.type_variables.borrow_mut().types_escaping_snapshot(&snapshot.type_snapshot);
565 let mut escaping_region_vars = FnvHashSet();
566 for ty in &escaping_types {
567 self.tcx.collect_regions(ty, &mut escaping_region_vars);
570 region_vars.retain(|®ion_vid| {
571 let r = ty::ReVar(region_vid);
572 !escaping_region_vars.contains(&r)
575 debug!("region_vars_confined_to_snapshot: region_vars={:?} escaping_types={:?}",
582 /// Replace all regions bound by `binder` with skolemized regions and
583 /// return a map indicating which bound-region was replaced with what
584 /// skolemized region. This is the first step of checking subtyping
585 /// when higher-ranked things are involved.
587 /// **Important:** you must call this function from within a snapshot.
588 /// Moreover, before committing the snapshot, you must eventually call
589 /// either `plug_leaks` or `pop_skolemized` to remove the skolemized
590 /// regions. If you rollback the snapshot (or are using a probe), then
591 /// the pop occurs as part of the rollback, so an explicit call is not
592 /// needed (but is also permitted).
594 /// See `README.md` for more details.
595 pub fn skolemize_late_bound_regions<T>(&self,
596 binder: &ty::Binder<T>,
597 snapshot: &CombinedSnapshot)
598 -> (T, SkolemizationMap)
599 where T : TypeFoldable<'tcx>
601 let (result, map) = self.tcx.replace_late_bound_regions(binder, |br| {
602 self.region_vars.push_skolemized(br, &snapshot.region_vars_snapshot)
605 debug!("skolemize_bound_regions(binder={:?}, result={:?}, map={:?})",
613 /// Searches the region constriants created since `snapshot` was started
614 /// and checks to determine whether any of the skolemized regions created
615 /// in `skol_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 skol_map: &SkolemizationMap,
622 snapshot: &CombinedSnapshot)
623 -> RelateResult<'tcx, ()>
625 debug!("leak_check: skol_map={:?}",
628 // ## Issue #32330 warnings
630 // When Issue #32330 is fixed, a certain number of late-bound
631 // regions (LBR) will become early-bound. We wish to issue
632 // warnings when the result of `leak_check` relies on such LBR, as
633 // that means that compilation will likely start to fail.
635 // Recall that when we do a "HR subtype" check, we replace all
636 // late-bound regions (LBR) in the subtype with fresh variables,
637 // and skolemize the late-bound regions in the supertype. If those
638 // skolemized regions from the supertype wind up being
639 // super-regions (directly or indirectly) of either
641 // - another skolemized region; or,
642 // - some region that pre-exists the HR subtype check
643 // - e.g., a region variable that is not one of those created
644 // to represent bound regions in the subtype
646 // then leak-check (and hence the subtype check) fails.
648 // What will change when we fix #32330 is that some of the LBR in the
649 // subtype may become early-bound. In that case, they would no longer be in
650 // the "permitted set" of variables that can be related to a skolemized
653 // So the foundation for this warning is to collect variables that we found
654 // to be related to a skolemized type. For each of them, we have a
655 // `BoundRegion` which carries a `Issue32330` flag. We check whether any of
656 // those flags indicate that this variable was created from a lifetime
657 // that will change from late- to early-bound. If so, we issue a warning
658 // indicating that the results of compilation may change.
660 // This is imperfect, since there are other kinds of code that will not
661 // compile once #32330 is fixed. However, it fixes the errors observed in
662 // practice on crater runs.
663 let mut warnings = vec![];
665 let new_vars = self.region_vars_confined_to_snapshot(snapshot);
666 for (&skol_br, &skol) in skol_map {
667 // The inputs to a skolemized variable can only
668 // be itself or other new variables.
669 let incoming_taints = self.tainted_regions(snapshot,
671 TaintDirections::both());
672 for &tainted_region in &incoming_taints {
673 // Each skolemized should only be relatable to itself
675 match tainted_region {
677 if new_vars.contains(&vid) {
679 match self.region_vars.var_origin(vid) {
681 ty::BrNamed(_, _, wc),
689 if tainted_region == skol { continue; }
693 debug!("{:?} (which replaced {:?}) is tainted by {:?}",
698 if overly_polymorphic {
699 debug!("Overly polymorphic!");
700 return Err(TypeError::RegionsOverlyPolymorphic(skol_br,
703 debug!("Not as polymorphic!");
704 return Err(TypeError::RegionsInsufficientlyPolymorphic(skol_br,
710 self.issue_32330_warnings(span, &warnings);
715 /// This code converts from skolemized regions back to late-bound
716 /// regions. It works by replacing each region in the taint set of a
717 /// skolemized region with a bound-region. The bound region will be bound
718 /// by the outer-most binder in `value`; the caller must ensure that there is
719 /// such a binder and it is the right place.
721 /// This routine is only intended to be used when the leak-check has
722 /// passed; currently, it's used in the trait matching code to create
723 /// a set of nested obligations frmo an impl that matches against
724 /// something higher-ranked. More details can be found in
725 /// `librustc/middle/traits/README.md`.
727 /// As a brief example, consider the obligation `for<'a> Fn(&'a int)
728 /// -> &'a int`, and the impl:
730 /// impl<A,R> Fn<A,R> for SomethingOrOther
734 /// Here we will have replaced `'a` with a skolemized region
735 /// `'0`. This means that our substitution will be `{A=>&'0
736 /// int, R=>&'0 int}`.
738 /// When we apply the substitution to the bounds, we will wind up with
739 /// `&'0 int : Clone` as a predicate. As a last step, we then go and
740 /// replace `'0` with a late-bound region `'a`. The depth is matched
741 /// to the depth of the predicate, in this case 1, so that the final
742 /// predicate is `for<'a> &'a int : Clone`.
743 pub fn plug_leaks<T>(&self,
744 skol_map: SkolemizationMap,
745 snapshot: &CombinedSnapshot,
747 where T : TypeFoldable<'tcx>
749 debug!("plug_leaks(skol_map={:?}, value={:?})",
753 // Compute a mapping from the "taint set" of each skolemized
754 // region back to the `ty::BoundRegion` that it originally
755 // represented. Because `leak_check` passed, we know that
756 // these taint sets are mutually disjoint.
757 let inv_skol_map: FnvHashMap<ty::Region, ty::BoundRegion> =
760 .flat_map(|(&skol_br, &skol)| {
761 self.tainted_regions(snapshot, skol, TaintDirections::both())
763 .map(move |tainted_region| (tainted_region, skol_br))
767 debug!("plug_leaks: inv_skol_map={:?}",
770 // Remove any instantiated type variables from `value`; those can hide
771 // references to regions from the `fold_regions` code below.
772 let value = self.resolve_type_vars_if_possible(value);
774 // Map any skolemization byproducts back to a late-bound
775 // region. Put that late-bound region at whatever the outermost
776 // binder is that we encountered in `value`. The caller is
777 // responsible for ensuring that (a) `value` contains at least one
778 // binder and (b) that binder is the one we want to use.
779 let result = self.tcx.fold_regions(&value, &mut false, |r, current_depth| {
780 match inv_skol_map.get(&r) {
783 // It is the responsibility of the caller to ensure
784 // that each skolemized region appears within a
785 // binder. In practice, this routine is only used by
786 // trait checking, and all of the skolemized regions
787 // appear inside predicates, which always have
788 // binders, so this assert is satisfied.
789 assert!(current_depth > 1);
791 // since leak-check passed, this skolemized region
792 // should only have incoming edges from variables
793 // (which ought not to escape the snapshot, but we
794 // don't check that) or itself
797 ty::ReVar(_) => true,
798 ty::ReSkolemized(_, ref br1) => br == br1,
801 "leak-check would have us replace {:?} with {:?}",
804 ty::ReLateBound(ty::DebruijnIndex::new(current_depth - 1), br.clone())
809 debug!("plug_leaks: result={:?}",
812 self.pop_skolemized(skol_map, snapshot);
814 debug!("plug_leaks: result={:?}", result);
819 /// Pops the skolemized regions found in `skol_map` from the region
820 /// inference context. Whenever you create skolemized regions via
821 /// `skolemize_late_bound_regions`, they must be popped before you
822 /// commit the enclosing snapshot (if you do not commit, e.g. within a
823 /// probe or as a result of an error, then this is not necessary, as
824 /// popping happens as part of the rollback).
826 /// Note: popping also occurs implicitly as part of `leak_check`.
827 pub fn pop_skolemized(&self,
828 skol_map: SkolemizationMap,
829 snapshot: &CombinedSnapshot)
831 debug!("pop_skolemized({:?})", skol_map);
832 let skol_regions: FnvHashSet<_> = skol_map.values().cloned().collect();
833 self.region_vars.pop_skolemized(&skol_regions, &snapshot.region_vars_snapshot);