]> git.lizzy.rs Git - rust.git/blob - src/librustc/infer/higher_ranked/mod.rs
Rollup merge of #51765 - jonas-schievink:patch-1, r=KodrAus
[rust.git] / src / librustc / infer / higher_ranked / mod.rs
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.
4 //
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.
10
11 //! Helper routines for higher-ranked things. See the `doc` module at
12 //! the end of the file for details.
13
14 use super::{CombinedSnapshot,
15             InferCtxt,
16             HigherRankedType,
17             SubregionOrigin,
18             SkolemizationMap};
19 use super::combine::CombineFields;
20 use super::region_constraints::{TaintDirections};
21
22 use ty::{self, TyCtxt, Binder, TypeFoldable};
23 use ty::error::TypeError;
24 use ty::relate::{Relate, RelateResult, TypeRelation};
25 use std::collections::BTreeMap;
26 use syntax_pos::Span;
27 use util::nodemap::{FxHashMap, FxHashSet};
28
29 pub struct HrMatchResult<U> {
30     pub value: U,
31 }
32
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>>
36         where T: Relate<'tcx>
37     {
38         debug!("higher_ranked_sub(a={:?}, b={:?})",
39                a, b);
40
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
44         //
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
47         // `doc`.
48
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;
53
54             // First, we instantiate each bound region in the subtype with a fresh
55             // region variable.
56             let (a_prime, _) =
57                 self.infcx.replace_late_bound_regions_with_fresh_var(
58                     span,
59                     HigherRankedType,
60                     a);
61
62             // Second, we instantiate each bound region in the supertype with a
63             // fresh concrete region.
64             let (b_prime, skol_map) =
65                 self.infcx.skolemize_late_bound_regions(b);
66
67             debug!("a_prime={:?}", a_prime);
68             debug!("b_prime={:?}", b_prime);
69
70             // Compare types now that bound regions have been replaced.
71             let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?;
72
73             // Presuming type comparison succeeds, we need to check
74             // that the skolemized regions do not "leak".
75             self.infcx.leak_check(!a_is_expected, span, &skol_map, snapshot)?;
76
77             // We are finished with the skolemized regions now so pop
78             // them off.
79             self.infcx.pop_skolemized(skol_map, snapshot);
80
81             debug!("higher_ranked_sub: OK result={:?}", result);
82
83             Ok(ty::Binder::bind(result))
84         });
85     }
86
87     /// The value consists of a pair `(t, u)` where `t` is the
88     /// *matcher* and `u` is a *value*. The idea is to find a
89     /// substitution `S` such that `S(t) == b`, and then return
90     /// `S(u)`. In other words, find values for the late-bound regions
91     /// in `a` that can make `t == b` and then replace the LBR in `u`
92     /// with those values.
93     ///
94     /// This routine is (as of this writing) used in trait matching,
95     /// particularly projection.
96     ///
97     /// NB. It should not happen that there are LBR appearing in `U`
98     /// that do not appear in `T`. If that happens, those regions are
99     /// unconstrained, and this routine replaces them with `'static`.
100     pub fn higher_ranked_match<T, U>(&mut self,
101                                      a_pair: &Binder<(T, U)>,
102                                      b_match: &T,
103                                      a_is_expected: bool)
104                                      -> RelateResult<'tcx, HrMatchResult<U>>
105         where T: Relate<'tcx>,
106               U: TypeFoldable<'tcx>
107     {
108         debug!("higher_ranked_match(a={:?}, b={:?})",
109                a_pair, b_match);
110
111         // Start a snapshot so we can examine "all bindings that were
112         // created as part of this type comparison".
113         return self.infcx.commit_if_ok(|snapshot| {
114             // First, we instantiate each bound region in the matcher
115             // with a skolemized region.
116             let ((a_match, a_value), skol_map) =
117                 self.infcx.skolemize_late_bound_regions(a_pair);
118
119             debug!("higher_ranked_match: a_match={:?}", a_match);
120             debug!("higher_ranked_match: skol_map={:?}", skol_map);
121
122             // Equate types now that bound regions have been replaced.
123             self.equate(a_is_expected).relate(&a_match, &b_match)?;
124
125             // Map each skolemized region to a vector of other regions that it
126             // must be equated with. (Note that this vector may include other
127             // skolemized regions from `skol_map`.)
128             let skol_resolution_map: FxHashMap<_, _> =
129                 skol_map
130                 .iter()
131                 .map(|(&br, &skol)| {
132                     let tainted_regions =
133                         self.infcx.tainted_regions(snapshot,
134                                                    skol,
135                                                    TaintDirections::incoming()); // [1]
136
137                     // [1] this routine executes after the skolemized
138                     // regions have been *equated* with something
139                     // else, so examining the incoming edges ought to
140                     // be enough to collect all constraints
141
142                     (skol, (br, tainted_regions))
143                 })
144                 .collect();
145
146             // For each skolemized region, pick a representative -- which can
147             // be any region from the sets above, except for other members of
148             // `skol_map`. There should always be a representative if things
149             // are properly well-formed.
150             let skol_representatives: FxHashMap<_, _> =
151                 skol_resolution_map
152                 .iter()
153                 .map(|(&skol, &(_, ref regions))| {
154                     let representative =
155                         regions.iter()
156                                .filter(|&&r| !skol_resolution_map.contains_key(r))
157                                .cloned()
158                                .next()
159                                .unwrap_or_else(|| {
160                                    bug!("no representative region for `{:?}` in `{:?}`",
161                                         skol, regions)
162                                });
163
164                     (skol, representative)
165                 })
166                 .collect();
167
168             // Equate all the members of each skolemization set with the
169             // representative.
170             for (skol, &(_br, ref regions)) in &skol_resolution_map {
171                 let representative = &skol_representatives[skol];
172                 debug!("higher_ranked_match: \
173                         skol={:?} representative={:?} regions={:?}",
174                        skol, representative, regions);
175                 for region in regions.iter()
176                                      .filter(|&r| !skol_resolution_map.contains_key(r))
177                                      .filter(|&r| r != representative)
178                 {
179                     let origin = SubregionOrigin::Subtype(self.trace.clone());
180                     self.infcx.borrow_region_constraints()
181                               .make_eqregion(origin,
182                                              *representative,
183                                              *region);
184                 }
185             }
186
187             // Replace the skolemized regions appearing in value with
188             // their representatives
189             let a_value =
190                 fold_regions_in(
191                     self.tcx(),
192                     &a_value,
193                     |r, _| skol_representatives.get(&r).cloned().unwrap_or(r));
194
195             debug!("higher_ranked_match: value={:?}", a_value);
196
197             // We are now done with these skolemized variables.
198             self.infcx.pop_skolemized(skol_map, snapshot);
199
200             Ok(HrMatchResult { value: a_value })
201         });
202     }
203
204     pub fn higher_ranked_lub<T>(&mut self, a: &Binder<T>, b: &Binder<T>, a_is_expected: bool)
205                                 -> RelateResult<'tcx, Binder<T>>
206         where T: Relate<'tcx>
207     {
208         // Start a snapshot so we can examine "all bindings that were
209         // created as part of this type comparison".
210         return self.infcx.commit_if_ok(|snapshot| {
211             // Instantiate each bound region with a fresh region variable.
212             let span = self.trace.cause.span;
213             let (a_with_fresh, a_map) =
214                 self.infcx.replace_late_bound_regions_with_fresh_var(
215                     span, HigherRankedType, a);
216             let (b_with_fresh, _) =
217                 self.infcx.replace_late_bound_regions_with_fresh_var(
218                     span, HigherRankedType, b);
219
220             // Collect constraints.
221             let result0 =
222                 self.lub(a_is_expected).relate(&a_with_fresh, &b_with_fresh)?;
223             let result0 =
224                 self.infcx.resolve_type_vars_if_possible(&result0);
225             debug!("lub result0 = {:?}", result0);
226
227             // Generalize the regions appearing in result0 if possible
228             let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot);
229             let span = self.trace.cause.span;
230             let result1 =
231                 fold_regions_in(
232                     self.tcx(),
233                     &result0,
234                     |r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn,
235                                                     &new_vars, &a_map, r));
236
237             debug!("lub({:?},{:?}) = {:?}",
238                    a,
239                    b,
240                    result1);
241
242             Ok(ty::Binder::bind(result1))
243         });
244
245         fn generalize_region<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
246                                              span: Span,
247                                              snapshot: &CombinedSnapshot<'a, 'tcx>,
248                                              debruijn: ty::DebruijnIndex,
249                                              new_vars: &[ty::RegionVid],
250                                              a_map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>,
251                                              r0: ty::Region<'tcx>)
252                                              -> ty::Region<'tcx> {
253             // Regions that pre-dated the LUB computation stay as they are.
254             if !is_var_in_set(new_vars, r0) {
255                 assert!(!r0.is_late_bound());
256                 debug!("generalize_region(r0={:?}): not new variable", r0);
257                 return r0;
258             }
259
260             let tainted = infcx.tainted_regions(snapshot, r0, TaintDirections::both());
261
262             // Variables created during LUB computation which are
263             // *related* to regions that pre-date the LUB computation
264             // stay as they are.
265             if !tainted.iter().all(|&r| is_var_in_set(new_vars, r)) {
266                 debug!("generalize_region(r0={:?}): \
267                         non-new-variables found in {:?}",
268                        r0, tainted);
269                 assert!(!r0.is_late_bound());
270                 return r0;
271             }
272
273             // Otherwise, the variable must be associated with at
274             // least one of the variables representing bound regions
275             // in both A and B.  Replace the variable with the "first"
276             // bound region from A that we find it to be associated
277             // with.
278             for (a_br, a_r) in a_map {
279                 if tainted.iter().any(|x| x == a_r) {
280                     debug!("generalize_region(r0={:?}): \
281                             replacing with {:?}, tainted={:?}",
282                            r0, *a_br, tainted);
283                     return infcx.tcx.mk_region(ty::ReLateBound(debruijn, *a_br));
284                 }
285             }
286
287             span_bug!(
288                 span,
289                 "region {:?} is not associated with any bound region from A!",
290                 r0)
291         }
292     }
293
294     pub fn higher_ranked_glb<T>(&mut self, a: &Binder<T>, b: &Binder<T>, a_is_expected: bool)
295                                 -> RelateResult<'tcx, Binder<T>>
296         where T: Relate<'tcx>
297     {
298         debug!("higher_ranked_glb({:?}, {:?})",
299                a, b);
300
301         // Make a snapshot so we can examine "all bindings that were
302         // created as part of this type comparison".
303         return self.infcx.commit_if_ok(|snapshot| {
304             // Instantiate each bound region with a fresh region variable.
305             let (a_with_fresh, a_map) =
306                 self.infcx.replace_late_bound_regions_with_fresh_var(
307                     self.trace.cause.span, HigherRankedType, a);
308             let (b_with_fresh, b_map) =
309                 self.infcx.replace_late_bound_regions_with_fresh_var(
310                     self.trace.cause.span, HigherRankedType, b);
311             let a_vars = var_ids(self, &a_map);
312             let b_vars = var_ids(self, &b_map);
313
314             // Collect constraints.
315             let result0 =
316                 self.glb(a_is_expected).relate(&a_with_fresh, &b_with_fresh)?;
317             let result0 =
318                 self.infcx.resolve_type_vars_if_possible(&result0);
319             debug!("glb result0 = {:?}", result0);
320
321             // Generalize the regions appearing in result0 if possible
322             let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot);
323             let span = self.trace.cause.span;
324             let result1 =
325                 fold_regions_in(
326                     self.tcx(),
327                     &result0,
328                     |r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn,
329                                                     &new_vars,
330                                                     &a_map, &a_vars, &b_vars,
331                                                     r));
332
333             debug!("glb({:?},{:?}) = {:?}",
334                    a,
335                    b,
336                    result1);
337
338             Ok(ty::Binder::bind(result1))
339         });
340
341         fn generalize_region<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
342                                              span: Span,
343                                              snapshot: &CombinedSnapshot<'a, 'tcx>,
344                                              debruijn: ty::DebruijnIndex,
345                                              new_vars: &[ty::RegionVid],
346                                              a_map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>,
347                                              a_vars: &[ty::RegionVid],
348                                              b_vars: &[ty::RegionVid],
349                                              r0: ty::Region<'tcx>)
350                                              -> ty::Region<'tcx> {
351             if !is_var_in_set(new_vars, r0) {
352                 assert!(!r0.is_late_bound());
353                 return r0;
354             }
355
356             let tainted = infcx.tainted_regions(snapshot, r0, TaintDirections::both());
357
358             let mut a_r = None;
359             let mut b_r = None;
360             let mut only_new_vars = true;
361             for r in &tainted {
362                 if is_var_in_set(a_vars, *r) {
363                     if a_r.is_some() {
364                         return fresh_bound_variable(infcx, debruijn);
365                     } else {
366                         a_r = Some(*r);
367                     }
368                 } else if is_var_in_set(b_vars, *r) {
369                     if b_r.is_some() {
370                         return fresh_bound_variable(infcx, debruijn);
371                     } else {
372                         b_r = Some(*r);
373                     }
374                 } else if !is_var_in_set(new_vars, *r) {
375                     only_new_vars = false;
376                 }
377             }
378
379             // NB---I do not believe this algorithm computes
380             // (necessarily) the GLB.  As written it can
381             // spuriously fail. In particular, if there is a case
382             // like: |fn(&a)| and fn(fn(&b)), where a and b are
383             // free, it will return fn(&c) where c = GLB(a,b).  If
384             // however this GLB is not defined, then the result is
385             // an error, even though something like
386             // "fn<X>(fn(&X))" where X is bound would be a
387             // subtype of both of those.
388             //
389             // The problem is that if we were to return a bound
390             // variable, we'd be computing a lower-bound, but not
391             // necessarily the *greatest* lower-bound.
392             //
393             // Unfortunately, this problem is non-trivial to solve,
394             // because we do not know at the time of computing the GLB
395             // whether a GLB(a,b) exists or not, because we haven't
396             // run region inference (or indeed, even fully computed
397             // the region hierarchy!). The current algorithm seems to
398             // works ok in practice.
399
400             if a_r.is_some() && b_r.is_some() && only_new_vars {
401                 // Related to exactly one bound variable from each fn:
402                 return rev_lookup(infcx, span, a_map, a_r.unwrap());
403             } else if a_r.is_none() && b_r.is_none() {
404                 // Not related to bound variables from either fn:
405                 assert!(!r0.is_late_bound());
406                 return r0;
407             } else {
408                 // Other:
409                 return fresh_bound_variable(infcx, debruijn);
410             }
411         }
412
413         fn rev_lookup<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
414                                       span: Span,
415                                       a_map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>,
416                                       r: ty::Region<'tcx>) -> ty::Region<'tcx>
417         {
418             for (a_br, a_r) in a_map {
419                 if *a_r == r {
420                     return infcx.tcx.mk_region(ty::ReLateBound(ty::INNERMOST, *a_br));
421                 }
422             }
423             span_bug!(
424                 span,
425                 "could not find original bound region for {:?}",
426                 r);
427         }
428
429         fn fresh_bound_variable<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
430                                                 debruijn: ty::DebruijnIndex)
431                                                 -> ty::Region<'tcx> {
432             infcx.borrow_region_constraints().new_bound(infcx.tcx, debruijn)
433         }
434     }
435 }
436
437 fn var_ids<'a, 'gcx, 'tcx>(fields: &CombineFields<'a, 'gcx, 'tcx>,
438                            map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
439                            -> Vec<ty::RegionVid> {
440     map.iter()
441        .map(|(_, &r)| match *r {
442            ty::ReVar(r) => { r }
443            _ => {
444                span_bug!(
445                    fields.trace.cause.span,
446                    "found non-region-vid: {:?}",
447                    r);
448            }
449        })
450        .collect()
451 }
452
453 fn is_var_in_set(new_vars: &[ty::RegionVid], r: ty::Region) -> bool {
454     match *r {
455         ty::ReVar(ref v) => new_vars.iter().any(|x| x == v),
456         _ => false
457     }
458 }
459
460 fn fold_regions_in<'a, 'gcx, 'tcx, T, F>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
461                                          unbound_value: &T,
462                                          mut fldr: F)
463                                          -> T
464     where T: TypeFoldable<'tcx>,
465           F: FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx>,
466 {
467     tcx.fold_regions(unbound_value, &mut false, |region, current_depth| {
468         // we should only be encountering "escaping" late-bound regions here,
469         // because the ones at the current level should have been replaced
470         // with fresh variables
471         assert!(match *region {
472             ty::ReLateBound(..) => false,
473             _ => true
474         });
475
476         fldr(region, current_depth)
477     })
478 }
479
480 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
481     fn tainted_regions(&self,
482                        snapshot: &CombinedSnapshot<'a, 'tcx>,
483                        r: ty::Region<'tcx>,
484                        directions: TaintDirections)
485                        -> FxHashSet<ty::Region<'tcx>> {
486         self.borrow_region_constraints().tainted(
487             self.tcx,
488             &snapshot.region_constraints_snapshot,
489             r,
490             directions)
491     }
492
493     fn region_vars_confined_to_snapshot(&self,
494                                         snapshot: &CombinedSnapshot<'a, 'tcx>)
495                                         -> Vec<ty::RegionVid>
496     {
497         /*!
498          * Returns the set of region variables that do not affect any
499          * types/regions which existed before `snapshot` was
500          * started. This is used in the sub/lub/glb computations. The
501          * idea here is that when we are computing lub/glb of two
502          * regions, we sometimes create intermediate region variables.
503          * Those region variables may touch some of the skolemized or
504          * other "forbidden" regions we created to replace bound
505          * regions, but they don't really represent an "external"
506          * constraint.
507          *
508          * However, sometimes fresh variables are created for other
509          * purposes too, and those *may* represent an external
510          * constraint. In particular, when a type variable is
511          * instantiated, we create region variables for all the
512          * regions that appear within, and if that type variable
513          * pre-existed the snapshot, then those region variables
514          * represent external constraints.
515          *
516          * An example appears in the unit test
517          * `sub_free_bound_false_infer`.  In this test, we want to
518          * know whether
519          *
520          * ```rust
521          * fn(_#0t) <: for<'a> fn(&'a int)
522          * ```
523          *
524          * Note that the subtype has a type variable. Because the type
525          * variable can't be instantiated with a region that is bound
526          * in the fn signature, this comparison ought to fail. But if
527          * we're not careful, it will succeed.
528          *
529          * The reason is that when we walk through the subtyping
530          * algorith, we begin by replacing `'a` with a skolemized
531          * variable `'1`. We then have `fn(_#0t) <: fn(&'1 int)`. This
532          * can be made true by unifying `_#0t` with `&'1 int`. In the
533          * process, we create a fresh variable for the skolemized
534          * region, `'$2`, and hence we have that `_#0t == &'$2
535          * int`. However, because `'$2` was created during the sub
536          * computation, if we're not careful we will erroneously
537          * assume it is one of the transient region variables
538          * representing a lub/glb internally. Not good.
539          *
540          * To prevent this, we check for type variables which were
541          * unified during the snapshot, and say that any region
542          * variable created during the snapshot but which finds its
543          * way into a type variable is considered to "escape" the
544          * snapshot.
545          */
546
547         let mut region_vars =
548             self.borrow_region_constraints().vars_created_since_snapshot(
549                 &snapshot.region_constraints_snapshot);
550
551         let escaping_types =
552             self.type_variables.borrow_mut().types_escaping_snapshot(&snapshot.type_snapshot);
553
554         let mut escaping_region_vars = FxHashSet();
555         for ty in &escaping_types {
556             self.tcx.collect_regions(ty, &mut escaping_region_vars);
557         }
558
559         region_vars.retain(|&region_vid| {
560             let r = ty::ReVar(region_vid);
561             !escaping_region_vars.contains(&r)
562         });
563
564         debug!("region_vars_confined_to_snapshot: region_vars={:?} escaping_types={:?}",
565                region_vars,
566                escaping_types);
567
568         region_vars
569     }
570
571     /// Replace all regions bound by `binder` with skolemized regions and
572     /// return a map indicating which bound-region was replaced with what
573     /// skolemized region. This is the first step of checking subtyping
574     /// when higher-ranked things are involved.
575     ///
576     /// **Important:** you must call this function from within a snapshot.
577     /// Moreover, before committing the snapshot, you must eventually call
578     /// either `plug_leaks` or `pop_skolemized` to remove the skolemized
579     /// regions. If you rollback the snapshot (or are using a probe), then
580     /// the pop occurs as part of the rollback, so an explicit call is not
581     /// needed (but is also permitted).
582     ///
583     /// For more information about how skolemization for HRTBs works, see
584     /// the [rustc guide].
585     ///
586     /// [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/traits/hrtb.html
587     pub fn skolemize_late_bound_regions<T>(&self,
588                                            binder: &ty::Binder<T>)
589                                            -> (T, SkolemizationMap<'tcx>)
590         where T : TypeFoldable<'tcx>
591     {
592         let (result, map) = self.tcx.replace_late_bound_regions(binder, |br| {
593             self.universe.set(self.universe().subuniverse());
594             self.tcx.mk_region(ty::ReSkolemized(self.universe(), br))
595         });
596
597         debug!("skolemize_bound_regions(binder={:?}, result={:?}, map={:?})",
598                binder,
599                result,
600                map);
601
602         (result, map)
603     }
604
605     /// Searches the region constraints created since `snapshot` was started
606     /// and checks to determine whether any of the skolemized regions created
607     /// in `skol_map` would "escape" -- meaning that they are related to
608     /// other regions in some way. If so, the higher-ranked subtyping doesn't
609     /// hold. See `README.md` for more details.
610     pub fn leak_check(&self,
611                       overly_polymorphic: bool,
612                       _span: Span,
613                       skol_map: &SkolemizationMap<'tcx>,
614                       snapshot: &CombinedSnapshot<'a, 'tcx>)
615                       -> RelateResult<'tcx, ()>
616     {
617         debug!("leak_check: skol_map={:?}",
618                skol_map);
619
620         let new_vars = self.region_vars_confined_to_snapshot(snapshot);
621         for (&skol_br, &skol) in skol_map {
622             // The inputs to a skolemized variable can only
623             // be itself or other new variables.
624             let incoming_taints = self.tainted_regions(snapshot,
625                                                        skol,
626                                                        TaintDirections::both());
627             for &tainted_region in &incoming_taints {
628                 // Each skolemized should only be relatable to itself
629                 // or new variables:
630                 match *tainted_region {
631                     ty::ReVar(vid) => {
632                         if new_vars.contains(&vid) {
633                             continue;
634                         }
635                     }
636                     _ => {
637                         if tainted_region == skol { continue; }
638                     }
639                 };
640
641                 debug!("{:?} (which replaced {:?}) is tainted by {:?}",
642                        skol,
643                        skol_br,
644                        tainted_region);
645
646                 return Err(if overly_polymorphic {
647                     debug!("Overly polymorphic!");
648                     TypeError::RegionsOverlyPolymorphic(skol_br, tainted_region)
649                 } else {
650                     debug!("Not as polymorphic!");
651                     TypeError::RegionsInsufficientlyPolymorphic(skol_br, tainted_region)
652                 })
653             }
654         }
655
656         Ok(())
657     }
658
659     /// This code converts from skolemized regions back to late-bound
660     /// regions. It works by replacing each region in the taint set of a
661     /// skolemized region with a bound-region. The bound region will be bound
662     /// by the outer-most binder in `value`; the caller must ensure that there is
663     /// such a binder and it is the right place.
664     ///
665     /// This routine is only intended to be used when the leak-check has
666     /// passed; currently, it's used in the trait matching code to create
667     /// a set of nested obligations frmo an impl that matches against
668     /// something higher-ranked.  More details can be found in
669     /// `librustc/middle/traits/README.md`.
670     ///
671     /// As a brief example, consider the obligation `for<'a> Fn(&'a int)
672     /// -> &'a int`, and the impl:
673     ///
674     ///     impl<A,R> Fn<A,R> for SomethingOrOther
675     ///         where A : Clone
676     ///     { ... }
677     ///
678     /// Here we will have replaced `'a` with a skolemized region
679     /// `'0`. This means that our substitution will be `{A=>&'0
680     /// int, R=>&'0 int}`.
681     ///
682     /// When we apply the substitution to the bounds, we will wind up with
683     /// `&'0 int : Clone` as a predicate. As a last step, we then go and
684     /// replace `'0` with a late-bound region `'a`.  The depth is matched
685     /// to the depth of the predicate, in this case 1, so that the final
686     /// predicate is `for<'a> &'a int : Clone`.
687     pub fn plug_leaks<T>(&self,
688                          skol_map: SkolemizationMap<'tcx>,
689                          snapshot: &CombinedSnapshot<'a, 'tcx>,
690                          value: T) -> T
691         where T : TypeFoldable<'tcx>
692     {
693         debug!("plug_leaks(skol_map={:?}, value={:?})",
694                skol_map,
695                value);
696
697         if skol_map.is_empty() {
698             return value;
699         }
700
701         // Compute a mapping from the "taint set" of each skolemized
702         // region back to the `ty::BoundRegion` that it originally
703         // represented. Because `leak_check` passed, we know that
704         // these taint sets are mutually disjoint.
705         let inv_skol_map: FxHashMap<ty::Region<'tcx>, ty::BoundRegion> =
706             skol_map
707             .iter()
708             .flat_map(|(&skol_br, &skol)| {
709                 self.tainted_regions(snapshot, skol, TaintDirections::both())
710                     .into_iter()
711                     .map(move |tainted_region| (tainted_region, skol_br))
712             })
713             .collect();
714
715         debug!("plug_leaks: inv_skol_map={:?}",
716                inv_skol_map);
717
718         // Remove any instantiated type variables from `value`; those can hide
719         // references to regions from the `fold_regions` code below.
720         let value = self.resolve_type_vars_if_possible(&value);
721
722         // Map any skolemization byproducts back to a late-bound
723         // region. Put that late-bound region at whatever the outermost
724         // binder is that we encountered in `value`. The caller is
725         // responsible for ensuring that (a) `value` contains at least one
726         // binder and (b) that binder is the one we want to use.
727         let result = self.tcx.fold_regions(&value, &mut false, |r, current_depth| {
728             match inv_skol_map.get(&r) {
729                 None => r,
730                 Some(br) => {
731                     // It is the responsibility of the caller to ensure
732                     // that each skolemized region appears within a
733                     // binder. In practice, this routine is only used by
734                     // trait checking, and all of the skolemized regions
735                     // appear inside predicates, which always have
736                     // binders, so this assert is satisfied.
737                     assert!(current_depth > ty::INNERMOST);
738
739                     // since leak-check passed, this skolemized region
740                     // should only have incoming edges from variables
741                     // (which ought not to escape the snapshot, but we
742                     // don't check that) or itself
743                     assert!(
744                         match *r {
745                             ty::ReVar(_) => true,
746                             ty::ReSkolemized(_, ref br1) => br == br1,
747                             _ => false,
748                         },
749                         "leak-check would have us replace {:?} with {:?}",
750                         r, br);
751
752                     self.tcx.mk_region(ty::ReLateBound(
753                         current_depth.shifted_out(1),
754                         br.clone(),
755                     ))
756                 }
757             }
758         });
759
760         self.pop_skolemized(skol_map, snapshot);
761
762         debug!("plug_leaks: result={:?}", result);
763
764         result
765     }
766
767     /// Pops the skolemized regions found in `skol_map` from the region
768     /// inference context. Whenever you create skolemized regions via
769     /// `skolemize_late_bound_regions`, they must be popped before you
770     /// commit the enclosing snapshot (if you do not commit, e.g. within a
771     /// probe or as a result of an error, then this is not necessary, as
772     /// popping happens as part of the rollback).
773     ///
774     /// Note: popping also occurs implicitly as part of `leak_check`.
775     pub fn pop_skolemized(&self,
776                           skol_map: SkolemizationMap<'tcx>,
777                           snapshot: &CombinedSnapshot<'a, 'tcx>) {
778         debug!("pop_skolemized({:?})", skol_map);
779         let skol_regions: FxHashSet<_> = skol_map.values().cloned().collect();
780         self.borrow_region_constraints()
781             .pop_skolemized(self.universe(), &skol_regions, &snapshot.region_constraints_snapshot);
782         self.universe.set(snapshot.universe);
783         if !skol_map.is_empty() {
784             self.projection_cache.borrow_mut().rollback_skolemized(
785                 &snapshot.projection_cache_snapshot);
786         }
787     }
788 }