From 04eadedb2888d96c5f5222454a6ca5470e4c0834 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 19 Dec 2016 17:26:47 +0100 Subject: [PATCH] allow using tuple variant names as function handles --- src/eval_context.rs | 70 +++++++++++++++---- src/terminator/mod.rs | 27 ++++--- .../tuple_like_enum_variant_constructor.rs | 3 + 3 files changed, 75 insertions(+), 25 deletions(-) create mode 100644 tests/run-pass/tuple_like_enum_variant_constructor.rs diff --git a/src/eval_context.rs b/src/eval_context.rs index e02ea09be86..6eb9b3a1e56 100644 --- a/src/eval_context.rs +++ b/src/eval_context.rs @@ -355,18 +355,44 @@ pub(super) fn pop_stack_frame(&mut self) -> EvalResult<'tcx, ()> { Ok(()) } - fn assign_fields>( + pub fn assign_discr_and_fields< + I: IntoIterator, + V: IntoValTyPair<'tcx>, + J: IntoIterator, + >( &mut self, dest: Lvalue<'tcx>, offsets: I, - operands: &[mir::Operand<'tcx>], + operands: J, + discr_val: u128, + discr_size: u64, + ) -> EvalResult<'tcx, ()> { + // FIXME(solson) + let dest_ptr = self.force_allocation(dest)?.to_ptr(); + + let mut offsets = offsets.into_iter(); + let discr_offset = offsets.next().unwrap(); + let discr_dest = dest_ptr.offset(discr_offset); + self.memory.write_uint(discr_dest, discr_val, discr_size)?; + + self.assign_fields(dest, offsets, operands) + } + + pub fn assign_fields< + I: IntoIterator, + V: IntoValTyPair<'tcx>, + J: IntoIterator, + >( + &mut self, + dest: Lvalue<'tcx>, + offsets: I, + operands: J, ) -> EvalResult<'tcx, ()> { // FIXME(solson) let dest = self.force_allocation(dest)?.to_ptr(); for (offset, operand) in offsets.into_iter().zip(operands) { - let value = self.eval_operand(operand)?; - let value_ty = self.operand_ty(operand); + let (value, value_ty) = operand.into_val_ty_pair(self)?; let field_dest = dest.offset(offset); self.write_value_to_ptr(value, field_dest, value_ty)?; } @@ -431,18 +457,14 @@ pub(super) fn eval_rvalue_into_lvalue( if let mir::AggregateKind::Adt(adt_def, variant, _, _) = *kind { let discr_val = adt_def.variants[variant].disr_val.to_u128_unchecked(); let discr_size = discr.size().bytes(); - let discr_offset = variants[variant].offsets[0].bytes(); - - // FIXME(solson) - let dest = self.force_allocation(dest)?; - let discr_dest = (dest.to_ptr()).offset(discr_offset); - self.memory.write_uint(discr_dest, discr_val, discr_size)?; - - // Don't include the first offset; it's for the discriminant. - let field_offsets = variants[variant].offsets.iter().skip(1) - .map(|s| s.bytes()); - self.assign_fields(dest, field_offsets, operands)?; + self.assign_discr_and_fields( + dest, + variants[variant].offsets.iter().cloned().map(Size::bytes), + operands, + discr_val, + discr_size, + )?; } else { bug!("tried to assign {:?} to Layout::General", kind); } @@ -1464,3 +1486,21 @@ pub fn monomorphize_field_ty<'a, 'tcx:'a >(tcx: TyCtxt<'a, 'tcx, 'tcx>, f: &ty:: pub fn is_inhabited<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { ty.uninhabited_from(&mut FxHashSet::default(), tcx).is_empty() } + +pub trait IntoValTyPair<'tcx> { + fn into_val_ty_pair<'a>(self, ecx: &mut EvalContext<'a, 'tcx>) -> EvalResult<'tcx, (Value, Ty<'tcx>)> where 'tcx: 'a; +} + +impl<'tcx> IntoValTyPair<'tcx> for (Value, Ty<'tcx>) { + fn into_val_ty_pair<'a>(self, _: &mut EvalContext<'a, 'tcx>) -> EvalResult<'tcx, (Value, Ty<'tcx>)> where 'tcx: 'a { + Ok(self) + } +} + +impl<'b, 'tcx: 'b> IntoValTyPair<'tcx> for &'b mir::Operand<'tcx> { + fn into_val_ty_pair<'a>(self, ecx: &mut EvalContext<'a, 'tcx>) -> EvalResult<'tcx, (Value, Ty<'tcx>)> where 'tcx: 'a { + let value = ecx.eval_operand(self)?; + let value_ty = ecx.operand_ty(self); + Ok((value, value_ty)) + } +} diff --git a/src/terminator/mod.rs b/src/terminator/mod.rs index 11082c633a7..bd1c85accd5 100644 --- a/src/terminator/mod.rs +++ b/src/terminator/mod.rs @@ -2,7 +2,7 @@ use rustc::mir; use rustc::traits::{self, Reveal}; use rustc::ty::fold::TypeFoldable; -use rustc::ty::layout::Layout; +use rustc::ty::layout::{Layout, Size}; use rustc::ty::subst::{Substs, Kind}; use rustc::ty::{self, Ty, TyCtxt, BareFnTy}; use syntax::codemap::{DUMMY_SP, Span}; @@ -238,20 +238,27 @@ fn eval_fn_call( let (lvalue, target) = destination.expect("tuple struct constructors can't diverge"); let dest_ty = self.tcx.item_type(adt_def.did); let dest_layout = self.type_layout(dest_ty)?; + let disr = v.disr_val.to_u128_unchecked(); match *dest_layout { Layout::Univariant { ref variant, .. } => { - assert_eq!(v.disr_val.to_u128_unchecked(), 0); + assert_eq!(disr, 0); let offsets = variant.offsets.iter().map(|s| s.bytes()); - // FIXME: don't allocate for single or dual field structs - let dest = self.force_allocation(lvalue)?.to_ptr(); - - for (offset, (value, value_ty)) in offsets.into_iter().zip(args) { - let field_dest = dest.offset(offset); - self.write_value_to_ptr(value, field_dest, value_ty)?; - } + self.assign_fields(lvalue, offsets, args)?; + }, + Layout::General { discr, ref variants, .. } => { + // FIXME: report a proper error for invalid discriminants + // right now we simply go into index out of bounds + let discr_size = discr.size().bytes(); + self.assign_discr_and_fields( + lvalue, + variants[disr as usize].offsets.iter().cloned().map(Size::bytes), + args, + disr, + discr_size, + )?; }, - // FIXME: enum variant constructors + // FIXME: raw nullable pointer constructors _ => bug!("bad layout for tuple struct constructor: {:?}", dest_layout), } self.goto_block(target); diff --git a/tests/run-pass/tuple_like_enum_variant_constructor.rs b/tests/run-pass/tuple_like_enum_variant_constructor.rs new file mode 100644 index 00000000000..5cf91b3f4d1 --- /dev/null +++ b/tests/run-pass/tuple_like_enum_variant_constructor.rs @@ -0,0 +1,3 @@ +fn main() { + assert_eq!(Some(42).map(Some), Some(Some(42))); +} -- GitLab