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.
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 // Type substitutions.
13 pub use self::ParamSpace::*;
14 pub use self::RegionSubsts::*;
17 use middle::ty::{self, Ty, HasTypeFlags, RegionEscape};
18 use middle::ty::fold::{TypeFoldable, TypeFolder};
20 use serialize::{Encodable, Encoder, Decodable, Decoder};
22 use std::iter::IntoIterator;
24 use std::vec::{Vec, IntoIter};
25 use syntax::codemap::{Span, DUMMY_SP};
27 ///////////////////////////////////////////////////////////////////////////
29 /// A substitution mapping type/region parameters to new values. We
30 /// identify each in-scope parameter by an *index* and a *parameter
31 /// space* (which indices where the parameter is defined; see
33 #[derive(Clone, PartialEq, Eq, Hash)]
34 pub struct Substs<'tcx> {
35 pub types: VecPerParamSpace<Ty<'tcx>>,
36 pub regions: RegionSubsts,
39 /// Represents the values to use when substituting lifetime parameters.
40 /// If the value is `ErasedRegions`, then this subst is occurring during
41 /// trans, and all region parameters will be replaced with `ty::ReStatic`.
42 #[derive(Clone, PartialEq, Eq, Hash)]
43 pub enum RegionSubsts {
45 NonerasedRegions(VecPerParamSpace<ty::Region>)
48 impl<'tcx> Substs<'tcx> {
49 pub fn new(t: VecPerParamSpace<Ty<'tcx>>,
50 r: VecPerParamSpace<ty::Region>)
53 Substs { types: t, regions: NonerasedRegions(r) }
56 pub fn new_type(t: Vec<Ty<'tcx>>,
60 Substs::new(VecPerParamSpace::new(t, Vec::new(), Vec::new()),
61 VecPerParamSpace::new(r, Vec::new(), Vec::new()))
64 pub fn new_trait(t: Vec<Ty<'tcx>>,
69 Substs::new(VecPerParamSpace::new(t, vec!(s), Vec::new()),
70 VecPerParamSpace::new(r, Vec::new(), Vec::new()))
73 pub fn erased(t: VecPerParamSpace<Ty<'tcx>>) -> Substs<'tcx>
75 Substs { types: t, regions: ErasedRegions }
78 pub fn empty() -> Substs<'tcx> {
80 types: VecPerParamSpace::empty(),
81 regions: NonerasedRegions(VecPerParamSpace::empty()),
85 pub fn trans_empty() -> Substs<'tcx> {
87 types: VecPerParamSpace::empty(),
88 regions: ErasedRegions
92 pub fn is_noop(&self) -> bool {
93 let regions_is_noop = match self.regions {
94 ErasedRegions => false, // may be used to canonicalize
95 NonerasedRegions(ref regions) => regions.is_empty(),
98 regions_is_noop && self.types.is_empty()
101 pub fn type_for_def(&self, ty_param_def: &ty::TypeParameterDef) -> Ty<'tcx> {
102 *self.types.get(ty_param_def.space, ty_param_def.index as usize)
105 pub fn self_ty(&self) -> Option<Ty<'tcx>> {
106 self.types.get_self().cloned()
109 pub fn with_self_ty(&self, self_ty: Ty<'tcx>) -> Substs<'tcx> {
110 assert!(self.self_ty().is_none());
111 let mut s = (*self).clone();
112 s.types.push(SelfSpace, self_ty);
116 pub fn erase_regions(self) -> Substs<'tcx> {
117 let Substs { types, regions: _ } = self;
118 Substs { types: types, regions: ErasedRegions }
121 /// Since ErasedRegions are only to be used in trans, most of the compiler can use this method
122 /// to easily access the set of region substitutions.
123 pub fn regions<'a>(&'a self) -> &'a VecPerParamSpace<ty::Region> {
125 ErasedRegions => panic!("Erased regions only expected in trans"),
126 NonerasedRegions(ref r) => r
130 /// Since ErasedRegions are only to be used in trans, most of the compiler can use this method
131 /// to easily access the set of region substitutions.
132 pub fn mut_regions<'a>(&'a mut self) -> &'a mut VecPerParamSpace<ty::Region> {
134 ErasedRegions => panic!("Erased regions only expected in trans"),
135 NonerasedRegions(ref mut r) => r
139 pub fn with_method(self,
140 m_types: Vec<Ty<'tcx>>,
141 m_regions: Vec<ty::Region>)
144 let Substs { types, regions } = self;
145 let types = types.with_vec(FnSpace, m_types);
146 let regions = regions.map(|r| r.with_vec(FnSpace, m_regions));
147 Substs { types: types, regions: regions }
150 pub fn method_to_trait(self) -> Substs<'tcx> {
151 let Substs { mut types, regions } = self;
152 types.truncate(FnSpace, 0);
153 let regions = regions.map(|mut r| { r.truncate(FnSpace, 0); r });
154 Substs { types: types, regions: regions }
158 impl<'tcx> Encodable for Substs<'tcx> {
160 fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
161 cstore::tls::with_encoding_context(s, |ecx, rbml_w| {
162 ecx.encode_substs(rbml_w, self);
168 impl<'tcx> Decodable for Substs<'tcx> {
169 fn decode<D: Decoder>(d: &mut D) -> Result<Substs<'tcx>, D::Error> {
170 cstore::tls::with_decoding_context(d, |dcx, rbml_r| {
171 Ok(dcx.decode_substs(rbml_r))
176 impl<'tcx> Decodable for &'tcx Substs<'tcx> {
177 fn decode<D: Decoder>(d: &mut D) -> Result<&'tcx Substs<'tcx>, D::Error> {
178 let substs = cstore::tls::with_decoding_context(d, |dcx, rbml_r| {
179 let substs = dcx.decode_substs(rbml_r);
180 dcx.tcx().mk_substs(substs)
188 pub fn map<F>(self, op: F) -> RegionSubsts where
189 F: FnOnce(VecPerParamSpace<ty::Region>) -> VecPerParamSpace<ty::Region>,
192 ErasedRegions => ErasedRegions,
193 NonerasedRegions(r) => NonerasedRegions(op(r))
197 pub fn is_erased(&self) -> bool {
199 ErasedRegions => true,
200 NonerasedRegions(_) => false,
205 ///////////////////////////////////////////////////////////////////////////
208 #[derive(PartialOrd, Ord, PartialEq, Eq, Copy,
209 Clone, Hash, RustcEncodable, RustcDecodable, Debug)]
210 pub enum ParamSpace {
211 TypeSpace, // Type parameters attached to a type definition, trait, or impl
212 SelfSpace, // Self parameter on a trait
213 FnSpace, // Type parameters attached to a method or fn
217 pub fn all() -> [ParamSpace; 3] {
218 [TypeSpace, SelfSpace, FnSpace]
221 pub fn to_uint(self) -> usize {
229 pub fn from_uint(u: usize) -> ParamSpace {
234 _ => panic!("Invalid ParamSpace: {}", u)
239 /// Vector of things sorted by param space. Used to keep
240 /// the set of things declared on the type, self, or method
242 #[derive(PartialEq, Eq, Clone, Hash, RustcEncodable, RustcDecodable)]
243 pub struct VecPerParamSpace<T> {
244 // This was originally represented as a tuple with one Vec<T> for
245 // each variant of ParamSpace, and that remains the abstraction
246 // that it provides to its clients.
248 // Here is how the representation corresponds to the abstraction
249 // i.e. the "abstraction function" AF:
251 // AF(self) = (self.content[..self.type_limit],
252 // self.content[self.type_limit..self.self_limit],
253 // self.content[self.self_limit..])
259 /// The `split` function converts one `VecPerParamSpace` into this
260 /// `SeparateVecsPerParamSpace` structure.
261 pub struct SeparateVecsPerParamSpace<T> {
267 impl<T: fmt::Debug> fmt::Debug for VecPerParamSpace<T> {
268 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
269 write!(f, "[{:?};{:?};{:?}]",
270 self.get_slice(TypeSpace),
271 self.get_slice(SelfSpace),
272 self.get_slice(FnSpace))
276 impl<T> VecPerParamSpace<T> {
277 fn limits(&self, space: ParamSpace) -> (usize, usize) {
279 TypeSpace => (0, self.type_limit),
280 SelfSpace => (self.type_limit, self.self_limit),
281 FnSpace => (self.self_limit, self.content.len()),
285 pub fn empty() -> VecPerParamSpace<T> {
293 pub fn params_from_type(types: Vec<T>) -> VecPerParamSpace<T> {
294 VecPerParamSpace::empty().with_vec(TypeSpace, types)
297 /// `t` is the type space.
298 /// `s` is the self space.
299 /// `f` is the fn space.
300 pub fn new(t: Vec<T>, s: Vec<T>, f: Vec<T>) -> VecPerParamSpace<T> {
301 let type_limit = t.len();
302 let self_limit = type_limit + s.len();
309 type_limit: type_limit,
310 self_limit: self_limit,
315 fn new_internal(content: Vec<T>, type_limit: usize, self_limit: usize)
316 -> VecPerParamSpace<T>
319 type_limit: type_limit,
320 self_limit: self_limit,
325 /// Appends `value` to the vector associated with `space`.
327 /// Unlike the `push` method in `Vec`, this should not be assumed
328 /// to be a cheap operation (even when amortized over many calls).
329 pub fn push(&mut self, space: ParamSpace, value: T) {
330 let (_, limit) = self.limits(space);
332 TypeSpace => { self.type_limit += 1; self.self_limit += 1; }
333 SelfSpace => { self.self_limit += 1; }
336 self.content.insert(limit, value);
339 /// Appends `values` to the vector associated with `space`.
341 /// Unlike the `extend` method in `Vec`, this should not be assumed
342 /// to be a cheap operation (even when amortized over many calls).
343 pub fn extend<I:Iterator<Item=T>>(&mut self, space: ParamSpace, values: I) {
344 // This could be made more efficient, obviously.
346 self.push(space, item);
350 pub fn pop(&mut self, space: ParamSpace) -> Option<T> {
351 let (start, limit) = self.limits(space);
356 TypeSpace => { self.type_limit -= 1; self.self_limit -= 1; }
357 SelfSpace => { self.self_limit -= 1; }
360 if self.content.is_empty() {
363 Some(self.content.remove(limit - 1))
368 pub fn truncate(&mut self, space: ParamSpace, len: usize) {
369 // FIXME (#15435): slow; O(n^2); could enhance vec to make it O(n).
370 while self.len(space) > len {
375 pub fn replace(&mut self, space: ParamSpace, elems: Vec<T>) {
376 // FIXME (#15435): slow; O(n^2); could enhance vec to make it O(n).
377 self.truncate(space, 0);
383 pub fn get_self<'a>(&'a self) -> Option<&'a T> {
384 let v = self.get_slice(SelfSpace);
385 assert!(v.len() <= 1);
386 if v.is_empty() { None } else { Some(&v[0]) }
389 pub fn len(&self, space: ParamSpace) -> usize {
390 self.get_slice(space).len()
393 pub fn is_empty_in(&self, space: ParamSpace) -> bool {
397 pub fn get_slice<'a>(&'a self, space: ParamSpace) -> &'a [T] {
398 let (start, limit) = self.limits(space);
399 &self.content[start.. limit]
402 pub fn get_mut_slice<'a>(&'a mut self, space: ParamSpace) -> &'a mut [T] {
403 let (start, limit) = self.limits(space);
404 &mut self.content[start.. limit]
407 pub fn opt_get<'a>(&'a self,
411 let v = self.get_slice(space);
412 if index < v.len() { Some(&v[index]) } else { None }
415 pub fn get<'a>(&'a self, space: ParamSpace, index: usize) -> &'a T {
416 &self.get_slice(space)[index]
419 pub fn iter<'a>(&'a self) -> Iter<'a,T> {
423 pub fn into_iter(self) -> IntoIter<T> {
424 self.content.into_iter()
427 pub fn iter_enumerated<'a>(&'a self) -> EnumeratedItems<'a,T> {
428 EnumeratedItems::new(self)
431 pub fn as_slice(&self) -> &[T] {
435 pub fn into_vec(self) -> Vec<T> {
439 pub fn all_vecs<P>(&self, mut pred: P) -> bool where
440 P: FnMut(&[T]) -> bool,
442 let spaces = [TypeSpace, SelfSpace, FnSpace];
443 spaces.iter().all(|&space| { pred(self.get_slice(space)) })
446 pub fn all<P>(&self, pred: P) -> bool where P: FnMut(&T) -> bool {
447 self.iter().all(pred)
450 pub fn any<P>(&self, pred: P) -> bool where P: FnMut(&T) -> bool {
451 self.iter().any(pred)
454 pub fn is_empty(&self) -> bool {
455 self.all_vecs(|v| v.is_empty())
458 pub fn map<U, P>(&self, pred: P) -> VecPerParamSpace<U> where P: FnMut(&T) -> U {
459 let result = self.iter().map(pred).collect();
460 VecPerParamSpace::new_internal(result,
465 pub fn map_enumerated<U, P>(&self, pred: P) -> VecPerParamSpace<U> where
466 P: FnMut((ParamSpace, usize, &T)) -> U,
468 let result = self.iter_enumerated().map(pred).collect();
469 VecPerParamSpace::new_internal(result,
474 pub fn split(self) -> SeparateVecsPerParamSpace<T> {
475 let VecPerParamSpace { type_limit, self_limit, content } = self;
477 let mut content_iter = content.into_iter();
479 SeparateVecsPerParamSpace {
480 types: content_iter.by_ref().take(type_limit).collect(),
481 selfs: content_iter.by_ref().take(self_limit - type_limit).collect(),
482 fns: content_iter.collect()
486 pub fn with_vec(mut self, space: ParamSpace, vec: Vec<T>)
487 -> VecPerParamSpace<T>
489 assert!(self.is_empty_in(space));
490 self.replace(space, vec);
496 pub struct EnumeratedItems<'a,T:'a> {
497 vec: &'a VecPerParamSpace<T>,
502 impl<'a,T> EnumeratedItems<'a,T> {
503 fn new(v: &'a VecPerParamSpace<T>) -> EnumeratedItems<'a,T> {
504 let mut result = EnumeratedItems { vec: v, space_index: 0, elem_index: 0 };
505 result.adjust_space();
509 fn adjust_space(&mut self) {
510 let spaces = ParamSpace::all();
512 self.space_index < spaces.len() &&
513 self.elem_index >= self.vec.len(spaces[self.space_index])
515 self.space_index += 1;
521 impl<'a,T> Iterator for EnumeratedItems<'a,T> {
522 type Item = (ParamSpace, usize, &'a T);
524 fn next(&mut self) -> Option<(ParamSpace, usize, &'a T)> {
525 let spaces = ParamSpace::all();
526 if self.space_index < spaces.len() {
527 let space = spaces[self.space_index];
528 let index = self.elem_index;
529 let item = self.vec.get(space, index);
531 self.elem_index += 1;
534 Some((space, index, item))
541 impl<T> IntoIterator for VecPerParamSpace<T> {
543 type IntoIter = IntoIter<T>;
545 fn into_iter(self) -> IntoIter<T> {
546 self.into_vec().into_iter()
550 impl<'a,T> IntoIterator for &'a VecPerParamSpace<T> {
552 type IntoIter = Iter<'a, T>;
554 fn into_iter(self) -> Iter<'a, T> {
555 self.as_slice().into_iter()
560 ///////////////////////////////////////////////////////////////////////////
561 // Public trait `Subst`
563 // Just call `foo.subst(tcx, substs)` to perform a substitution across
564 // `foo`. Or use `foo.subst_spanned(tcx, substs, Some(span))` when
565 // there is more information available (for better errors).
567 pub trait Subst<'tcx> : Sized {
568 fn subst(&self, tcx: &ty::ctxt<'tcx>, substs: &Substs<'tcx>) -> Self {
569 self.subst_spanned(tcx, substs, None)
572 fn subst_spanned(&self, tcx: &ty::ctxt<'tcx>,
573 substs: &Substs<'tcx>,
578 impl<'tcx, T:TypeFoldable<'tcx>> Subst<'tcx> for T {
579 fn subst_spanned(&self,
580 tcx: &ty::ctxt<'tcx>,
581 substs: &Substs<'tcx>,
585 let mut folder = SubstFolder { tcx: tcx,
590 region_binders_passed: 0 };
591 (*self).fold_with(&mut folder)
595 ///////////////////////////////////////////////////////////////////////////
596 // The actual substitution engine itself is a type folder.
598 struct SubstFolder<'a, 'tcx: 'a> {
599 tcx: &'a ty::ctxt<'tcx>,
600 substs: &'a Substs<'tcx>,
602 // The location for which the substitution is performed, if available.
605 // The root type that is being substituted, if available.
606 root_ty: Option<Ty<'tcx>>,
608 // Depth of type stack
609 ty_stack_depth: usize,
611 // Number of region binders we have passed through while doing the substitution
612 region_binders_passed: u32,
615 impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
616 fn tcx(&self) -> &ty::ctxt<'tcx> { self.tcx }
618 fn enter_region_binder(&mut self) {
619 self.region_binders_passed += 1;
622 fn exit_region_binder(&mut self) {
623 self.region_binders_passed -= 1;
626 fn fold_region(&mut self, r: ty::Region) -> ty::Region {
627 // Note: This routine only handles regions that are bound on
628 // type declarations and other outer declarations, not those
629 // bound in *fn types*. Region substitution of the bound
630 // regions that appear in a function signature is done using
631 // the specialized routine `ty::replace_late_regions()`.
633 ty::ReEarlyBound(data) => {
634 match self.substs.regions {
635 ErasedRegions => ty::ReStatic,
636 NonerasedRegions(ref regions) =>
637 match regions.opt_get(data.space, data.index as usize) {
639 self.shift_region_through_binders(r)
642 let span = self.span.unwrap_or(DUMMY_SP);
643 self.tcx().sess.span_bug(
645 &format!("Type parameter out of range \
646 when substituting in region {} (root type={:?}) \
647 (space={:?}, index={})",
660 fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
661 if !t.needs_subst() {
665 // track the root type we were asked to substitute
666 let depth = self.ty_stack_depth;
668 self.root_ty = Some(t);
670 self.ty_stack_depth += 1;
672 let t1 = match t.sty {
674 self.ty_for_param(p, t)
677 ty::fold::super_fold_ty(self, t)
681 assert_eq!(depth + 1, self.ty_stack_depth);
682 self.ty_stack_depth -= 1;
691 impl<'a,'tcx> SubstFolder<'a,'tcx> {
692 fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> {
693 // Look up the type in the substitutions. It really should be in there.
694 let opt_ty = self.substs.types.opt_get(p.space, p.idx as usize);
695 let ty = match opt_ty {
698 let span = self.span.unwrap_or(DUMMY_SP);
699 self.tcx().sess.span_bug(
701 &format!("Type parameter `{:?}` ({:?}/{:?}/{}) out of range \
702 when substituting (root type={:?}) substs={:?}",
712 self.shift_regions_through_binders(ty)
715 /// It is sometimes necessary to adjust the debruijn indices during substitution. This occurs
716 /// when we are substituting a type with escaping regions into a context where we have passed
717 /// through region binders. That's quite a mouthful. Let's see an example:
720 /// type Func<A> = fn(A);
721 /// type MetaFunc = for<'a> fn(Func<&'a int>)
724 /// The type `MetaFunc`, when fully expanded, will be
726 /// for<'a> fn(fn(&'a int))
729 /// | | DebruijnIndex of 2
732 /// Here the `'a` lifetime is bound in the outer function, but appears as an argument of the
733 /// inner one. Therefore, that appearance will have a DebruijnIndex of 2, because we must skip
734 /// over the inner binder (remember that we count Debruijn indices from 1). However, in the
735 /// definition of `MetaFunc`, the binder is not visible, so the type `&'a int` will have a
736 /// debruijn index of 1. It's only during the substitution that we can see we must increase the
737 /// depth by 1 to account for the binder that we passed through.
739 /// As a second example, consider this twist:
742 /// type FuncTuple<A> = (A,fn(A));
743 /// type MetaFuncTuple = for<'a> fn(FuncTuple<&'a int>)
746 /// Here the final type will be:
748 /// for<'a> fn((&'a int, fn(&'a int)))
751 /// DebruijnIndex of 1 |
752 /// DebruijnIndex of 2
754 /// As indicated in the diagram, here the same type `&'a int` is substituted once, but in the
755 /// first case we do not increase the Debruijn index and in the second case we do. The reason
756 /// is that only in the second case have we passed through a fn binder.
757 fn shift_regions_through_binders(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
758 debug!("shift_regions(ty={:?}, region_binders_passed={:?}, has_escaping_regions={:?})",
759 ty, self.region_binders_passed, ty.has_escaping_regions());
761 if self.region_binders_passed == 0 || !ty.has_escaping_regions() {
765 let result = ty::fold::shift_regions(self.tcx(), self.region_binders_passed, &ty);
766 debug!("shift_regions: shifted result = {:?}", result);
771 fn shift_region_through_binders(&self, region: ty::Region) -> ty::Region {
772 ty::fold::shift_region(region, self.region_binders_passed)