]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/subst.rs
check: Reword the warning to be more prescriptive
[rust.git] / src / librustc / middle / subst.rs
1 // Copyright 2012 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 // Type substitutions.
12
13 pub use self::ParamSpace::*;
14 pub use self::RegionSubsts::*;
15
16 use middle::ty::{self, Ty};
17 use middle::ty_fold::{self, TypeFoldable, TypeFolder};
18 use util::ppaux::Repr;
19
20 use std::fmt;
21 use std::iter::IntoIterator;
22 use std::slice::Iter;
23 use std::vec::{Vec, IntoIter};
24 use syntax::codemap::{Span, DUMMY_SP};
25
26 ///////////////////////////////////////////////////////////////////////////
27
28 /// A substitution mapping type/region parameters to new values. We
29 /// identify each in-scope parameter by an *index* and a *parameter
30 /// space* (which indices where the parameter is defined; see
31 /// `ParamSpace`).
32 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
33 pub struct Substs<'tcx> {
34     pub types: VecPerParamSpace<Ty<'tcx>>,
35     pub regions: RegionSubsts,
36 }
37
38 /// Represents the values to use when substituting lifetime parameters.
39 /// If the value is `ErasedRegions`, then this subst is occurring during
40 /// trans, and all region parameters will be replaced with `ty::ReStatic`.
41 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
42 pub enum RegionSubsts {
43     ErasedRegions,
44     NonerasedRegions(VecPerParamSpace<ty::Region>)
45 }
46
47 impl<'tcx> Substs<'tcx> {
48     pub fn new(t: VecPerParamSpace<Ty<'tcx>>,
49                r: VecPerParamSpace<ty::Region>)
50                -> Substs<'tcx>
51     {
52         Substs { types: t, regions: NonerasedRegions(r) }
53     }
54
55     pub fn new_type(t: Vec<Ty<'tcx>>,
56                     r: Vec<ty::Region>)
57                     -> Substs<'tcx>
58     {
59         Substs::new(VecPerParamSpace::new(t, Vec::new(), Vec::new()),
60                     VecPerParamSpace::new(r, Vec::new(), Vec::new()))
61     }
62
63     pub fn new_trait(t: Vec<Ty<'tcx>>,
64                      r: Vec<ty::Region>,
65                      s: Ty<'tcx>)
66                     -> Substs<'tcx>
67     {
68         Substs::new(VecPerParamSpace::new(t, vec!(s), Vec::new()),
69                     VecPerParamSpace::new(r, Vec::new(), Vec::new()))
70     }
71
72     pub fn erased(t: VecPerParamSpace<Ty<'tcx>>) -> Substs<'tcx>
73     {
74         Substs { types: t, regions: ErasedRegions }
75     }
76
77     pub fn empty() -> Substs<'tcx> {
78         Substs {
79             types: VecPerParamSpace::empty(),
80             regions: NonerasedRegions(VecPerParamSpace::empty()),
81         }
82     }
83
84     pub fn trans_empty() -> Substs<'tcx> {
85         Substs {
86             types: VecPerParamSpace::empty(),
87             regions: ErasedRegions
88         }
89     }
90
91     pub fn is_noop(&self) -> bool {
92         let regions_is_noop = match self.regions {
93             ErasedRegions => false, // may be used to canonicalize
94             NonerasedRegions(ref regions) => regions.is_empty(),
95         };
96
97         regions_is_noop && self.types.is_empty()
98     }
99
100     pub fn type_for_def(&self, ty_param_def: &ty::TypeParameterDef) -> Ty<'tcx> {
101         *self.types.get(ty_param_def.space, ty_param_def.index as uint)
102     }
103
104     pub fn has_regions_escaping_depth(&self, depth: u32) -> bool {
105         self.types.iter().any(|&t| ty::type_escapes_depth(t, depth)) || {
106             match self.regions {
107                 ErasedRegions =>
108                     false,
109                 NonerasedRegions(ref regions) =>
110                     regions.iter().any(|r| r.escapes_depth(depth)),
111             }
112         }
113     }
114
115     pub fn self_ty(&self) -> Option<Ty<'tcx>> {
116         self.types.get_self().cloned()
117     }
118
119     pub fn with_self_ty(&self, self_ty: Ty<'tcx>) -> Substs<'tcx> {
120         assert!(self.self_ty().is_none());
121         let mut s = (*self).clone();
122         s.types.push(SelfSpace, self_ty);
123         s
124     }
125
126     pub fn erase_regions(self) -> Substs<'tcx> {
127         let Substs { types, regions: _ } = self;
128         Substs { types: types, regions: ErasedRegions }
129     }
130
131     /// Since ErasedRegions are only to be used in trans, most of the compiler can use this method
132     /// to easily access the set of region substitutions.
133     pub fn regions<'a>(&'a self) -> &'a VecPerParamSpace<ty::Region> {
134         match self.regions {
135             ErasedRegions => panic!("Erased regions only expected in trans"),
136             NonerasedRegions(ref r) => r
137         }
138     }
139
140     /// Since ErasedRegions are only to be used in trans, most of the compiler can use this method
141     /// to easily access the set of region substitutions.
142     pub fn mut_regions<'a>(&'a mut self) -> &'a mut VecPerParamSpace<ty::Region> {
143         match self.regions {
144             ErasedRegions => panic!("Erased regions only expected in trans"),
145             NonerasedRegions(ref mut r) => r
146         }
147     }
148
149     pub fn with_method(self,
150                        m_types: Vec<Ty<'tcx>>,
151                        m_regions: Vec<ty::Region>)
152                        -> Substs<'tcx>
153     {
154         let Substs { types, regions } = self;
155         let types = types.with_vec(FnSpace, m_types);
156         let regions = regions.map(m_regions,
157                                   |r, m_regions| r.with_vec(FnSpace, m_regions));
158         Substs { types: types, regions: regions }
159     }
160 }
161
162 impl RegionSubsts {
163     fn map<A, F>(self, a: A, op: F) -> RegionSubsts where
164         F: FnOnce(VecPerParamSpace<ty::Region>, A) -> VecPerParamSpace<ty::Region>,
165     {
166         match self {
167             ErasedRegions => ErasedRegions,
168             NonerasedRegions(r) => NonerasedRegions(op(r, a))
169         }
170     }
171
172     pub fn is_erased(&self) -> bool {
173         match *self {
174             ErasedRegions => true,
175             NonerasedRegions(_) => false,
176         }
177     }
178 }
179
180 ///////////////////////////////////////////////////////////////////////////
181 // ParamSpace
182
183 #[derive(PartialOrd, Ord, PartialEq, Eq, Copy,
184            Clone, Hash, RustcEncodable, RustcDecodable, Debug)]
185 pub enum ParamSpace {
186     TypeSpace,  // Type parameters attached to a type definition, trait, or impl
187     SelfSpace,  // Self parameter on a trait
188     FnSpace,    // Type parameters attached to a method or fn
189 }
190
191 impl ParamSpace {
192     pub fn all() -> [ParamSpace; 3] {
193         [TypeSpace, SelfSpace, FnSpace]
194     }
195
196     pub fn to_uint(self) -> uint {
197         match self {
198             TypeSpace => 0,
199             SelfSpace => 1,
200             FnSpace => 2,
201         }
202     }
203
204     pub fn from_uint(u: uint) -> ParamSpace {
205         match u {
206             0 => TypeSpace,
207             1 => SelfSpace,
208             2 => FnSpace,
209             _ => panic!("Invalid ParamSpace: {}", u)
210         }
211     }
212 }
213
214 /// Vector of things sorted by param space. Used to keep
215 /// the set of things declared on the type, self, or method
216 /// distinct.
217 #[derive(PartialEq, Eq, Clone, Hash, RustcEncodable, RustcDecodable)]
218 pub struct VecPerParamSpace<T> {
219     // This was originally represented as a tuple with one Vec<T> for
220     // each variant of ParamSpace, and that remains the abstraction
221     // that it provides to its clients.
222     //
223     // Here is how the representation corresponds to the abstraction
224     // i.e. the "abstraction function" AF:
225     //
226     // AF(self) = (self.content[..self.type_limit],
227     //             self.content[self.type_limit..self.self_limit],
228     //             self.content[self.self_limit..])
229     type_limit: uint,
230     self_limit: uint,
231     content: Vec<T>,
232 }
233
234 /// The `split` function converts one `VecPerParamSpace` into this
235 /// `SeparateVecsPerParamSpace` structure.
236 pub struct SeparateVecsPerParamSpace<T> {
237     pub types: Vec<T>,
238     pub selfs: Vec<T>,
239     pub fns: Vec<T>,
240 }
241
242 impl<T: fmt::Debug> fmt::Debug for VecPerParamSpace<T> {
243     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
244         try!(write!(fmt, "VecPerParamSpace {{"));
245         for space in &ParamSpace::all() {
246             try!(write!(fmt, "{:?}: {:?}, ", *space, self.get_slice(*space)));
247         }
248         try!(write!(fmt, "}}"));
249         Ok(())
250     }
251 }
252
253 impl<T> VecPerParamSpace<T> {
254     fn limits(&self, space: ParamSpace) -> (uint, uint) {
255         match space {
256             TypeSpace => (0, self.type_limit),
257             SelfSpace => (self.type_limit, self.self_limit),
258             FnSpace => (self.self_limit, self.content.len()),
259         }
260     }
261
262     pub fn empty() -> VecPerParamSpace<T> {
263         VecPerParamSpace {
264             type_limit: 0,
265             self_limit: 0,
266             content: Vec::new()
267         }
268     }
269
270     pub fn params_from_type(types: Vec<T>) -> VecPerParamSpace<T> {
271         VecPerParamSpace::empty().with_vec(TypeSpace, types)
272     }
273
274     /// `t` is the type space.
275     /// `s` is the self space.
276     /// `a` is the assoc space.
277     /// `f` is the fn space.
278     pub fn new(t: Vec<T>, s: Vec<T>, f: Vec<T>) -> VecPerParamSpace<T> {
279         let type_limit = t.len();
280         let self_limit = type_limit + s.len();
281
282         let mut content = t;
283         content.extend(s.into_iter());
284         content.extend(f.into_iter());
285
286         VecPerParamSpace {
287             type_limit: type_limit,
288             self_limit: self_limit,
289             content: content,
290         }
291     }
292
293     fn new_internal(content: Vec<T>, type_limit: uint, self_limit: uint)
294                     -> VecPerParamSpace<T>
295     {
296         VecPerParamSpace {
297             type_limit: type_limit,
298             self_limit: self_limit,
299             content: content,
300         }
301     }
302
303     /// Appends `value` to the vector associated with `space`.
304     ///
305     /// Unlike the `push` method in `Vec`, this should not be assumed
306     /// to be a cheap operation (even when amortized over many calls).
307     pub fn push(&mut self, space: ParamSpace, value: T) {
308         let (_, limit) = self.limits(space);
309         match space {
310             TypeSpace => { self.type_limit += 1; self.self_limit += 1; }
311             SelfSpace => { self.self_limit += 1; }
312             FnSpace => { }
313         }
314         self.content.insert(limit, value);
315     }
316
317     /// Appends `values` to the vector associated with `space`.
318     ///
319     /// Unlike the `extend` method in `Vec`, this should not be assumed
320     /// to be a cheap operation (even when amortized over many calls).
321     pub fn extend<I:Iterator<Item=T>>(&mut self, space: ParamSpace, values: I) {
322         // This could be made more efficient, obviously.
323         for item in values {
324             self.push(space, item);
325         }
326     }
327
328     pub fn pop(&mut self, space: ParamSpace) -> Option<T> {
329         let (start, limit) = self.limits(space);
330         if start == limit {
331             None
332         } else {
333             match space {
334                 TypeSpace => { self.type_limit -= 1; self.self_limit -= 1; }
335                 SelfSpace => { self.self_limit -= 1; }
336                 FnSpace => {}
337             }
338             if self.content.is_empty() {
339                 None
340             } else {
341                 Some(self.content.remove(limit - 1))
342             }
343         }
344     }
345
346     pub fn truncate(&mut self, space: ParamSpace, len: uint) {
347         // FIXME (#15435): slow; O(n^2); could enhance vec to make it O(n).
348         while self.len(space) > len {
349             self.pop(space);
350         }
351     }
352
353     pub fn replace(&mut self, space: ParamSpace, elems: Vec<T>) {
354         // FIXME (#15435): slow; O(n^2); could enhance vec to make it O(n).
355         self.truncate(space, 0);
356         for t in elems {
357             self.push(space, t);
358         }
359     }
360
361     pub fn get_self<'a>(&'a self) -> Option<&'a T> {
362         let v = self.get_slice(SelfSpace);
363         assert!(v.len() <= 1);
364         if v.len() == 0 { None } else { Some(&v[0]) }
365     }
366
367     pub fn len(&self, space: ParamSpace) -> uint {
368         self.get_slice(space).len()
369     }
370
371     pub fn is_empty_in(&self, space: ParamSpace) -> bool {
372         self.len(space) == 0
373     }
374
375     pub fn get_slice<'a>(&'a self, space: ParamSpace) -> &'a [T] {
376         let (start, limit) = self.limits(space);
377         &self.content[start.. limit]
378     }
379
380     pub fn get_mut_slice<'a>(&'a mut self, space: ParamSpace) -> &'a mut [T] {
381         let (start, limit) = self.limits(space);
382         &mut self.content[start.. limit]
383     }
384
385     pub fn opt_get<'a>(&'a self,
386                        space: ParamSpace,
387                        index: uint)
388                        -> Option<&'a T> {
389         let v = self.get_slice(space);
390         if index < v.len() { Some(&v[index]) } else { None }
391     }
392
393     pub fn get<'a>(&'a self, space: ParamSpace, index: uint) -> &'a T {
394         &self.get_slice(space)[index]
395     }
396
397     pub fn iter<'a>(&'a self) -> Iter<'a,T> {
398         self.content.iter()
399     }
400
401     pub fn into_iter(self) -> IntoIter<T> {
402         self.content.into_iter()
403     }
404
405     pub fn iter_enumerated<'a>(&'a self) -> EnumeratedItems<'a,T> {
406         EnumeratedItems::new(self)
407     }
408
409     pub fn as_slice(&self) -> &[T] {
410         &self.content
411     }
412
413     pub fn into_vec(self) -> Vec<T> {
414         self.content
415     }
416
417     pub fn all_vecs<P>(&self, mut pred: P) -> bool where
418         P: FnMut(&[T]) -> bool,
419     {
420         let spaces = [TypeSpace, SelfSpace, FnSpace];
421         spaces.iter().all(|&space| { pred(self.get_slice(space)) })
422     }
423
424     pub fn all<P>(&self, pred: P) -> bool where P: FnMut(&T) -> bool {
425         self.iter().all(pred)
426     }
427
428     pub fn any<P>(&self, pred: P) -> bool where P: FnMut(&T) -> bool {
429         self.iter().any(pred)
430     }
431
432     pub fn is_empty(&self) -> bool {
433         self.all_vecs(|v| v.is_empty())
434     }
435
436     pub fn map<U, P>(&self, pred: P) -> VecPerParamSpace<U> where P: FnMut(&T) -> U {
437         let result = self.iter().map(pred).collect();
438         VecPerParamSpace::new_internal(result,
439                                        self.type_limit,
440                                        self.self_limit)
441     }
442
443     pub fn map_enumerated<U, P>(&self, pred: P) -> VecPerParamSpace<U> where
444         P: FnMut((ParamSpace, uint, &T)) -> U,
445     {
446         let result = self.iter_enumerated().map(pred).collect();
447         VecPerParamSpace::new_internal(result,
448                                        self.type_limit,
449                                        self.self_limit)
450     }
451
452     pub fn map_move<U, F>(self, mut pred: F) -> VecPerParamSpace<U> where
453         F: FnMut(T) -> U,
454     {
455         let SeparateVecsPerParamSpace {
456             types: t,
457             selfs: s,
458             fns: f
459         } = self.split();
460
461         VecPerParamSpace::new(t.into_iter().map(|p| pred(p)).collect(),
462                               s.into_iter().map(|p| pred(p)).collect(),
463                               f.into_iter().map(|p| pred(p)).collect())
464     }
465
466     pub fn split(self) -> SeparateVecsPerParamSpace<T> {
467         let VecPerParamSpace { type_limit, self_limit, content } = self;
468
469         let mut content_iter = content.into_iter();
470
471         SeparateVecsPerParamSpace {
472             types: content_iter.by_ref().take(type_limit).collect(),
473             selfs: content_iter.by_ref().take(self_limit - type_limit).collect(),
474             fns: content_iter.collect()
475         }
476     }
477
478     pub fn with_vec(mut self, space: ParamSpace, vec: Vec<T>)
479                     -> VecPerParamSpace<T>
480     {
481         assert!(self.is_empty_in(space));
482         self.replace(space, vec);
483         self
484     }
485 }
486
487 #[derive(Clone)]
488 pub struct EnumeratedItems<'a,T:'a> {
489     vec: &'a VecPerParamSpace<T>,
490     space_index: uint,
491     elem_index: uint
492 }
493
494 impl<'a,T> EnumeratedItems<'a,T> {
495     fn new(v: &'a VecPerParamSpace<T>) -> EnumeratedItems<'a,T> {
496         let mut result = EnumeratedItems { vec: v, space_index: 0, elem_index: 0 };
497         result.adjust_space();
498         result
499     }
500
501     fn adjust_space(&mut self) {
502         let spaces = ParamSpace::all();
503         while
504             self.space_index < spaces.len() &&
505             self.elem_index >= self.vec.len(spaces[self.space_index])
506         {
507             self.space_index += 1;
508             self.elem_index = 0;
509         }
510     }
511 }
512
513 impl<'a,T> Iterator for EnumeratedItems<'a,T> {
514     type Item = (ParamSpace, uint, &'a T);
515
516     fn next(&mut self) -> Option<(ParamSpace, uint, &'a T)> {
517         let spaces = ParamSpace::all();
518         if self.space_index < spaces.len() {
519             let space = spaces[self.space_index];
520             let index = self.elem_index;
521             let item = self.vec.get(space, index);
522
523             self.elem_index += 1;
524             self.adjust_space();
525
526             Some((space, index, item))
527         } else {
528             None
529         }
530     }
531 }
532
533 impl<T> IntoIterator for VecPerParamSpace<T> {
534     type Item = T;
535     type IntoIter = IntoIter<T>;
536
537     fn into_iter(self) -> IntoIter<T> {
538         self.into_vec().into_iter()
539     }
540 }
541
542 impl<'a,T> IntoIterator for &'a VecPerParamSpace<T> {
543     type Item = &'a T;
544     type IntoIter = Iter<'a, T>;
545
546     fn into_iter(self) -> Iter<'a, T> {
547         self.as_slice().into_iter()
548     }
549 }
550
551
552 ///////////////////////////////////////////////////////////////////////////
553 // Public trait `Subst`
554 //
555 // Just call `foo.subst(tcx, substs)` to perform a substitution across
556 // `foo`. Or use `foo.subst_spanned(tcx, substs, Some(span))` when
557 // there is more information available (for better errors).
558
559 pub trait Subst<'tcx> : Sized {
560     fn subst(&self, tcx: &ty::ctxt<'tcx>, substs: &Substs<'tcx>) -> Self {
561         self.subst_spanned(tcx, substs, None)
562     }
563
564     fn subst_spanned(&self, tcx: &ty::ctxt<'tcx>,
565                      substs: &Substs<'tcx>,
566                      span: Option<Span>)
567                      -> Self;
568 }
569
570 impl<'tcx, T:TypeFoldable<'tcx>> Subst<'tcx> for T {
571     fn subst_spanned(&self,
572                      tcx: &ty::ctxt<'tcx>,
573                      substs: &Substs<'tcx>,
574                      span: Option<Span>)
575                      -> T
576     {
577         let mut folder = SubstFolder { tcx: tcx,
578                                        substs: substs,
579                                        span: span,
580                                        root_ty: None,
581                                        ty_stack_depth: 0,
582                                        region_binders_passed: 0 };
583         (*self).fold_with(&mut folder)
584     }
585 }
586
587 ///////////////////////////////////////////////////////////////////////////
588 // The actual substitution engine itself is a type folder.
589
590 struct SubstFolder<'a, 'tcx: 'a> {
591     tcx: &'a ty::ctxt<'tcx>,
592     substs: &'a Substs<'tcx>,
593
594     // The location for which the substitution is performed, if available.
595     span: Option<Span>,
596
597     // The root type that is being substituted, if available.
598     root_ty: Option<Ty<'tcx>>,
599
600     // Depth of type stack
601     ty_stack_depth: uint,
602
603     // Number of region binders we have passed through while doing the substitution
604     region_binders_passed: u32,
605 }
606
607 impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
608     fn tcx(&self) -> &ty::ctxt<'tcx> { self.tcx }
609
610     fn enter_region_binder(&mut self) {
611         self.region_binders_passed += 1;
612     }
613
614     fn exit_region_binder(&mut self) {
615         self.region_binders_passed -= 1;
616     }
617
618     fn fold_region(&mut self, r: ty::Region) -> ty::Region {
619         // Note: This routine only handles regions that are bound on
620         // type declarations and other outer declarations, not those
621         // bound in *fn types*. Region substitution of the bound
622         // regions that appear in a function signature is done using
623         // the specialized routine `ty::replace_late_regions()`.
624         match r {
625             ty::ReEarlyBound(_, space, i, region_name) => {
626                 match self.substs.regions {
627                     ErasedRegions => ty::ReStatic,
628                     NonerasedRegions(ref regions) =>
629                         match regions.opt_get(space, i as uint) {
630                             Some(&r) => {
631                                 self.shift_region_through_binders(r)
632                             }
633                             None => {
634                                 let span = self.span.unwrap_or(DUMMY_SP);
635                                 self.tcx().sess.span_bug(
636                                     span,
637                                     &format!("Type parameter out of range \
638                                      when substituting in region {} (root type={}) \
639                                      (space={:?}, index={})",
640                                     region_name.as_str(),
641                                     self.root_ty.repr(self.tcx()),
642                                     space, i));
643                             }
644                         }
645                 }
646             }
647             _ => r
648         }
649     }
650
651     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
652         if !ty::type_needs_subst(t) {
653             return t;
654         }
655
656         // track the root type we were asked to substitute
657         let depth = self.ty_stack_depth;
658         if depth == 0 {
659             self.root_ty = Some(t);
660         }
661         self.ty_stack_depth += 1;
662
663         let t1 = match t.sty {
664             ty::ty_param(p) => {
665                 self.ty_for_param(p, t)
666             }
667             _ => {
668                 ty_fold::super_fold_ty(self, t)
669             }
670         };
671
672         assert_eq!(depth + 1, self.ty_stack_depth);
673         self.ty_stack_depth -= 1;
674         if depth == 0 {
675             self.root_ty = None;
676         }
677
678         return t1;
679     }
680 }
681
682 impl<'a,'tcx> SubstFolder<'a,'tcx> {
683     fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> {
684         // Look up the type in the substitutions. It really should be in there.
685         let opt_ty = self.substs.types.opt_get(p.space, p.idx as uint);
686         let ty = match opt_ty {
687             Some(t) => *t,
688             None => {
689                 let span = self.span.unwrap_or(DUMMY_SP);
690                 self.tcx().sess.span_bug(
691                     span,
692                     &format!("Type parameter `{}` ({}/{:?}/{}) out of range \
693                                  when substituting (root type={}) substs={}",
694                             p.repr(self.tcx()),
695                             source_ty.repr(self.tcx()),
696                             p.space,
697                             p.idx,
698                             self.root_ty.repr(self.tcx()),
699                             self.substs.repr(self.tcx())));
700             }
701         };
702
703         self.shift_regions_through_binders(ty)
704     }
705
706     /// It is sometimes necessary to adjust the debruijn indices during substitution. This occurs
707     /// when we are substituting a type with escaping regions into a context where we have passed
708     /// through region binders. That's quite a mouthful. Let's see an example:
709     ///
710     /// ```
711     /// type Func<A> = fn(A);
712     /// type MetaFunc = for<'a> fn(Func<&'a int>)
713     /// ```
714     ///
715     /// The type `MetaFunc`, when fully expanded, will be
716     ///
717     ///     for<'a> fn(fn(&'a int))
718     ///             ^~ ^~ ^~~
719     ///             |  |  |
720     ///             |  |  DebruijnIndex of 2
721     ///             Binders
722     ///
723     /// Here the `'a` lifetime is bound in the outer function, but appears as an argument of the
724     /// inner one. Therefore, that appearance will have a DebruijnIndex of 2, because we must skip
725     /// over the inner binder (remember that we count Debruijn indices from 1). However, in the
726     /// definition of `MetaFunc`, the binder is not visible, so the type `&'a int` will have a
727     /// debruijn index of 1. It's only during the substitution that we can see we must increase the
728     /// depth by 1 to account for the binder that we passed through.
729     ///
730     /// As a second example, consider this twist:
731     ///
732     /// ```
733     /// type FuncTuple<A> = (A,fn(A));
734     /// type MetaFuncTuple = for<'a> fn(FuncTuple<&'a int>)
735     /// ```
736     ///
737     /// Here the final type will be:
738     ///
739     ///     for<'a> fn((&'a int, fn(&'a int)))
740     ///                 ^~~         ^~~
741     ///                 |           |
742     ///          DebruijnIndex of 1 |
743     ///                      DebruijnIndex of 2
744     ///
745     /// As indicated in the diagram, here the same type `&'a int` is substituted once, but in the
746     /// first case we do not increase the Debruijn index and in the second case we do. The reason
747     /// is that only in the second case have we passed through a fn binder.
748     fn shift_regions_through_binders(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
749         debug!("shift_regions(ty={:?}, region_binders_passed={:?}, type_has_escaping_regions={:?})",
750                ty.repr(self.tcx()), self.region_binders_passed, ty::type_has_escaping_regions(ty));
751
752         if self.region_binders_passed == 0 || !ty::type_has_escaping_regions(ty) {
753             return ty;
754         }
755
756         let result = ty_fold::shift_regions(self.tcx(), self.region_binders_passed, &ty);
757         debug!("shift_regions: shifted result = {:?}", result.repr(self.tcx()));
758
759         result
760     }
761
762     fn shift_region_through_binders(&self, region: ty::Region) -> ty::Region {
763         ty_fold::shift_region(region, self.region_binders_passed)
764     }
765 }