]> git.lizzy.rs Git - rust.git/commitdiff
Add const kind and UnpackedKind::Const
authorvarkor <github@varkor.com>
Wed, 20 Feb 2019 01:12:15 +0000 (01:12 +0000)
committervarkor <github@varkor.com>
Tue, 5 Mar 2019 22:08:44 +0000 (22:08 +0000)
Co-Authored-By: Gabriel Smith <yodaldevoid@users.noreply.github.com>
src/librustc/ty/subst.rs

index 450fab81661fc72336319c4298ca548ff3b220bf..35c6f980cd9342d77969dbf8f4603f2f8c86821f 100644 (file)
@@ -2,8 +2,9 @@
 
 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> {
@@ -50,6 +53,11 @@ fn pack(self) -> Kind<'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 {
@@ -85,6 +93,12 @@ fn from(ty: Ty<'tcx>) -> Kind<'tcx> {
     }
 }
 
+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> {
@@ -93,6 +107,7 @@ 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()
             }
         }
@@ -104,6 +119,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self.unpack() {
             UnpackedKind::Lifetime(lt) => write!(f, "{:?}", lt),
             UnpackedKind::Type(ty) => write!(f, "{:?}", ty),
+            UnpackedKind::Const(ct) => write!(f, "{:?}", ct),
         }
     }
 }
@@ -113,6 +129,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self.unpack() {
             UnpackedKind::Lifetime(lt) => write!(f, "{}", lt),
             UnpackedKind::Type(ty) => write!(f, "{}", ty),
+            UnpackedKind::Const(ct) => write!(f, "{}", ct),
         }
     }
 }
@@ -122,8 +139,9 @@ impl<'a, 'tcx> Lift<'tcx> for Kind<'a> {
 
     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()),
         }
     }
 }
@@ -133,6 +151,7 @@ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F)
         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(),
         }
     }
 
@@ -140,6 +159,7 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
         match self.unpack() {
             UnpackedKind::Lifetime(lt) => lt.visit_with(visitor),
             UnpackedKind::Type(ty) => ty.visit_with(visitor),
+            UnpackedKind::Const(ct) => ct.visit_with(visitor),
         }
     }
 }
@@ -195,6 +215,15 @@ pub fn bound_vars_for_item(
                         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()
+                }
             }
         })
     }
@@ -283,6 +312,29 @@ pub fn regions(&'a self) -> impl DoubleEndedIterator<Item = ty::Region<'tcx>> +
         })
     }
 
+    #[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() {
@@ -301,6 +353,15 @@ pub fn region_at(&self, i: usize) -> ty::Region<'tcx> {
         }
     }
 
+    #[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()
@@ -469,6 +530,21 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
 
         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> {
@@ -494,6 +570,34 @@ fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'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: