use crate::hir::def_id::DefId;
use crate::infer::canonical::Canonical;
-use crate::ty::{self, Lift, List, Ty, TyCtxt};
+use crate::ty::{self, Lift, List, Ty, TyCtxt, InferConst, ParamConst};
use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
+use crate::mir::interpret::ConstValue;
use serialize::{self, Encodable, Encoder, Decodable, Decoder};
use syntax_pos::{Span, DUMMY_SP};
use std::num::NonZeroUsize;
/// An entity in the Rust type system, which can be one of
-/// several kinds (only types and lifetimes for now).
+/// several kinds (types, lifetimes, and consts).
/// To reduce memory usage, a `Kind` is a interned pointer,
/// with the lowest 2 bits being reserved for a tag to
-/// indicate the type (`Ty` or `Region`) it points to.
+/// indicate the type (`Ty`, `Region`, or `Const`) it points to.
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct Kind<'tcx> {
ptr: NonZeroUsize,
- marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>)>
+ marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>, &'tcx ty::LazyConst<'tcx>)>
}
const TAG_MASK: usize = 0b11;
const TYPE_TAG: usize = 0b00;
const REGION_TAG: usize = 0b01;
+const CONST_TAG: usize = 0b10;
#[derive(Debug, RustcEncodable, RustcDecodable, PartialEq, Eq, PartialOrd, Ord)]
pub enum UnpackedKind<'tcx> {
Lifetime(ty::Region<'tcx>),
Type(Ty<'tcx>),
+ Const(&'tcx ty::LazyConst<'tcx>),
}
impl<'tcx> UnpackedKind<'tcx> {
assert_eq!(mem::align_of_val(ty) & TAG_MASK, 0);
(TYPE_TAG, ty as *const _ as usize)
}
+ UnpackedKind::Const(ct) => {
+ // Ensure we can use the tag bits.
+ assert_eq!(mem::align_of_val(ct) & TAG_MASK, 0);
+ (CONST_TAG, ct as *const _ as usize)
+ }
};
Kind {
}
}
+impl<'tcx> From<&'tcx ty::LazyConst<'tcx>> for Kind<'tcx> {
+ fn from(c: &'tcx ty::LazyConst<'tcx>) -> Kind<'tcx> {
+ UnpackedKind::Const(c).pack()
+ }
+}
+
impl<'tcx> Kind<'tcx> {
#[inline]
pub fn unpack(self) -> UnpackedKind<'tcx> {
match ptr & TAG_MASK {
REGION_TAG => UnpackedKind::Lifetime(&*((ptr & !TAG_MASK) as *const _)),
TYPE_TAG => UnpackedKind::Type(&*((ptr & !TAG_MASK) as *const _)),
+ CONST_TAG => UnpackedKind::Const(&*((ptr & !TAG_MASK) as *const _)),
_ => intrinsics::unreachable()
}
}
match self.unpack() {
UnpackedKind::Lifetime(lt) => write!(f, "{:?}", lt),
UnpackedKind::Type(ty) => write!(f, "{:?}", ty),
+ UnpackedKind::Const(ct) => write!(f, "{:?}", ct),
}
}
}
match self.unpack() {
UnpackedKind::Lifetime(lt) => write!(f, "{}", lt),
UnpackedKind::Type(ty) => write!(f, "{}", ty),
+ UnpackedKind::Const(ct) => write!(f, "{}", ct),
}
}
}
fn lift_to_tcx<'cx, 'gcx>(&self, tcx: TyCtxt<'cx, 'gcx, 'tcx>) -> Option<Self::Lifted> {
match self.unpack() {
- UnpackedKind::Lifetime(a) => a.lift_to_tcx(tcx).map(|a| a.into()),
- UnpackedKind::Type(a) => a.lift_to_tcx(tcx).map(|a| a.into()),
+ UnpackedKind::Lifetime(lt) => lt.lift_to_tcx(tcx).map(|lt| lt.into()),
+ UnpackedKind::Type(ty) => ty.lift_to_tcx(tcx).map(|ty| ty.into()),
+ UnpackedKind::Const(ct) => ct.lift_to_tcx(tcx).map(|ct| ct.into()),
}
}
}
match self.unpack() {
UnpackedKind::Lifetime(lt) => lt.fold_with(folder).into(),
UnpackedKind::Type(ty) => ty.fold_with(folder).into(),
+ UnpackedKind::Const(ct) => ct.fold_with(folder).into(),
}
}
match self.unpack() {
UnpackedKind::Lifetime(lt) => lt.visit_with(visitor),
UnpackedKind::Type(ty) => ty.visit_with(visitor),
+ UnpackedKind::Const(ct) => ct.visit_with(visitor),
}
}
}
ty::BoundRegion::BrNamed(param.def_id, param.name)
)).into()
}
+
+ ty::GenericParamDefKind::Const => {
+ tcx.mk_lazy_const(ty::LazyConst::Evaluated(ty::Const {
+ val: ConstValue::Infer(
+ InferConst::Canonical(ty::INNERMOST, ty::BoundVar::from(param.index))
+ ),
+ ty: tcx.type_of(def_id),
+ })).into()
+ }
}
})
}
})
}
+ #[inline]
+ pub fn consts(&'a self) -> impl DoubleEndedIterator<Item = &'tcx ty::LazyConst<'tcx>> + 'a {
+ self.iter().filter_map(|k| {
+ if let UnpackedKind::Const(ct) = k.unpack() {
+ Some(ct)
+ } else {
+ None
+ }
+ })
+ }
+
+ #[inline]
+ pub fn non_erasable_generics(
+ &'a self
+ ) -> impl DoubleEndedIterator<Item = UnpackedKind<'tcx>> + 'a {
+ self.iter().filter_map(|k| {
+ match k.unpack() {
+ UnpackedKind::Lifetime(_) => None,
+ generic => Some(generic),
+ }
+ })
+ }
+
#[inline]
pub fn type_at(&self, i: usize) -> Ty<'tcx> {
if let UnpackedKind::Type(ty) = self[i].unpack() {
}
}
+ #[inline]
+ pub fn const_at(&self, i: usize) -> &'tcx ty::LazyConst<'tcx> {
+ if let UnpackedKind::Const(ct) = self[i].unpack() {
+ ct
+ } else {
+ bug!("expected const for param #{} in {:?}", i, self);
+ }
+ }
+
#[inline]
pub fn type_for_def(&self, def: &ty::GenericParamDef) -> Kind<'tcx> {
self.type_at(def.index as usize).into()
return t1;
}
+
+ fn fold_const(&mut self, c: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> {
+ if !c.needs_subst() {
+ return c;
+ }
+
+ if let ty::LazyConst::Evaluated(ty::Const {
+ val: ConstValue::Param(p),
+ ..
+ }) = c {
+ self.const_for_param(*p, c)
+ } else {
+ c.super_fold_with(self)
+ }
+ }
}
impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> {
self.shift_vars_through_binders(ty)
}
+ fn const_for_param(
+ &self,
+ p: ParamConst,
+ source_cn: &'tcx ty::LazyConst<'tcx>
+ ) -> &'tcx ty::LazyConst<'tcx> {
+ // Look up the const in the substitutions. It really should be in there.
+ let opt_cn = self.substs.get(p.index as usize).map(|k| k.unpack());
+ let cn = match opt_cn {
+ Some(UnpackedKind::Const(cn)) => cn,
+ _ => {
+ let span = self.span.unwrap_or(DUMMY_SP);
+ span_bug!(
+ span,
+ "Const parameter `{:?}` ({:?}/{}) out of range \
+ when substituting (root type={:?}) substs={:?}",
+ p,
+ source_cn,
+ p.index,
+ self.root_ty,
+ self.substs,
+ );
+ }
+ };
+
+ // FIXME(const_generics): shift const through binders
+ cn
+ }
+
/// It is sometimes necessary to adjust the De Bruijn indices during substitution. This occurs
/// 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: