Skip to content

Commit 6d24b37

Browse files
committed
let the Value handle enum projections, so the visitor does not have to care
1 parent b0f1b1a commit 6d24b37

File tree

2 files changed

+56
-30
lines changed

2 files changed

+56
-30
lines changed

src/librustc_mir/interpret/validity.rs

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -173,11 +173,15 @@ impl<'rt, 'a, 'tcx, Tag> ValidityVisitor<'rt, 'a, 'tcx, Tag> {
173173

174174
// enums
175175
ty::Adt(def, ..) if def.is_enum() => {
176-
let variant = match layout.variants {
177-
layout::Variants::Single { index } => &def.variants[index],
178-
_ => bug!("aggregate_field_path_elem: got enum but not in a specific variant"),
179-
};
180-
PathElem::Field(variant.fields[field].ident.name)
176+
// we might be projecting *to* a variant, or to a field *in*a variant.
177+
match layout.variants {
178+
layout::Variants::Single { index } =>
179+
// Inside a variant
180+
PathElem::Field(def.variants[index].fields[field].ident.name),
181+
_ =>
182+
// To a variant
183+
PathElem::Field(def.variants[field].name)
184+
}
181185
}
182186

183187
// other ADTs
@@ -226,30 +230,21 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
226230
Ok(())
227231
}
228232

229-
fn downcast_enum(&mut self, ectx: &EvalContext<'a, 'mir, 'tcx, M>)
233+
#[inline]
234+
fn visit(&mut self, ectx: &mut EvalContext<'a, 'mir, 'tcx, M>)
230235
-> EvalResult<'tcx>
231236
{
232-
let variant = match ectx.read_discriminant(self.op) {
233-
Ok(res) => res.1,
234-
Err(err) => return match err.kind {
237+
// Translate enum discriminant errors to something nicer.
238+
match ectx.walk_value(self) {
239+
Ok(()) => Ok(()),
240+
Err(err) => match err.kind {
235241
EvalErrorKind::InvalidDiscriminant(val) =>
236242
validation_failure!(
237243
format!("invalid enum discriminant {}", val), self.path
238244
),
239-
_ =>
240-
validation_failure!(
241-
format!("non-integer enum discriminant"), self.path
242-
),
245+
_ => Err(err),
243246
}
244-
};
245-
// Put the variant projection onto the path, as a field
246-
self.path.push(PathElem::Field(self.op.layout.ty
247-
.ty_adt_def()
248-
.unwrap()
249-
.variants[variant].name));
250-
// Proceed with this variant
251-
self.op = ectx.operand_downcast(self.op, variant)?;
252-
Ok(())
247+
}
253248
}
254249

255250
fn visit_primitive(&mut self, ectx: &mut EvalContext<'a, 'mir, 'tcx, M>)

src/librustc_mir/interpret/visitor.rs

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ pub trait Value<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>: Copy
3030
// Create this from an `MPlaceTy`.
3131
fn from_mem_place(MPlaceTy<'tcx, M::PointerTag>) -> Self;
3232

33+
// Read the current enum discriminant, and downcast to that. Also return the
34+
// variant index.
35+
fn project_downcast(
36+
self,
37+
ectx: &EvalContext<'a, 'mir, 'tcx, M>
38+
) -> EvalResult<'tcx, (Self, usize)>;
39+
3340
// Project to the n-th field.
3441
fn project_field(
3542
self,
@@ -60,6 +67,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
6067
mplace.into()
6168
}
6269

70+
#[inline(always)]
71+
fn project_downcast(
72+
self,
73+
ectx: &EvalContext<'a, 'mir, 'tcx, M>
74+
) -> EvalResult<'tcx, (Self, usize)> {
75+
let idx = ectx.read_discriminant(self)?.1;
76+
Ok((ectx.operand_downcast(self, idx)?, idx))
77+
}
78+
6379
#[inline(always)]
6480
fn project_field(
6581
self,
@@ -90,6 +106,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
90106
mplace
91107
}
92108

109+
#[inline(always)]
110+
fn project_downcast(
111+
self,
112+
ectx: &EvalContext<'a, 'mir, 'tcx, M>
113+
) -> EvalResult<'tcx, (Self, usize)> {
114+
let idx = ectx.read_discriminant(self.into())?.1;
115+
Ok((ectx.mplace_downcast(self, idx)?, idx))
116+
}
117+
93118
#[inline(always)]
94119
fn project_field(
95120
self,
@@ -120,6 +145,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
120145
mplace.into()
121146
}
122147

148+
#[inline(always)]
149+
fn project_downcast(
150+
self,
151+
ectx: &EvalContext<'a, 'mir, 'tcx, M>
152+
) -> EvalResult<'tcx, (Self, usize)> {
153+
let idx = ectx.read_discriminant(ectx.place_to_op(self)?)?.1;
154+
Ok((ectx.place_downcast(self, idx)?, idx))
155+
}
156+
123157
#[inline(always)]
124158
fn project_field(
125159
self,
@@ -155,12 +189,6 @@ pub trait ValueVisitor<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>: fmt::Debug +
155189
field: usize,
156190
) -> EvalResult<'tcx>;
157191

158-
// This is an enum, downcast it to whatever the current variant is.
159-
// (We do this here and not in `Value` to keep error handling
160-
// under control of th visitor.)
161-
fn downcast_enum(&mut self, ectx: &EvalContext<'a, 'mir, 'tcx, M>)
162-
-> EvalResult<'tcx>;
163-
164192
// A chance for the visitor to do special (different or more efficient) handling for some
165193
// array types. Return `true` if the value was handled and we should return.
166194
#[inline]
@@ -202,8 +230,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
202230
match v.layout().variants {
203231
layout::Variants::NicheFilling { .. } |
204232
layout::Variants::Tagged { .. } => {
205-
v.downcast_enum(self)?;
206-
trace!("variant layout: {:#?}", v.layout());
233+
let (inner, idx) = v.value().project_downcast(self)?;
234+
trace!("variant layout: {:#?}", inner.layout());
235+
// recurse with the inner type
236+
return v.visit_field(self, inner, idx);
207237
}
208238
layout::Variants::Single { .. } => {}
209239
}
@@ -215,6 +245,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
215245
// immediate trait objects are not a thing
216246
let dest = v.value().force_allocation(self)?;
217247
let inner = self.unpack_dyn_trait(dest)?.1;
248+
trace!("dyn object layout: {:#?}", inner.layout);
218249
// recurse with the inner type
219250
return v.visit_field(self, Value::from_mem_place(inner), 0);
220251
},

0 commit comments

Comments
 (0)