allow using tuple variant names as function handles
This commit is contained in:
parent
684f757139
commit
04eadedb28
@ -355,18 +355,44 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn assign_fields<I: IntoIterator<Item = u64>>(
|
||||
pub fn assign_discr_and_fields<
|
||||
I: IntoIterator<Item = u64>,
|
||||
V: IntoValTyPair<'tcx>,
|
||||
J: IntoIterator<Item = V>,
|
||||
>(
|
||||
&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<Item = u64>,
|
||||
V: IntoValTyPair<'tcx>,
|
||||
J: IntoIterator<Item = V>,
|
||||
>(
|
||||
&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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use rustc::hir::def_id::DefId;
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
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)?;
|
||||
},
|
||||
// FIXME: enum variant constructors
|
||||
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: raw nullable pointer constructors
|
||||
_ => bug!("bad layout for tuple struct constructor: {:?}", dest_layout),
|
||||
}
|
||||
self.goto_block(target);
|
||||
|
3
tests/run-pass/tuple_like_enum_variant_constructor.rs
Normal file
3
tests/run-pass/tuple_like_enum_variant_constructor.rs
Normal file
@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
assert_eq!(Some(42).map(Some), Some(Some(42)));
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user