refactor cast_immediate to dispatch on the type first, and on the value second
This commit is contained in:
parent
ec1e71895a
commit
b318bcfa78
@ -14,15 +14,6 @@
|
||||
use super::{InterpCx, Machine, PlaceTy, OpTy, ImmTy, Immediate, FnVal};
|
||||
|
||||
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
fn type_is_fat_ptr(&self, ty: Ty<'tcx>) -> bool {
|
||||
match ty.sty {
|
||||
ty::RawPtr(ty::TypeAndMut { ty, .. }) |
|
||||
ty::Ref(_, ty, _) => !self.type_is_sized(ty),
|
||||
ty::Adt(def, _) if def.is_box() => !self.type_is_sized(ty.boxed_ty()),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cast(
|
||||
&mut self,
|
||||
src: OpTy<'tcx, M::PointerTag>,
|
||||
@ -99,68 +90,59 @@ fn cast_immediate(
|
||||
src: ImmTy<'tcx, M::PointerTag>,
|
||||
dest_layout: TyLayout<'tcx>,
|
||||
) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
|
||||
if self.type_is_fat_ptr(src.layout.ty) {
|
||||
return match (*src, self.type_is_fat_ptr(dest_layout.ty)) {
|
||||
// pointers to extern types
|
||||
(Immediate::Scalar(_),_) |
|
||||
// slices and trait objects to other slices/trait objects
|
||||
(Immediate::ScalarPair(..), true) => {
|
||||
// No change to immediate
|
||||
Ok(*src)
|
||||
}
|
||||
// slices and trait objects to thin pointers (dropping the metadata)
|
||||
(Immediate::ScalarPair(data, _), false) => {
|
||||
Ok(data.into())
|
||||
}
|
||||
};
|
||||
} else {
|
||||
match src.layout.variants {
|
||||
layout::Variants::Single { index } => {
|
||||
if let Some(discr) =
|
||||
src.layout.ty.discriminant_for_variant(*self.tcx, index)
|
||||
{
|
||||
// Cast from a univariant enum
|
||||
assert!(src.layout.is_zst());
|
||||
return Ok(Scalar::from_uint(discr.val, dest_layout.size).into());
|
||||
}
|
||||
}
|
||||
layout::Variants::Multiple { .. } => {},
|
||||
}
|
||||
|
||||
return Ok(self.cast_scalar(src.to_scalar()?, src.layout, dest_layout)?.into());
|
||||
}
|
||||
}
|
||||
|
||||
fn cast_scalar(
|
||||
&self,
|
||||
val: Scalar<M::PointerTag>,
|
||||
src_layout: TyLayout<'tcx>,
|
||||
dest_layout: TyLayout<'tcx>,
|
||||
) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
|
||||
use rustc::ty::TyKind::*;
|
||||
trace!("Casting {:?}: {:?} to {:?}", val, src_layout.ty, dest_layout.ty);
|
||||
trace!("Casting {:?}: {:?} to {:?}", *src, src.layout.ty, dest_layout.ty);
|
||||
|
||||
match src_layout.ty.sty {
|
||||
match src.layout.ty.sty {
|
||||
// Floating point
|
||||
Float(FloatTy::F32) => self.cast_from_float(val.to_f32()?, dest_layout.ty),
|
||||
Float(FloatTy::F64) => self.cast_from_float(val.to_f64()?, dest_layout.ty),
|
||||
// Integer(-like), including fn ptr casts and casts from enums that
|
||||
// are represented as integers (this excludes univariant enums, which
|
||||
// are handled in `cast` directly).
|
||||
_ => {
|
||||
Float(FloatTy::F32) =>
|
||||
return Ok(self.cast_from_float(src.to_scalar()?.to_f32()?, dest_layout.ty)?.into()),
|
||||
Float(FloatTy::F64) =>
|
||||
return Ok(self.cast_from_float(src.to_scalar()?.to_f64()?, dest_layout.ty)?.into()),
|
||||
// The rest is integer/pointer-"like", including fn ptr casts and casts from enums that
|
||||
// are represented as integers.
|
||||
_ =>
|
||||
assert!(
|
||||
src_layout.ty.is_bool() || src_layout.ty.is_char() ||
|
||||
src_layout.ty.is_enum() || src_layout.ty.is_integral() ||
|
||||
src_layout.ty.is_unsafe_ptr() || src_layout.ty.is_fn_ptr() ||
|
||||
src_layout.ty.is_region_ptr(),
|
||||
"Unexpected cast from type {:?}", src_layout.ty
|
||||
);
|
||||
match val.to_bits_or_ptr(src_layout.size, self) {
|
||||
Err(ptr) => self.cast_from_ptr(ptr, src_layout, dest_layout),
|
||||
Ok(data) => self.cast_from_int(data, src_layout, dest_layout),
|
||||
src.layout.ty.is_bool() || src.layout.ty.is_char() ||
|
||||
src.layout.ty.is_enum() || src.layout.ty.is_integral() ||
|
||||
src.layout.ty.is_unsafe_ptr() || src.layout.ty.is_fn_ptr() ||
|
||||
src.layout.ty.is_region_ptr(),
|
||||
"Unexpected cast from type {:?}", src.layout.ty
|
||||
)
|
||||
}
|
||||
|
||||
// Handle cast the metadata away from a fat pointer.
|
||||
if dest_layout.size != src.layout.size {
|
||||
assert_eq!(dest_layout.size, self.memory.pointer_size());
|
||||
return match *src {
|
||||
Immediate::ScalarPair(data, _) => Ok(data.into()),
|
||||
Immediate::Scalar(..) =>
|
||||
bug!(
|
||||
"{:?} input to a fat-to-thin cast ({:?} -> {:?})",
|
||||
*src, src.layout.ty, dest_layout.ty
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
// Handle cast from a univariant (ZST) enum
|
||||
match src.layout.variants {
|
||||
layout::Variants::Single { index } => {
|
||||
if let Some(discr) =
|
||||
src.layout.ty.discriminant_for_variant(*self.tcx, index)
|
||||
{
|
||||
assert!(src.layout.is_zst());
|
||||
return Ok(Scalar::from_uint(discr.val, dest_layout.size).into());
|
||||
}
|
||||
}
|
||||
layout::Variants::Multiple { .. } => {},
|
||||
}
|
||||
|
||||
// Handle all the rest.
|
||||
let val = src.to_scalar()?;
|
||||
Ok(match val.to_bits_or_ptr(src.layout.size, self) {
|
||||
Err(ptr) => self.cast_from_ptr(ptr, src.layout, dest_layout)?,
|
||||
Ok(data) => self.cast_from_int(data, src.layout, dest_layout)?,
|
||||
}.into())
|
||||
}
|
||||
|
||||
fn cast_from_int(
|
||||
|
Loading…
Reference in New Issue
Block a user