about summary refs log tree commit diff
path: root/src/librustc_mir/interpret
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2018-11-01 13:53:21 +0100
committerRalf Jung <post@ralfj.de>2018-11-05 09:17:48 +0100
commit6d24b37a70de0afc2b145aff72964162ec8a4291 (patch)
tree199d68820b027e763b6767420006807aa269091d /src/librustc_mir/interpret
parentb0f1b1a73ee1c5be48d3a288eff50a46b773a9df (diff)
downloadrust-6d24b37a70de0afc2b145aff72964162ec8a4291.tar.gz
rust-6d24b37a70de0afc2b145aff72964162ec8a4291.zip
let the Value handle enum projections, so the visitor does not have to care
Diffstat (limited to 'src/librustc_mir/interpret')
-rw-r--r--src/librustc_mir/interpret/validity.rs39
-rw-r--r--src/librustc_mir/interpret/visitor.rs47
2 files changed, 56 insertions, 30 deletions
diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs
index 2d977d10944..f7ba92c40eb 100644
--- a/src/librustc_mir/interpret/validity.rs
+++ b/src/librustc_mir/interpret/validity.rs
@@ -173,11 +173,15 @@ impl<'rt, 'a, 'tcx, Tag> ValidityVisitor<'rt, 'a, 'tcx, Tag> {
 
             // enums
             ty::Adt(def, ..) if def.is_enum() => {
-                let variant = match layout.variants {
-                    layout::Variants::Single { index } => &def.variants[index],
-                    _ => bug!("aggregate_field_path_elem: got enum but not in a specific variant"),
-                };
-                PathElem::Field(variant.fields[field].ident.name)
+                // we might be projecting *to* a variant, or to a field *in*a variant.
+                match layout.variants {
+                    layout::Variants::Single { index } =>
+                        // Inside a variant
+                        PathElem::Field(def.variants[index].fields[field].ident.name),
+                    _ =>
+                        // To a variant
+                        PathElem::Field(def.variants[field].name)
+                }
             }
 
             // other ADTs
@@ -226,30 +230,21 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
         Ok(())
     }
 
-    fn downcast_enum(&mut self, ectx: &EvalContext<'a, 'mir, 'tcx, M>)
+    #[inline]
+    fn visit(&mut self, ectx: &mut EvalContext<'a, 'mir, 'tcx, M>)
         -> EvalResult<'tcx>
     {
-        let variant = match ectx.read_discriminant(self.op) {
-            Ok(res) => res.1,
-            Err(err) => return match err.kind {
+        // Translate enum discriminant errors to something nicer.
+        match ectx.walk_value(self) {
+            Ok(()) => Ok(()),
+            Err(err) => match err.kind {
                 EvalErrorKind::InvalidDiscriminant(val) =>
                     validation_failure!(
                         format!("invalid enum discriminant {}", val), self.path
                     ),
-                _ =>
-                    validation_failure!(
-                        format!("non-integer enum discriminant"), self.path
-                    ),
+                _ => Err(err),
             }
-        };
-        // Put the variant projection onto the path, as a field
-        self.path.push(PathElem::Field(self.op.layout.ty
-                                    .ty_adt_def()
-                                    .unwrap()
-                                    .variants[variant].name));
-        // Proceed with this variant
-        self.op = ectx.operand_downcast(self.op, variant)?;
-        Ok(())
+        }
     }
 
     fn visit_primitive(&mut self, ectx: &mut EvalContext<'a, 'mir, 'tcx, M>)
diff --git a/src/librustc_mir/interpret/visitor.rs b/src/librustc_mir/interpret/visitor.rs
index 96e76ffd972..863eeb3b250 100644
--- a/src/librustc_mir/interpret/visitor.rs
+++ b/src/librustc_mir/interpret/visitor.rs
@@ -30,6 +30,13 @@ pub trait Value<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>: Copy
     // Create this from an `MPlaceTy`.
     fn from_mem_place(MPlaceTy<'tcx, M::PointerTag>) -> Self;
 
+    // Read the current enum discriminant, and downcast to that.  Also return the
+    // variant index.
+    fn project_downcast(
+        self,
+        ectx: &EvalContext<'a, 'mir, 'tcx, M>
+    ) -> EvalResult<'tcx, (Self, usize)>;
+
     // Project to the n-th field.
     fn project_field(
         self,
@@ -61,6 +68,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
     }
 
     #[inline(always)]
+    fn project_downcast(
+        self,
+        ectx: &EvalContext<'a, 'mir, 'tcx, M>
+    ) -> EvalResult<'tcx, (Self, usize)> {
+        let idx = ectx.read_discriminant(self)?.1;
+        Ok((ectx.operand_downcast(self, idx)?, idx))
+    }
+
+    #[inline(always)]
     fn project_field(
         self,
         ectx: &mut EvalContext<'a, 'mir, 'tcx, M>,
@@ -91,6 +107,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
     }
 
     #[inline(always)]
+    fn project_downcast(
+        self,
+        ectx: &EvalContext<'a, 'mir, 'tcx, M>
+    ) -> EvalResult<'tcx, (Self, usize)> {
+        let idx = ectx.read_discriminant(self.into())?.1;
+        Ok((ectx.mplace_downcast(self, idx)?, idx))
+    }
+
+    #[inline(always)]
     fn project_field(
         self,
         ectx: &mut EvalContext<'a, 'mir, 'tcx, M>,
@@ -121,6 +146,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
     }
 
     #[inline(always)]
+    fn project_downcast(
+        self,
+        ectx: &EvalContext<'a, 'mir, 'tcx, M>
+    ) -> EvalResult<'tcx, (Self, usize)> {
+        let idx = ectx.read_discriminant(ectx.place_to_op(self)?)?.1;
+        Ok((ectx.place_downcast(self, idx)?, idx))
+    }
+
+    #[inline(always)]
     fn project_field(
         self,
         ectx: &mut EvalContext<'a, 'mir, 'tcx, M>,
@@ -155,12 +189,6 @@ pub trait ValueVisitor<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>: fmt::Debug +
         field: usize,
     ) -> EvalResult<'tcx>;
 
-    // This is an enum, downcast it to whatever the current variant is.
-    // (We do this here and not in `Value` to keep error handling
-    // under control of th visitor.)
-    fn downcast_enum(&mut self, ectx: &EvalContext<'a, 'mir, 'tcx, M>)
-        -> EvalResult<'tcx>;
-
     // A chance for the visitor to do special (different or more efficient) handling for some
     // array types.  Return `true` if the value was handled and we should return.
     #[inline]
@@ -202,8 +230,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         match v.layout().variants {
             layout::Variants::NicheFilling { .. } |
             layout::Variants::Tagged { .. } => {
-                v.downcast_enum(self)?;
-                trace!("variant layout: {:#?}", v.layout());
+                let (inner, idx) = v.value().project_downcast(self)?;
+                trace!("variant layout: {:#?}", inner.layout());
+                // recurse with the inner type
+                return v.visit_field(self, inner, idx);
             }
             layout::Variants::Single { .. } => {}
         }
@@ -215,6 +245,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
                 // immediate trait objects are not a thing
                 let dest = v.value().force_allocation(self)?;
                 let inner = self.unpack_dyn_trait(dest)?.1;
+                trace!("dyn object layout: {:#?}", inner.layout);
                 // recurse with the inner type
                 return v.visit_field(self, Value::from_mem_place(inner), 0);
             },