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::*;
16 use middle::ty::{mod, Ty};
17 use middle::ty_fold::{mod, TypeFoldable, TypeFolder};
18 use util::ppaux::Repr;
21 use std::slice::Items;
23 use syntax::codemap::{Span, DUMMY_SP};
25 ///////////////////////////////////////////////////////////////////////////
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
33 #[deriving(Clone, PartialEq, Eq, Hash, Show)]
34 pub struct Substs<'tcx> {
35 pub types: VecPerParamSpace<Ty<'tcx>>,
36 pub regions: RegionSubsts,
40 * Represents the values to use when substituting lifetime parameters.
41 * If the value is `ErasedRegions`, then this subst is occurring during
42 * trans, and all region parameters will be replaced with `ty::ReStatic`. */
43 #[deriving(Clone, PartialEq, Eq, Hash, Show)]
44 pub enum RegionSubsts {
46 NonerasedRegions(VecPerParamSpace<ty::Region>)
49 impl<'tcx> Substs<'tcx> {
50 pub fn new(t: VecPerParamSpace<Ty<'tcx>>,
51 r: VecPerParamSpace<ty::Region>)
54 Substs { types: t, regions: NonerasedRegions(r) }
57 pub fn new_type(t: Vec<Ty<'tcx>>,
61 Substs::new(VecPerParamSpace::new(t, Vec::new(), Vec::new(), Vec::new()),
62 VecPerParamSpace::new(r, Vec::new(), Vec::new(), Vec::new()))
65 pub fn new_trait(t: Vec<Ty<'tcx>>,
71 Substs::new(VecPerParamSpace::new(t, vec!(s), a, Vec::new()),
72 VecPerParamSpace::new(r, Vec::new(), Vec::new(), Vec::new()))
75 pub fn erased(t: VecPerParamSpace<Ty<'tcx>>) -> Substs<'tcx>
77 Substs { types: t, regions: ErasedRegions }
80 pub fn empty() -> Substs<'tcx> {
82 types: VecPerParamSpace::empty(),
83 regions: NonerasedRegions(VecPerParamSpace::empty()),
87 pub fn trans_empty() -> Substs<'tcx> {
89 types: VecPerParamSpace::empty(),
90 regions: ErasedRegions
94 pub fn is_noop(&self) -> bool {
95 let regions_is_noop = match self.regions {
96 ErasedRegions => false, // may be used to canonicalize
97 NonerasedRegions(ref regions) => regions.is_empty(),
100 regions_is_noop && self.types.is_empty()
103 pub fn type_for_def(&self, ty_param_def: &ty::TypeParameterDef) -> Ty<'tcx> {
104 *self.types.get(ty_param_def.space, ty_param_def.index)
107 pub fn has_regions_escaping_depth(&self, depth: uint) -> bool {
108 self.types.iter().any(|&t| ty::type_escapes_depth(t, depth)) || {
112 NonerasedRegions(ref regions) =>
113 regions.iter().any(|r| r.escapes_depth(depth)),
118 pub fn self_ty(&self) -> Option<Ty<'tcx>> {
119 self.types.get_self().map(|&t| t)
122 pub fn with_self_ty(&self, self_ty: Ty<'tcx>) -> Substs<'tcx> {
123 assert!(self.self_ty().is_none());
124 let mut s = (*self).clone();
125 s.types.push(SelfSpace, self_ty);
129 pub fn erase_regions(self) -> Substs<'tcx> {
130 let Substs { types, regions: _ } = self;
131 Substs { types: types, regions: ErasedRegions }
134 /// Since ErasedRegions are only to be used in trans, most of the compiler can use this method
135 /// to easily access the set of region substitutions.
136 pub fn regions<'a>(&'a self) -> &'a VecPerParamSpace<ty::Region> {
138 ErasedRegions => panic!("Erased regions only expected in trans"),
139 NonerasedRegions(ref r) => r
143 /// Since ErasedRegions are only to be used in trans, most of the compiler can use this method
144 /// to easily access the set of region substitutions.
145 pub fn mut_regions<'a>(&'a mut self) -> &'a mut VecPerParamSpace<ty::Region> {
147 ErasedRegions => panic!("Erased regions only expected in trans"),
148 NonerasedRegions(ref mut r) => r
152 pub fn with_method(self,
153 m_types: Vec<Ty<'tcx>>,
154 m_regions: Vec<ty::Region>)
157 let Substs { types, regions } = self;
158 let types = types.with_vec(FnSpace, m_types);
159 let regions = regions.map(m_regions,
160 |r, m_regions| r.with_vec(FnSpace, m_regions));
161 Substs { types: types, regions: regions }
168 op: |VecPerParamSpace<ty::Region>, A| -> VecPerParamSpace<ty::Region>)
171 ErasedRegions => ErasedRegions,
172 NonerasedRegions(r) => NonerasedRegions(op(r, a))
176 pub fn is_erased(&self) -> bool {
178 ErasedRegions => true,
179 NonerasedRegions(_) => false,
184 ///////////////////////////////////////////////////////////////////////////
187 #[deriving(PartialOrd, Ord, PartialEq, Eq,
188 Clone, Hash, Encodable, Decodable, Show)]
189 pub enum ParamSpace {
190 TypeSpace, // Type parameters attached to a type definition, trait, or impl
191 SelfSpace, // Self parameter on a trait
192 AssocSpace, // Assoc types defined in a trait/impl
193 FnSpace, // Type parameters attached to a method or fn
197 pub fn all() -> [ParamSpace, ..4] {
198 [TypeSpace, SelfSpace, AssocSpace, FnSpace]
201 pub fn to_uint(self) -> uint {
210 pub fn from_uint(u: uint) -> ParamSpace {
216 _ => panic!("Invalid ParamSpace: {}", u)
222 * Vector of things sorted by param space. Used to keep
223 * the set of things declared on the type, self, or method
226 #[deriving(PartialEq, Eq, Clone, Hash, Encodable, Decodable)]
227 pub struct VecPerParamSpace<T> {
228 // This was originally represented as a tuple with one Vec<T> for
229 // each variant of ParamSpace, and that remains the abstraction
230 // that it provides to its clients.
232 // Here is how the representation corresponds to the abstraction
233 // i.e. the "abstraction function" AF:
235 // AF(self) = (self.content[..self.type_limit],
236 // self.content[self.type_limit..self.self_limit],
237 // self.content[self.self_limit..self.assoc_limit],
238 // self.content[self.assoc_limit..])
246 * The `split` function converts one `VecPerParamSpace` into this
247 * `SeparateVecsPerParamSpace` structure.
249 pub struct SeparateVecsPerParamSpace<T> {
256 impl<T:fmt::Show> fmt::Show for VecPerParamSpace<T> {
257 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
258 try!(write!(fmt, "VecPerParamSpace {{"));
259 for space in ParamSpace::all().iter() {
260 try!(write!(fmt, "{}: {}, ", *space, self.get_slice(*space)));
262 try!(write!(fmt, "}}"));
267 impl<T> VecPerParamSpace<T> {
268 fn limits(&self, space: ParamSpace) -> (uint, uint) {
270 TypeSpace => (0, self.type_limit),
271 SelfSpace => (self.type_limit, self.self_limit),
272 AssocSpace => (self.self_limit, self.assoc_limit),
273 FnSpace => (self.assoc_limit, self.content.len()),
277 pub fn empty() -> VecPerParamSpace<T> {
286 pub fn params_from_type(types: Vec<T>) -> VecPerParamSpace<T> {
287 VecPerParamSpace::empty().with_vec(TypeSpace, types)
290 /// `t` is the type space.
291 /// `s` is the self space.
292 /// `a` is the assoc space.
293 /// `f` is the fn space.
294 pub fn new(t: Vec<T>, s: Vec<T>, a: Vec<T>, f: Vec<T>) -> VecPerParamSpace<T> {
295 let type_limit = t.len();
296 let self_limit = type_limit + s.len();
297 let assoc_limit = self_limit + a.len();
300 content.extend(s.into_iter());
301 content.extend(a.into_iter());
302 content.extend(f.into_iter());
305 type_limit: type_limit,
306 self_limit: self_limit,
307 assoc_limit: assoc_limit,
312 fn new_internal(content: Vec<T>, type_limit: uint, self_limit: uint, assoc_limit: uint)
313 -> VecPerParamSpace<T>
316 type_limit: type_limit,
317 self_limit: self_limit,
318 assoc_limit: assoc_limit,
323 /// Appends `value` to the vector associated with `space`.
325 /// Unlike the `push` method in `Vec`, this should not be assumed
326 /// to be a cheap operation (even when amortized over many calls).
327 pub fn push(&mut self, space: ParamSpace, value: T) {
328 let (_, limit) = self.limits(space);
330 TypeSpace => { self.type_limit += 1; self.self_limit += 1; self.assoc_limit += 1; }
331 SelfSpace => { self.self_limit += 1; self.assoc_limit += 1; }
332 AssocSpace => { self.assoc_limit += 1; }
335 self.content.insert(limit, value);
338 pub fn pop(&mut self, space: ParamSpace) -> Option<T> {
339 let (start, limit) = self.limits(space);
344 TypeSpace => { self.type_limit -= 1; self.self_limit -= 1; self.assoc_limit -= 1; }
345 SelfSpace => { self.self_limit -= 1; self.assoc_limit -= 1; }
346 AssocSpace => { self.assoc_limit -= 1; }
349 self.content.remove(limit - 1)
353 pub fn truncate(&mut self, space: ParamSpace, len: uint) {
354 // FIXME (#15435): slow; O(n^2); could enhance vec to make it O(n).
355 while self.len(space) > len {
360 pub fn replace(&mut self, space: ParamSpace, elems: Vec<T>) {
361 // FIXME (#15435): slow; O(n^2); could enhance vec to make it O(n).
362 self.truncate(space, 0);
363 for t in elems.into_iter() {
368 pub fn get_self<'a>(&'a self) -> Option<&'a T> {
369 let v = self.get_slice(SelfSpace);
370 assert!(v.len() <= 1);
371 if v.len() == 0 { None } else { Some(&v[0]) }
374 pub fn len(&self, space: ParamSpace) -> uint {
375 self.get_slice(space).len()
378 pub fn is_empty_in(&self, space: ParamSpace) -> bool {
382 pub fn get_slice<'a>(&'a self, space: ParamSpace) -> &'a [T] {
383 let (start, limit) = self.limits(space);
384 self.content.slice(start, limit)
387 pub fn get_mut_slice<'a>(&'a mut self, space: ParamSpace) -> &'a mut [T] {
388 let (start, limit) = self.limits(space);
389 self.content.slice_mut(start, limit)
392 pub fn opt_get<'a>(&'a self,
396 let v = self.get_slice(space);
397 if index < v.len() { Some(&v[index]) } else { None }
400 pub fn get<'a>(&'a self, space: ParamSpace, index: uint) -> &'a T {
401 &self.get_slice(space)[index]
404 pub fn iter<'a>(&'a self) -> Items<'a,T> {
408 pub fn iter_enumerated<'a>(&'a self) -> EnumeratedItems<'a,T> {
409 EnumeratedItems::new(self)
412 pub fn as_slice(&self) -> &[T] {
413 self.content.as_slice()
416 pub fn all_vecs(&self, pred: |&[T]| -> bool) -> bool {
417 let spaces = [TypeSpace, SelfSpace, FnSpace];
418 spaces.iter().all(|&space| { pred(self.get_slice(space)) })
421 pub fn all(&self, pred: |&T| -> bool) -> bool {
422 self.iter().all(pred)
425 pub fn any(&self, pred: |&T| -> bool) -> bool {
426 self.iter().any(pred)
429 pub fn is_empty(&self) -> bool {
430 self.all_vecs(|v| v.is_empty())
433 pub fn map<U>(&self, pred: |&T| -> U) -> VecPerParamSpace<U> {
434 let result = self.iter().map(pred).collect();
435 VecPerParamSpace::new_internal(result,
441 pub fn map_enumerated<U>(&self, pred: |(ParamSpace, uint, &T)| -> U) -> VecPerParamSpace<U> {
442 let result = self.iter_enumerated().map(pred).collect();
443 VecPerParamSpace::new_internal(result,
449 pub fn map_move<U>(self, pred: |T| -> U) -> VecPerParamSpace<U> {
450 let SeparateVecsPerParamSpace {
457 VecPerParamSpace::new(t.into_iter().map(|p| pred(p)).collect(),
458 s.into_iter().map(|p| pred(p)).collect(),
459 a.into_iter().map(|p| pred(p)).collect(),
460 f.into_iter().map(|p| pred(p)).collect())
463 pub fn split(self) -> SeparateVecsPerParamSpace<T> {
464 let VecPerParamSpace { type_limit, self_limit, assoc_limit, content } = self;
466 let mut content_iter = content.into_iter();
468 SeparateVecsPerParamSpace {
469 types: content_iter.by_ref().take(type_limit).collect(),
470 selfs: content_iter.by_ref().take(self_limit - type_limit).collect(),
471 assocs: content_iter.by_ref().take(assoc_limit - self_limit).collect(),
472 fns: content_iter.collect()
476 pub fn with_vec(mut self, space: ParamSpace, vec: Vec<T>)
477 -> VecPerParamSpace<T>
479 assert!(self.is_empty_in(space));
480 self.replace(space, vec);
485 pub struct EnumeratedItems<'a,T:'a> {
486 vec: &'a VecPerParamSpace<T>,
491 impl<'a,T> EnumeratedItems<'a,T> {
492 fn new(v: &'a VecPerParamSpace<T>) -> EnumeratedItems<'a,T> {
493 let mut result = EnumeratedItems { vec: v, space_index: 0, elem_index: 0 };
494 result.adjust_space();
498 fn adjust_space(&mut self) {
499 let spaces = ParamSpace::all();
501 self.space_index < spaces.len() &&
502 self.elem_index >= self.vec.len(spaces[self.space_index])
504 self.space_index += 1;
510 impl<'a,T> Iterator<(ParamSpace, uint, &'a T)> for EnumeratedItems<'a,T> {
511 fn next(&mut self) -> Option<(ParamSpace, uint, &'a T)> {
512 let spaces = ParamSpace::all();
513 if self.space_index < spaces.len() {
514 let space = spaces[self.space_index];
515 let index = self.elem_index;
516 let item = self.vec.get(space, index);
518 self.elem_index += 1;
521 Some((space, index, item))
528 ///////////////////////////////////////////////////////////////////////////
529 // Public trait `Subst`
531 // Just call `foo.subst(tcx, substs)` to perform a substitution across
532 // `foo`. Or use `foo.subst_spanned(tcx, substs, Some(span))` when
533 // there is more information available (for better errors).
535 pub trait Subst<'tcx> {
536 fn subst(&self, tcx: &ty::ctxt<'tcx>, substs: &Substs<'tcx>) -> Self {
537 self.subst_spanned(tcx, substs, None)
540 fn subst_spanned(&self, tcx: &ty::ctxt<'tcx>,
541 substs: &Substs<'tcx>,
546 impl<'tcx, T:TypeFoldable<'tcx>> Subst<'tcx> for T {
547 fn subst_spanned(&self,
548 tcx: &ty::ctxt<'tcx>,
549 substs: &Substs<'tcx>,
553 let mut folder = SubstFolder { tcx: tcx,
558 region_binders_passed: 0 };
559 (*self).fold_with(&mut folder)
563 ///////////////////////////////////////////////////////////////////////////
564 // The actual substitution engine itself is a type folder.
566 struct SubstFolder<'a, 'tcx: 'a> {
567 tcx: &'a ty::ctxt<'tcx>,
568 substs: &'a Substs<'tcx>,
570 // The location for which the substitution is performed, if available.
573 // The root type that is being substituted, if available.
574 root_ty: Option<Ty<'tcx>>,
576 // Depth of type stack
577 ty_stack_depth: uint,
579 // Number of region binders we have passed through while doing the substitution
580 region_binders_passed: uint,
583 impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
584 fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { self.tcx }
586 fn enter_region_binder(&mut self) {
587 self.region_binders_passed += 1;
590 fn exit_region_binder(&mut self) {
591 self.region_binders_passed -= 1;
594 fn fold_region(&mut self, r: ty::Region) -> ty::Region {
595 // Note: This routine only handles regions that are bound on
596 // type declarations and other outer declarations, not those
597 // bound in *fn types*. Region substitution of the bound
598 // regions that appear in a function signature is done using
599 // the specialized routine
600 // `middle::typeck::check::regionmanip::replace_late_regions_in_fn_sig()`.
602 ty::ReEarlyBound(_, space, i, region_name) => {
603 match self.substs.regions {
604 ErasedRegions => ty::ReStatic,
605 NonerasedRegions(ref regions) =>
606 match regions.opt_get(space, i) {
608 self.shift_region_through_binders(r)
611 let span = self.span.unwrap_or(DUMMY_SP);
612 self.tcx().sess.span_bug(
614 format!("Type parameter out of range \
615 when substituting in region {} (root type={}) \
616 (space={}, index={})",
617 region_name.as_str(),
618 self.root_ty.repr(self.tcx()),
619 space, i).as_slice());
628 fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
629 if !ty::type_needs_subst(t) {
633 // track the root type we were asked to substitute
634 let depth = self.ty_stack_depth;
636 self.root_ty = Some(t);
638 self.ty_stack_depth += 1;
640 let t1 = match t.sty {
642 self.ty_for_param(p, t)
645 ty_fold::super_fold_ty(self, t)
649 assert_eq!(depth + 1, self.ty_stack_depth);
650 self.ty_stack_depth -= 1;
659 impl<'a,'tcx> SubstFolder<'a,'tcx> {
660 fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> {
661 // Look up the type in the substitutions. It really should be in there.
662 let opt_ty = self.substs.types.opt_get(p.space, p.idx);
663 let ty = match opt_ty {
666 let span = self.span.unwrap_or(DUMMY_SP);
667 self.tcx().sess.span_bug(
669 format!("Type parameter `{}` ({}/{}/{}) out of range \
670 when substituting (root type={}) substs={}",
672 source_ty.repr(self.tcx()),
675 self.root_ty.repr(self.tcx()),
676 self.substs.repr(self.tcx())).as_slice());
680 self.shift_regions_through_binders(ty)
683 /// It is sometimes necessary to adjust the debruijn indices during substitution. This occurs
684 /// when we are substituting a type with escaping regions into a context where we have passed
685 /// through region binders. That's quite a mouthful. Let's see an example:
688 /// type Func<A> = fn(A);
689 /// type MetaFunc = for<'a> fn(Func<&'a int>)
692 /// The type `MetaFunc`, when fully expanded, will be
694 /// for<'a> fn(fn(&'a int))
697 /// | | DebruijnIndex of 2
700 /// Here the `'a` lifetime is bound in the outer function, but appears as an argument of the
701 /// inner one. Therefore, that appearance will have a DebruijnIndex of 2, because we must skip
702 /// over the inner binder (remember that we count Debruijn indices from 1). However, in the
703 /// definition of `MetaFunc`, the binder is not visible, so the type `&'a int` will have a
704 /// debruijn index of 1. It's only during the substitution that we can see we must increase the
705 /// depth by 1 to account for the binder that we passed through.
707 /// As a second example, consider this twist:
710 /// type FuncTuple<A> = (A,fn(A));
711 /// type MetaFuncTuple = for<'a> fn(FuncTuple<&'a int>)
714 /// Here the final type will be:
716 /// for<'a> fn((&'a int, fn(&'a int)))
719 /// DebruijnIndex of 1 |
720 /// DebruijnIndex of 2
722 /// As indicated in the diagram, here the same type `&'a int` is substituted once, but in the
723 /// first case we do not increase the Debruijn index and in the second case we do. The reason
724 /// is that only in the second case have we passed through a fn binder.
725 fn shift_regions_through_binders(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
726 debug!("shift_regions(ty={}, region_binders_passed={}, type_has_escaping_regions={})",
727 ty.repr(self.tcx()), self.region_binders_passed, ty::type_has_escaping_regions(ty));
729 if self.region_binders_passed == 0 || !ty::type_has_escaping_regions(ty) {
733 let result = ty_fold::shift_regions(self.tcx(), self.region_binders_passed, &ty);
734 debug!("shift_regions: shifted result = {}", result.repr(self.tcx()));
739 fn shift_region_through_binders(&self, region: ty::Region) -> ty::Region {
740 ty_fold::shift_region(region, self.region_binders_passed)