diff options
Diffstat (limited to 'src/librustc/ty/subst.rs')
| -rw-r--r-- | src/librustc/ty/subst.rs | 88 |
1 files changed, 62 insertions, 26 deletions
diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 64cfba7df6e..b7f1731ba44 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -12,7 +12,7 @@ use hir::def_id::DefId; use infer::canonical::Canonical; -use ty::{self, CanonicalVar, Lift, List, Ty, TyCtxt}; +use ty::{self, BoundVar, Lift, List, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use serialize::{self, Encodable, Encoder, Decodable, Decoder}; @@ -27,7 +27,7 @@ use std::marker::PhantomData; use std::mem; use std::num::NonZeroUsize; -/// An entity in the Rust typesystem, which can be one of +/// An entity in the Rust type system, which can be one of /// several kinds (only types and lifetimes for now). /// To reduce memory usage, a `Kind` is a interned pointer, /// with the lowest 2 bits being reserved for a tag to @@ -171,7 +171,7 @@ impl<'tcx> Decodable for Kind<'tcx> { pub type Substs<'tcx> = List<Kind<'tcx>>; impl<'a, 'gcx, 'tcx> Substs<'tcx> { - /// Creates a Substs that maps each generic parameter to itself. + /// Creates a `Substs` that maps each generic parameter to itself. pub fn identity_for_item(tcx: TyCtxt<'a, 'gcx, 'tcx>, def_id: DefId) -> &'tcx Substs<'tcx> { Substs::for_item(tcx, def_id, |param, _| { @@ -179,9 +179,37 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { }) } - /// Creates a Substs for generic parameter definitions, + /// Creates a `Substs` that maps each generic parameter to a higher-ranked + /// var bound at index `0`. For types, we use a `BoundVar` index equal to + /// the type parameter index. For regions, we use the `BoundRegion::BrNamed` + /// variant (which has a def-id). + pub fn bound_vars_for_item( + tcx: TyCtxt<'a, 'gcx, 'tcx>, + def_id: DefId + ) -> &'tcx Substs<'tcx> { + Substs::for_item(tcx, def_id, |param, _| { + match param.kind { + ty::GenericParamDefKind::Type { .. } => { + tcx.mk_ty(ty::Bound(ty::BoundTy { + index: ty::INNERMOST, + var: ty::BoundVar::from(param.index), + kind: ty::BoundTyKind::Param(param.name), + })).into() + } + + ty::GenericParamDefKind::Lifetime => { + tcx.mk_region(ty::RegionKind::ReLateBound( + ty::INNERMOST, + ty::BoundRegion::BrNamed(param.def_id, param.name) + )).into() + } + } + }) + } + + /// Creates a `Substs` for generic parameter definitions, /// by calling closures to obtain each kind. - /// The closures get to observe the Substs as they're + /// The closures get to observe the `Substs` as they're /// being built, which can be used to correctly /// substitute defaults of generic parameters. pub fn for_item<F>(tcx: TyCtxt<'a, 'gcx, 'tcx>, @@ -242,7 +270,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { } #[inline] - pub fn types(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a { + pub fn types(&'a self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'a { self.iter().filter_map(|k| { if let UnpackedKind::Type(ty) = k.unpack() { Some(ty) @@ -253,7 +281,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { } #[inline] - pub fn regions(&'a self) -> impl DoubleEndedIterator<Item=ty::Region<'tcx>> + 'a { + pub fn regions(&'a self) -> impl DoubleEndedIterator<Item = ty::Region<'tcx>> + 'a { self.iter().filter_map(|k| { if let UnpackedKind::Lifetime(lt) = k.unpack() { Some(lt) @@ -332,7 +360,7 @@ impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Substs<'tcx> {} // `foo`. Or use `foo.subst_spanned(tcx, substs, Some(span))` when // there is more information available (for better errors). -pub trait Subst<'tcx> : Sized { +pub trait Subst<'tcx>: Sized { fn subst<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, substs: &[Kind<'tcx>]) -> Self { self.subst_spanned(tcx, substs, None) @@ -355,7 +383,7 @@ impl<'tcx, T:TypeFoldable<'tcx>> Subst<'tcx> for T { span, root_ty: None, ty_stack_depth: 0, - region_binders_passed: 0 }; + binders_passed: 0 }; (*self).fold_with(&mut folder) } } @@ -377,16 +405,16 @@ struct SubstFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { ty_stack_depth: usize, // Number of region binders we have passed through while doing the substitution - region_binders_passed: u32, + binders_passed: u32, } impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> { fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx } fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> { - self.region_binders_passed += 1; + self.binders_passed += 1; let t = t.super_fold_with(self); - self.region_binders_passed -= 1; + self.binders_passed -= 1; t } @@ -471,12 +499,12 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { } }; - self.shift_regions_through_binders(ty) + self.shift_vars_through_binders(ty) } /// It is sometimes necessary to adjust the debruijn indices during substitution. This occurs - /// when we are substituting a type with escaping regions into a context where we have passed - /// through region binders. That's quite a mouthful. Let's see an example: + /// when we are substituting a type with escaping bound vars into a context where we have + /// passed through binders. That's quite a mouthful. Let's see an example: /// /// ``` /// type Func<A> = fn(A); @@ -516,25 +544,25 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { /// As indicated in the diagram, here the same type `&'a int` is substituted once, but in the /// first case we do not increase the Debruijn index and in the second case we do. The reason /// is that only in the second case have we passed through a fn binder. - fn shift_regions_through_binders(&self, ty: Ty<'tcx>) -> Ty<'tcx> { - debug!("shift_regions(ty={:?}, region_binders_passed={:?}, has_escaping_regions={:?})", - ty, self.region_binders_passed, ty.has_escaping_regions()); + fn shift_vars_through_binders(&self, ty: Ty<'tcx>) -> Ty<'tcx> { + debug!("shift_vars(ty={:?}, binders_passed={:?}, has_escaping_bound_vars={:?})", + ty, self.binders_passed, ty.has_escaping_bound_vars()); - if self.region_binders_passed == 0 || !ty.has_escaping_regions() { + if self.binders_passed == 0 || !ty.has_escaping_bound_vars() { return ty; } - let result = ty::fold::shift_regions(self.tcx(), self.region_binders_passed, &ty); - debug!("shift_regions: shifted result = {:?}", result); + let result = ty::fold::shift_vars(self.tcx(), &ty, self.binders_passed); + debug!("shift_vars: shifted result = {:?}", result); result } fn shift_region_through_binders(&self, region: ty::Region<'tcx>) -> ty::Region<'tcx> { - if self.region_binders_passed == 0 || !region.has_escaping_regions() { + if self.binders_passed == 0 || !region.has_escaping_bound_vars() { return region; } - self.tcx().mk_region(ty::fold::shift_region(*region, self.region_binders_passed)) + ty::fold::shift_region(self.tcx, region, self.binders_passed) } } @@ -553,15 +581,23 @@ impl CanonicalUserSubsts<'tcx> { return false; } - self.value.substs.iter().zip(CanonicalVar::new(0)..).all(|(kind, cvar)| { + self.value.substs.iter().zip(BoundVar::new(0)..).all(|(kind, cvar)| { match kind.unpack() { UnpackedKind::Type(ty) => match ty.sty { - ty::Infer(ty::CanonicalTy(cvar1)) => cvar == cvar1, + ty::Bound(b) => { + // We only allow a `ty::INNERMOST` index in substitutions. + assert_eq!(b.index, ty::INNERMOST); + cvar == b.var + } _ => false, }, UnpackedKind::Lifetime(r) => match r { - ty::ReCanonical(cvar1) => cvar == *cvar1, + ty::ReLateBound(index, br) => { + // We only allow a `ty::INNERMOST` index in substitutions. + assert_eq!(*index, ty::INNERMOST); + cvar == br.assert_bound_var() + } _ => false, }, } |
