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
::{self, Ty}
;
17 use middle
::ty_fold
::{self, TypeFoldable, TypeFolder}
;
18 use util
::ppaux
::Repr
;
21 use std
::iter
::IntoIterator
;
23 use std
::vec
::{Vec, IntoIter}
;
24 use syntax
::codemap
::{Span, DUMMY_SP}
;
26 ///////////////////////////////////////////////////////////////////////////
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
32 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
33 pub struct Substs
<'tcx
> {
34 pub types
: VecPerParamSpace
<Ty
<'tcx
>>,
35 pub regions
: RegionSubsts
,
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
{
44 NonerasedRegions(VecPerParamSpace
<ty
::Region
>)
47 impl<'tcx
> Substs
<'tcx
> {
48 pub fn new(t
: VecPerParamSpace
<Ty
<'tcx
>>,
49 r
: VecPerParamSpace
<ty
::Region
>)
52 Substs { types: t, regions: NonerasedRegions(r) }
55 pub fn new_type(t
: Vec
<Ty
<'tcx
>>,
59 Substs
::new(VecPerParamSpace
::new(t
, Vec
::new(), Vec
::new()),
60 VecPerParamSpace
::new(r
, Vec
::new(), Vec
::new()))
63 pub fn new_trait(t
: Vec
<Ty
<'tcx
>>,
68 Substs
::new(VecPerParamSpace
::new(t
, vec
!(s
), Vec
::new()),
69 VecPerParamSpace
::new(r
, Vec
::new(), Vec
::new()))
72 pub fn erased(t
: VecPerParamSpace
<Ty
<'tcx
>>) -> Substs
<'tcx
>
74 Substs { types: t, regions: ErasedRegions }
77 pub fn empty() -> Substs
<'tcx
> {
79 types
: VecPerParamSpace
::empty(),
80 regions
: NonerasedRegions(VecPerParamSpace
::empty()),
84 pub fn trans_empty() -> Substs
<'tcx
> {
86 types
: VecPerParamSpace
::empty(),
87 regions
: ErasedRegions
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(),
97 regions_is_noop
&& self.types
.is_empty()
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 usize)
104 pub fn has_regions_escaping_depth(&self, depth
: u32) -> bool
{
105 self.types
.iter().any(|&t
| ty
::type_escapes_depth(t
, depth
)) || {
109 NonerasedRegions(ref regions
) =>
110 regions
.iter().any(|r
| r
.escapes_depth(depth
)),
115 pub fn self_ty(&self) -> Option
<Ty
<'tcx
>> {
116 self.types
.get_self().cloned()
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
);
126 pub fn erase_regions(self) -> Substs
<'tcx
> {
127 let Substs { types, regions: _ }
= self;
128 Substs { types: types, regions: ErasedRegions }
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
> {
135 ErasedRegions
=> panic
!("Erased regions only expected in trans"),
136 NonerasedRegions(ref r
) => r
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
> {
144 ErasedRegions
=> panic
!("Erased regions only expected in trans"),
145 NonerasedRegions(ref mut r
) => r
149 pub fn with_method(self,
150 m_types
: Vec
<Ty
<'tcx
>>,
151 m_regions
: Vec
<ty
::Region
>)
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 }
163 fn map
<A
, F
>(self, a
: A
, op
: F
) -> RegionSubsts
where
164 F
: FnOnce(VecPerParamSpace
<ty
::Region
>, A
) -> VecPerParamSpace
<ty
::Region
>,
167 ErasedRegions
=> ErasedRegions
,
168 NonerasedRegions(r
) => NonerasedRegions(op(r
, a
))
172 pub fn is_erased(&self) -> bool
{
174 ErasedRegions
=> true,
175 NonerasedRegions(_
) => false,
180 ///////////////////////////////////////////////////////////////////////////
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
192 pub fn all() -> [ParamSpace
; 3] {
193 [TypeSpace
, SelfSpace
, FnSpace
]
196 pub fn to_uint(self) -> usize {
204 pub fn from_uint(u
: usize) -> ParamSpace
{
209 _
=> panic
!("Invalid ParamSpace: {}", u
)
214 /// Vector of things sorted by param space. Used to keep
215 /// the set of things declared on the type, self, or method
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.
223 // Here is how the representation corresponds to the abstraction
224 // i.e. the "abstraction function" AF:
226 // AF(self) = (self.content[..self.type_limit],
227 // self.content[self.type_limit..self.self_limit],
228 // self.content[self.self_limit..])
234 /// The `split` function converts one `VecPerParamSpace` into this
235 /// `SeparateVecsPerParamSpace` structure.
236 pub struct SeparateVecsPerParamSpace
<T
> {
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
)));
248 try
!(write
!(fmt
, "}}"));
253 impl<T
> VecPerParamSpace
<T
> {
254 fn limits(&self, space
: ParamSpace
) -> (usize, usize) {
256 TypeSpace
=> (0, self.type_limit
),
257 SelfSpace
=> (self.type_limit
, self.self_limit
),
258 FnSpace
=> (self.self_limit
, self.content
.len()),
262 pub fn empty() -> VecPerParamSpace
<T
> {
270 pub fn params_from_type(types
: Vec
<T
>) -> VecPerParamSpace
<T
> {
271 VecPerParamSpace
::empty().with_vec(TypeSpace
, types
)
274 /// `t` is the type space.
275 /// `s` is the self space.
276 /// `f` is the fn space.
277 pub fn new(t
: Vec
<T
>, s
: Vec
<T
>, f
: Vec
<T
>) -> VecPerParamSpace
<T
> {
278 let type_limit
= t
.len();
279 let self_limit
= type_limit
+ s
.len();
282 content
.extend(s
.into_iter());
283 content
.extend(f
.into_iter());
286 type_limit
: type_limit
,
287 self_limit
: self_limit
,
292 fn new_internal(content
: Vec
<T
>, type_limit
: usize, self_limit
: usize)
293 -> VecPerParamSpace
<T
>
296 type_limit
: type_limit
,
297 self_limit
: self_limit
,
302 /// Appends `value` to the vector associated with `space`.
304 /// Unlike the `push` method in `Vec`, this should not be assumed
305 /// to be a cheap operation (even when amortized over many calls).
306 pub fn push(&mut self, space
: ParamSpace
, value
: T
) {
307 let (_
, limit
) = self.limits(space
);
309 TypeSpace
=> { self.type_limit += 1; self.self_limit += 1; }
310 SelfSpace
=> { self.self_limit += 1; }
313 self.content
.insert(limit
, value
);
316 /// Appends `values` to the vector associated with `space`.
318 /// Unlike the `extend` method in `Vec`, this should not be assumed
319 /// to be a cheap operation (even when amortized over many calls).
320 pub fn extend
<I
:Iterator
<Item
=T
>>(&mut self, space
: ParamSpace
, values
: I
) {
321 // This could be made more efficient, obviously.
323 self.push(space
, item
);
327 pub fn pop(&mut self, space
: ParamSpace
) -> Option
<T
> {
328 let (start
, limit
) = self.limits(space
);
333 TypeSpace
=> { self.type_limit -= 1; self.self_limit -= 1; }
334 SelfSpace
=> { self.self_limit -= 1; }
337 if self.content
.is_empty() {
340 Some(self.content
.remove(limit
- 1))
345 pub fn truncate(&mut self, space
: ParamSpace
, len
: usize) {
346 // FIXME (#15435): slow; O(n^2); could enhance vec to make it O(n).
347 while self.len(space
) > len
{
352 pub fn replace(&mut self, space
: ParamSpace
, elems
: Vec
<T
>) {
353 // FIXME (#15435): slow; O(n^2); could enhance vec to make it O(n).
354 self.truncate(space
, 0);
360 pub fn get_self
<'a
>(&'a
self) -> Option
<&'a T
> {
361 let v
= self.get_slice(SelfSpace
);
362 assert
!(v
.len() <= 1);
363 if v
.is_empty() { None }
else { Some(&v[0]) }
366 pub fn len(&self, space
: ParamSpace
) -> usize {
367 self.get_slice(space
).len()
370 pub fn is_empty_in(&self, space
: ParamSpace
) -> bool
{
374 pub fn get_slice
<'a
>(&'a
self, space
: ParamSpace
) -> &'a
[T
] {
375 let (start
, limit
) = self.limits(space
);
376 &self.content
[start
.. limit
]
379 pub fn get_mut_slice
<'a
>(&'a
mut self, space
: ParamSpace
) -> &'a
mut [T
] {
380 let (start
, limit
) = self.limits(space
);
381 &mut self.content
[start
.. limit
]
384 pub fn opt_get
<'a
>(&'a
self,
388 let v
= self.get_slice(space
);
389 if index
< v
.len() { Some(&v[index]) }
else { None }
392 pub fn get
<'a
>(&'a
self, space
: ParamSpace
, index
: usize) -> &'a T
{
393 &self.get_slice(space
)[index
]
396 pub fn iter
<'a
>(&'a
self) -> Iter
<'a
,T
> {
400 pub fn into_iter(self) -> IntoIter
<T
> {
401 self.content
.into_iter()
404 pub fn iter_enumerated
<'a
>(&'a
self) -> EnumeratedItems
<'a
,T
> {
405 EnumeratedItems
::new(self)
408 pub fn as_slice(&self) -> &[T
] {
412 pub fn into_vec(self) -> Vec
<T
> {
416 pub fn all_vecs
<P
>(&self, mut pred
: P
) -> bool
where
417 P
: FnMut(&[T
]) -> bool
,
419 let spaces
= [TypeSpace
, SelfSpace
, FnSpace
];
420 spaces
.iter().all(|&space
| { pred(self.get_slice(space)) }
)
423 pub fn all
<P
>(&self, pred
: P
) -> bool
where P
: FnMut(&T
) -> bool
{
424 self.iter().all(pred
)
427 pub fn any
<P
>(&self, pred
: P
) -> bool
where P
: FnMut(&T
) -> bool
{
428 self.iter().any(pred
)
431 pub fn is_empty(&self) -> bool
{
432 self.all_vecs(|v
| v
.is_empty())
435 pub fn map
<U
, P
>(&self, pred
: P
) -> VecPerParamSpace
<U
> where P
: FnMut(&T
) -> U
{
436 let result
= self.iter().map(pred
).collect();
437 VecPerParamSpace
::new_internal(result
,
442 pub fn map_enumerated
<U
, P
>(&self, pred
: P
) -> VecPerParamSpace
<U
> where
443 P
: FnMut((ParamSpace
, usize, &T
)) -> U
,
445 let result
= self.iter_enumerated().map(pred
).collect();
446 VecPerParamSpace
::new_internal(result
,
451 pub fn map_move
<U
, F
>(self, mut pred
: F
) -> VecPerParamSpace
<U
> where
454 let SeparateVecsPerParamSpace
{
460 VecPerParamSpace
::new(t
.into_iter().map(|p
| pred(p
)).collect(),
461 s
.into_iter().map(|p
| pred(p
)).collect(),
462 f
.into_iter().map(|p
| pred(p
)).collect())
465 pub fn split(self) -> SeparateVecsPerParamSpace
<T
> {
466 let VecPerParamSpace { type_limit, self_limit, content }
= self;
468 let mut content_iter
= content
.into_iter();
470 SeparateVecsPerParamSpace
{
471 types
: content_iter
.by_ref().take(type_limit
).collect(),
472 selfs
: content_iter
.by_ref().take(self_limit
- type_limit
).collect(),
473 fns
: content_iter
.collect()
477 pub fn with_vec(mut self, space
: ParamSpace
, vec
: Vec
<T
>)
478 -> VecPerParamSpace
<T
>
480 assert
!(self.is_empty_in(space
));
481 self.replace(space
, vec
);
487 pub struct EnumeratedItems
<'a
,T
:'a
> {
488 vec
: &'a VecPerParamSpace
<T
>,
493 impl<'a
,T
> EnumeratedItems
<'a
,T
> {
494 fn new(v
: &'a VecPerParamSpace
<T
>) -> EnumeratedItems
<'a
,T
> {
495 let mut result
= EnumeratedItems { vec: v, space_index: 0, elem_index: 0 }
;
496 result
.adjust_space();
500 fn adjust_space(&mut self) {
501 let spaces
= ParamSpace
::all();
503 self.space_index
< spaces
.len() &&
504 self.elem_index
>= self.vec
.len(spaces
[self.space_index
])
506 self.space_index
+= 1;
512 impl<'a
,T
> Iterator
for EnumeratedItems
<'a
,T
> {
513 type Item
= (ParamSpace
, usize, &'a T
);
515 fn next(&mut self) -> Option
<(ParamSpace
, usize, &'a T
)> {
516 let spaces
= ParamSpace
::all();
517 if self.space_index
< spaces
.len() {
518 let space
= spaces
[self.space_index
];
519 let index
= self.elem_index
;
520 let item
= self.vec
.get(space
, index
);
522 self.elem_index
+= 1;
525 Some((space
, index
, item
))
532 impl<T
> IntoIterator
for VecPerParamSpace
<T
> {
534 type IntoIter
= IntoIter
<T
>;
536 fn into_iter(self) -> IntoIter
<T
> {
537 self.into_vec().into_iter()
541 impl<'a
,T
> IntoIterator
for &'a VecPerParamSpace
<T
> {
543 type IntoIter
= Iter
<'a
, T
>;
545 fn into_iter(self) -> Iter
<'a
, T
> {
546 self.as_slice().into_iter()
551 ///////////////////////////////////////////////////////////////////////////
552 // Public trait `Subst`
554 // Just call `foo.subst(tcx, substs)` to perform a substitution across
555 // `foo`. Or use `foo.subst_spanned(tcx, substs, Some(span))` when
556 // there is more information available (for better errors).
558 pub trait Subst
<'tcx
> : Sized
{
559 fn subst(&self, tcx
: &ty
::ctxt
<'tcx
>, substs
: &Substs
<'tcx
>) -> Self {
560 self.subst_spanned(tcx
, substs
, None
)
563 fn subst_spanned(&self, tcx
: &ty
::ctxt
<'tcx
>,
564 substs
: &Substs
<'tcx
>,
569 impl<'tcx
, T
:TypeFoldable
<'tcx
>> Subst
<'tcx
> for T
{
570 fn subst_spanned(&self,
571 tcx
: &ty
::ctxt
<'tcx
>,
572 substs
: &Substs
<'tcx
>,
576 let mut folder
= SubstFolder
{ tcx
: tcx
,
581 region_binders_passed
: 0 };
582 (*self).fold_with(&mut folder
)
586 ///////////////////////////////////////////////////////////////////////////
587 // The actual substitution engine itself is a type folder.
589 struct SubstFolder
<'a
, 'tcx
: 'a
> {
590 tcx
: &'a ty
::ctxt
<'tcx
>,
591 substs
: &'a Substs
<'tcx
>,
593 // The location for which the substitution is performed, if available.
596 // The root type that is being substituted, if available.
597 root_ty
: Option
<Ty
<'tcx
>>,
599 // Depth of type stack
600 ty_stack_depth
: usize,
602 // Number of region binders we have passed through while doing the substitution
603 region_binders_passed
: u32,
606 impl<'a
, 'tcx
> TypeFolder
<'tcx
> for SubstFolder
<'a
, 'tcx
> {
607 fn tcx(&self) -> &ty
::ctxt
<'tcx
> { self.tcx }
609 fn enter_region_binder(&mut self) {
610 self.region_binders_passed
+= 1;
613 fn exit_region_binder(&mut self) {
614 self.region_binders_passed
-= 1;
617 fn fold_region(&mut self, r
: ty
::Region
) -> ty
::Region
{
618 // Note: This routine only handles regions that are bound on
619 // type declarations and other outer declarations, not those
620 // bound in *fn types*. Region substitution of the bound
621 // regions that appear in a function signature is done using
622 // the specialized routine `ty::replace_late_regions()`.
624 ty
::ReEarlyBound(data
) => {
625 match self.substs
.regions
{
626 ErasedRegions
=> ty
::ReStatic
,
627 NonerasedRegions(ref regions
) =>
628 match regions
.opt_get(data
.space
, data
.index
as usize) {
630 self.shift_region_through_binders(r
)
633 let span
= self.span
.unwrap_or(DUMMY_SP
);
634 self.tcx().sess
.span_bug(
636 &format
!("Type parameter out of range \
637 when substituting in region {} (root type={}) \
638 (space={:?}, index={})",
640 self.root_ty
.repr(self.tcx()),
651 fn fold_ty(&mut self, t
: Ty
<'tcx
>) -> Ty
<'tcx
> {
652 if !ty
::type_needs_subst(t
) {
656 // track the root type we were asked to substitute
657 let depth
= self.ty_stack_depth
;
659 self.root_ty
= Some(t
);
661 self.ty_stack_depth
+= 1;
663 let t1
= match t
.sty
{
665 self.ty_for_param(p
, t
)
668 ty_fold
::super_fold_ty(self, t
)
672 assert_eq
!(depth
+ 1, self.ty_stack_depth
);
673 self.ty_stack_depth
-= 1;
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 usize);
686 let ty
= match opt_ty
{
689 let span
= self.span
.unwrap_or(DUMMY_SP
);
690 self.tcx().sess
.span_bug(
692 &format
!("Type parameter `{}` ({}/{:?}/{}) out of range \
693 when substituting (root type={}) substs={}",
695 source_ty
.repr(self.tcx()),
698 self.root_ty
.repr(self.tcx()),
699 self.substs
.repr(self.tcx())));
703 self.shift_regions_through_binders(ty
)
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:
711 /// type Func<A> = fn(A);
712 /// type MetaFunc = for<'a> fn(Func<&'a int>)
715 /// The type `MetaFunc`, when fully expanded, will be
717 /// for<'a> fn(fn(&'a int))
720 /// | | DebruijnIndex of 2
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.
730 /// As a second example, consider this twist:
733 /// type FuncTuple<A> = (A,fn(A));
734 /// type MetaFuncTuple = for<'a> fn(FuncTuple<&'a int>)
737 /// Here the final type will be:
739 /// for<'a> fn((&'a int, fn(&'a int)))
742 /// DebruijnIndex of 1 |
743 /// DebruijnIndex of 2
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
));
752 if self.region_binders_passed
== 0 || !ty
::type_has_escaping_regions(ty
) {
756 let result
= ty_fold
::shift_regions(self.tcx(), self.region_binders_passed
, &ty
);
757 debug
!("shift_regions: shifted result = {:?}", result
.repr(self.tcx()));
762 fn shift_region_through_binders(&self, region
: ty
::Region
) -> ty
::Region
{
763 ty_fold
::shift_region(region
, self.region_binders_passed
)