<commit_before>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! This file handles the relationships between free regions --
//! meaning lifetime parameters. Ordinarily, free regions are
//! unrelated to one another, but they can be related vai implied or
//! explicit bounds.  In that case, we track the bounds using the
//! `TransitiveRelation` type and use that to decide when one free
//! region outlives another and so forth.

use middle::ty::{self, FreeRegion, Region};
use middle::wf::ImpliedBound;
use rustc_data_structures::transitive_relation::TransitiveRelation;

#[derive(Clone)]
pub struct FreeRegionMap {
    // Stores the relation `a < b`, where `a` and `b` are regions.
    relation: TransitiveRelation<Region>
}

impl FreeRegionMap {
    pub fn new() -> FreeRegionMap {
        FreeRegionMap { relation: TransitiveRelation::new() }
    }

    pub fn relate_free_regions_from_implied_bounds<'tcx>(&mut self,
                                                        implied_bounds: &[ImpliedBound<'tcx>])
    {
        debug!("relate_free_regions_from_implied_bounds()");
        for implied_bound in implied_bounds {
            debug!("implied bound: {:?}", implied_bound);
            match *implied_bound {
                ImpliedBound::RegionSubRegion(ty::ReFree(free_a), ty::ReFree(free_b)) => {
                    self.relate_free_regions(free_a, free_b);
                }
                ImpliedBound::RegionSubRegion(..) |
                ImpliedBound::RegionSubParam(..) |
                ImpliedBound::RegionSubProjection(..) => {
                }
            }
        }
    }

    pub fn relate_free_regions_from_predicates<'tcx>(&mut self,
                                                     tcx: &ty::ctxt<'tcx>,
                                                     predicates: &[ty::Predicate<'tcx>]) {
        debug!("relate_free_regions_from_predicates(predicates={:?})", predicates);
        for predicate in predicates {
            match *predicate {
                ty::Predicate::Projection(..) |
                ty::Predicate::Trait(..) |
                ty::Predicate::Equate(..) |
                ty::Predicate::WellFormed(..) |
                ty::Predicate::ObjectSafe(..) |
                ty::Predicate::TypeOutlives(..) => {
                    // No region bounds here
                }
                ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => {
                    match (r_a, r_b) {
                        (ty::ReStatic, ty::ReFree(_)) => {},
                        (ty::ReFree(fr_a), ty::ReStatic) => self.relate_to_static(fr_a),
                        (ty::ReFree(fr_a), ty::ReFree(fr_b)) => {
                            // Record that `'a:'b`. Or, put another way, `'b <= 'a`.
                            self.relate_free_regions(fr_b, fr_a);
                        }
                        _ => {
                            // All named regions are instantiated with free regions.
                            tcx.sess.bug(
                                &format!("record_region_bounds: non free region: {:?} / {:?}",
                                         r_a,
                                         r_b));
                        }
                    }
                }
            }
        }
    }

    fn relate_to_static(&mut self, sup: FreeRegion) {
        self.relation.add(ty::ReStatic, ty::ReFree(sup));
    }

    fn relate_free_regions(&mut self, sub: FreeRegion, sup: FreeRegion) {
        self.relation.add(ty::ReFree(sub), ty::ReFree(sup))
    }

    /// Determines whether two free regions have a subregion relationship
    /// by walking the graph encoded in `map`.  Note that
    /// it is possible that `sub != sup` and `sub <= sup` and `sup <= sub`
    /// (that is, the user can give two different names to the same lifetime).
    pub fn sub_free_region(&self, sub: FreeRegion, sup: FreeRegion) -> bool {
        let result = sub == sup || {
            let sub = ty::ReFree(sub);
            let sup = ty::ReFree(sup);
            self.relation.contains(&sub, &sup) || self.relation.contains(&ty::ReStatic, &sup)
        };
        debug!("sub_free_region(sub={:?}, sup={:?}) = {:?}", sub, sup, result);
        result
    }

    pub fn lub_free_regions(&self, fr_a: FreeRegion, fr_b: FreeRegion) -> Region {
        let r_a = ty::ReFree(fr_a);
        let r_b = ty::ReFree(fr_b);
        let result = if fr_a == fr_b { r_a } else {
            match self.relation.postdom_upper_bound(&r_a, &r_b) {
                None => ty::ReStatic,
                Some(r) => *r,
            }
        };
        debug!("lub_free_regions(fr_a={:?}, fr_b={:?}) = {:?}", fr_a, fr_b, result);
        result
    }

    /// Determines whether one region is a subregion of another.  This is intended to run *after
    /// inference* and sadly the logic is somewhat duplicated with the code in infer.rs.
    pub fn is_subregion_of(&self,
                           tcx: &ty::ctxt,
                           sub_region: ty::Region,
                           super_region: ty::Region)
                           -> bool {
        let result = sub_region == super_region || {
            match (sub_region, super_region) {
                (ty::ReEmpty, _) |
                (_, ty::ReStatic) =>
                    true,

                (ty::ReScope(sub_scope), ty::ReScope(super_scope)) =>
                    tcx.region_maps.is_subscope_of(sub_scope, super_scope),

                (ty::ReScope(sub_scope), ty::ReFree(fr)) =>
                    tcx.region_maps.is_subscope_of(sub_scope, fr.scope) ||
                    self.is_static(fr),

                (ty::ReFree(sub_fr), ty::ReFree(super_fr)) =>
                    self.sub_free_region(sub_fr, super_fr),

                (ty::ReStatic, ty::ReFree(sup_fr)) =>
                    self.is_static(sup_fr),

                _ =>
                    false,
            }
        };
        debug!("is_subregion_of(sub_region={:?}, super_region={:?}) = {:?}",
               sub_region, super_region, result);
        result
    }

    /// Determines whether this free-region is required to be 'static
    pub fn is_static(&self, super_region: ty::FreeRegion) -> bool {
        debug!("is_static(super_region={:?})", super_region);
        self.relation.contains(&ty::ReStatic, &ty::ReFree(super_region))
    }
}

#[cfg(test)]
fn free_region(index: u32) -> FreeRegion {
    use middle::region::DestructionScopeData;
    FreeRegion { scope: DestructionScopeData::new(0),
                 bound_region: ty::BoundRegion::BrAnon(index) }
}

#[test]
fn lub() {
    // a very VERY basic test, but see the tests in
    // TransitiveRelation, which are much more thorough.
    let frs: Vec<_> = (0..3).map(|i| free_region(i)).collect();
    let mut map = FreeRegionMap::new();
    map.relate_free_regions(frs[0], frs[2]);
    map.relate_free_regions(frs[1], frs[2]);
    assert_eq!(map.lub_free_regions(frs[0], frs[1]), ty::ReFree(frs[2]));
}
<commit_msg>fix test<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! This file handles the relationships between free regions --
//! meaning lifetime parameters. Ordinarily, free regions are
//! unrelated to one another, but they can be related vai implied or
//! explicit bounds.  In that case, we track the bounds using the
//! `TransitiveRelation` type and use that to decide when one free
//! region outlives another and so forth.

use middle::ty::{self, FreeRegion, Region};
use middle::wf::ImpliedBound;
use rustc_data_structures::transitive_relation::TransitiveRelation;

#[derive(Clone)]
pub struct FreeRegionMap {
    // Stores the relation `a < b`, where `a` and `b` are regions.
    relation: TransitiveRelation<Region>
}

impl FreeRegionMap {
    pub fn new() -> FreeRegionMap {
        FreeRegionMap { relation: TransitiveRelation::new() }
    }

    pub fn relate_free_regions_from_implied_bounds<'tcx>(&mut self,
                                                        implied_bounds: &[ImpliedBound<'tcx>])
    {
        debug!("relate_free_regions_from_implied_bounds()");
        for implied_bound in implied_bounds {
            debug!("implied bound: {:?}", implied_bound);
            match *implied_bound {
                ImpliedBound::RegionSubRegion(ty::ReFree(free_a), ty::ReFree(free_b)) => {
                    self.relate_free_regions(free_a, free_b);
                }
                ImpliedBound::RegionSubRegion(..) |
                ImpliedBound::RegionSubParam(..) |
                ImpliedBound::RegionSubProjection(..) => {
                }
            }
        }
    }

    pub fn relate_free_regions_from_predicates<'tcx>(&mut self,
                                                     tcx: &ty::ctxt<'tcx>,
                                                     predicates: &[ty::Predicate<'tcx>]) {
        debug!("relate_free_regions_from_predicates(predicates={:?})", predicates);
        for predicate in predicates {
            match *predicate {
                ty::Predicate::Projection(..) |
                ty::Predicate::Trait(..) |
                ty::Predicate::Equate(..) |
                ty::Predicate::WellFormed(..) |
                ty::Predicate::ObjectSafe(..) |
                ty::Predicate::TypeOutlives(..) => {
                    // No region bounds here
                }
                ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => {
                    match (r_a, r_b) {
                        (ty::ReStatic, ty::ReFree(_)) => {},
                        (ty::ReFree(fr_a), ty::ReStatic) => self.relate_to_static(fr_a),
                        (ty::ReFree(fr_a), ty::ReFree(fr_b)) => {
                            // Record that `'a:'b`. Or, put another way, `'b <= 'a`.
                            self.relate_free_regions(fr_b, fr_a);
                        }
                        _ => {
                            // All named regions are instantiated with free regions.
                            tcx.sess.bug(
                                &format!("record_region_bounds: non free region: {:?} / {:?}",
                                         r_a,
                                         r_b));
                        }
                    }
                }
            }
        }
    }

    fn relate_to_static(&mut self, sup: FreeRegion) {
        self.relation.add(ty::ReStatic, ty::ReFree(sup));
    }

    fn relate_free_regions(&mut self, sub: FreeRegion, sup: FreeRegion) {
        self.relation.add(ty::ReFree(sub), ty::ReFree(sup))
    }

    /// Determines whether two free regions have a subregion relationship
    /// by walking the graph encoded in `map`.  Note that
    /// it is possible that `sub != sup` and `sub <= sup` and `sup <= sub`
    /// (that is, the user can give two different names to the same lifetime).
    pub fn sub_free_region(&self, sub: FreeRegion, sup: FreeRegion) -> bool {
        let result = sub == sup || {
            let sub = ty::ReFree(sub);
            let sup = ty::ReFree(sup);
            self.relation.contains(&sub, &sup) || self.relation.contains(&ty::ReStatic, &sup)
        };
        debug!("sub_free_region(sub={:?}, sup={:?}) = {:?}", sub, sup, result);
        result
    }

    pub fn lub_free_regions(&self, fr_a: FreeRegion, fr_b: FreeRegion) -> Region {
        let r_a = ty::ReFree(fr_a);
        let r_b = ty::ReFree(fr_b);
        let result = if fr_a == fr_b { r_a } else {
            match self.relation.postdom_upper_bound(&r_a, &r_b) {
                None => ty::ReStatic,
                Some(r) => *r,
            }
        };
        debug!("lub_free_regions(fr_a={:?}, fr_b={:?}) = {:?}", fr_a, fr_b, result);
        result
    }

    /// Determines whether one region is a subregion of another.  This is intended to run *after
    /// inference* and sadly the logic is somewhat duplicated with the code in infer.rs.
    pub fn is_subregion_of(&self,
                           tcx: &ty::ctxt,
                           sub_region: ty::Region,
                           super_region: ty::Region)
                           -> bool {
        let result = sub_region == super_region || {
            match (sub_region, super_region) {
                (ty::ReEmpty, _) |
                (_, ty::ReStatic) =>
                    true,

                (ty::ReScope(sub_scope), ty::ReScope(super_scope)) =>
                    tcx.region_maps.is_subscope_of(sub_scope, super_scope),

                (ty::ReScope(sub_scope), ty::ReFree(fr)) =>
                    tcx.region_maps.is_subscope_of(sub_scope, fr.scope) ||
                    self.is_static(fr),

                (ty::ReFree(sub_fr), ty::ReFree(super_fr)) =>
                    self.sub_free_region(sub_fr, super_fr),

                (ty::ReStatic, ty::ReFree(sup_fr)) =>
                    self.is_static(sup_fr),

                _ =>
                    false,
            }
        };
        debug!("is_subregion_of(sub_region={:?}, super_region={:?}) = {:?}",
               sub_region, super_region, result);
        result
    }

    /// Determines whether this free-region is required to be 'static
    pub fn is_static(&self, super_region: ty::FreeRegion) -> bool {
        debug!("is_static(super_region={:?})", super_region);
        self.relation.contains(&ty::ReStatic, &ty::ReFree(super_region))
    }
}

#[cfg(test)]
fn free_region(index: u32) -> FreeRegion {
    use middle::region::DUMMY_CODE_EXTENT;
    FreeRegion { scope: DUMMY_CODE_EXTENT,
                 bound_region: ty::BoundRegion::BrAnon(index) }
}

#[test]
fn lub() {
    // a very VERY basic test, but see the tests in
    // TransitiveRelation, which are much more thorough.
    let frs: Vec<_> = (0..3).map(|i| free_region(i)).collect();
    let mut map = FreeRegionMap::new();
    map.relate_free_regions(frs[0], frs[2]);
    map.relate_free_regions(frs[1], frs[2]);
    assert_eq!(map.lub_free_regions(frs[0], frs[1]), ty::ReFree(frs[2]));
}
<|endoftext|>


<commit_before>use rustc::ty::{self, Ty, TypeAndMut};
use rustc::ty::layout::{self, TyLayout, Size};
use rustc::ty::adjustment::{PointerCast};
use syntax::ast::{FloatTy, IntTy, UintTy};
use syntax::symbol::sym;

use rustc_apfloat::ieee::{Single, Double};
use rustc_apfloat::{Float, FloatConvert};
use rustc::mir::interpret::{
    Scalar, InterpResult, Pointer, PointerArithmetic, InterpError,
};
use rustc::mir::CastKind;

use super::{InterpretCx, Machine, PlaceTy, OpTy, Immediate};

impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, '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>,
        kind: CastKind,
        dest: PlaceTy<'tcx, M::PointerTag>,
    ) -> InterpResult<'tcx> {
        use rustc::mir::CastKind::*;
        match kind {
            Pointer(PointerCast::Unsize) => {
                self.unsize_into(src, dest)?;
            }

            Misc | Pointer(PointerCast::MutToConstPointer) => {
                let src = self.read_immediate(src)?;

                if self.type_is_fat_ptr(src.layout.ty) {
                    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
                            self.write_immediate(*src, dest)?;
                        }
                        // slices and trait objects to thin pointers (dropping the metadata)
                        (Immediate::ScalarPair(data, _), false) => {
                            self.write_scalar(data, dest)?;
                        }
                    }
                } 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 self.write_scalar(
                                    Scalar::from_uint(discr.val, dest.layout.size),
                                    dest);
                            }
                        }
                        layout::Variants::Multiple { .. } => {},
                    }

                    let dest_val = self.cast_scalar(src.to_scalar()?, src.layout, dest.layout)?;
                    self.write_scalar(dest_val, dest)?;
                }
            }

            Pointer(PointerCast::ReifyFnPointer) => {
                // The src operand does not matter, just its type
                match src.layout.ty.sty {
                    ty::FnDef(def_id, substs) => {
                        if self.tcx.has_attr(def_id, sym::rustc_args_required_const) {
                            bug!("reifying a fn ptr that requires const arguments");
                        }
                        let instance: InterpResult<'tcx, _> = ty::Instance::resolve(
                            *self.tcx,
                            self.param_env,
                            def_id,
                            substs,
                        ).ok_or_else(|| InterpError::TooGeneric.into());
                        let fn_ptr = self.memory.create_fn_alloc(instance?);
                        self.write_scalar(Scalar::Ptr(fn_ptr.into()), dest)?;
                    }
                    _ => bug!("reify fn pointer on {:?}", src.layout.ty),
                }
            }

            Pointer(PointerCast::UnsafeFnPointer) => {
                let src = self.read_immediate(src)?;
                match dest.layout.ty.sty {
                    ty::FnPtr(_) => {
                        // No change to value
                        self.write_immediate(*src, dest)?;
                    }
                    _ => bug!("fn to unsafe fn cast on {:?}", dest.layout.ty),
                }
            }

            Pointer(PointerCast::ClosureFnPointer(_)) => {
                // The src operand does not matter, just its type
                match src.layout.ty.sty {
                    ty::Closure(def_id, substs) => {
                        let substs = self.subst_and_normalize_erasing_regions(substs)?;
                        let instance = ty::Instance::resolve_closure(
                            *self.tcx,
                            def_id,
                            substs,
                            ty::ClosureKind::FnOnce,
                        );
                        let fn_ptr = self.memory.create_fn_alloc(instance);
                        let val = Immediate::Scalar(Scalar::Ptr(fn_ptr.into()).into());
                        self.write_immediate(val, dest)?;
                    }
                    _ => bug!("closure fn pointer on {:?}", src.layout.ty),
                }
            }
        }
        Ok(())
    }

    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);

        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
            _ => {
                assert!(
                    src_layout.ty.is_bool() || src_layout.ty.is_char() ||
                    src_layout.ty.is_integral()   || src_layout.ty.is_region_ptr() ||
                    src_layout.ty.is_unsafe_ptr() || src_layout.ty.is_fn_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, dest_layout.ty),
                    Ok(data) => self.cast_from_int(data, src_layout, dest_layout),
                }
            }
        }
    }

    fn cast_from_int(
        &self,
        v: u128, // raw bits
        src_layout: TyLayout<'tcx>,
        dest_layout: TyLayout<'tcx>,
    ) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
        // Let's make sure v is sign-extended *if* it has a signed type.
        let signed = src_layout.abi.is_signed();
        let v = if signed {
            self.sign_extend(v, src_layout)
        } else {
            v
        };
        trace!("cast_from_int: {}, {}, {}", v, src_layout.ty, dest_layout.ty);
        use rustc::ty::TyKind::*;
        match dest_layout.ty.sty {
            Int(_) | Uint(_) | RawPtr(_) => {
                let v = self.truncate(v, dest_layout);
                Ok(Scalar::from_uint(v, dest_layout.size))
            }

            Float(FloatTy::F32) if signed => Ok(Scalar::from_f32(
                Single::from_i128(v as i128).value
            )),
            Float(FloatTy::F64) if signed => Ok(Scalar::from_f64(
                Double::from_i128(v as i128).value
            )),
            Float(FloatTy::F32) => Ok(Scalar::from_f32(
                Single::from_u128(v).value
            )),
            Float(FloatTy::F64) => Ok(Scalar::from_f64(
                Double::from_u128(v).value
            )),

            Char => {
                // `u8` to `char` cast
                debug_assert_eq!(v as u8 as u128, v);
                Ok(Scalar::from_uint(v, Size::from_bytes(4)))
            },

            // Casts to bool are not permitted by rustc, no need to handle them here.
            _ => err!(Unimplemented(format!("int to {:?} cast", dest_layout.ty))),
        }
    }

    fn cast_from_float<F>(
        &self,
        f: F,
        dest_ty: Ty<'tcx>
    ) -> InterpResult<'tcx, Scalar<M::PointerTag>>
    where F: Float + Into<Scalar<M::PointerTag>> + FloatConvert<Single> + FloatConvert<Double>
    {
        use rustc::ty::TyKind::*;
        match dest_ty.sty {
            // float -> uint
            Uint(t) => {
                let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize);
                let v = f.to_u128(width).value;
                // This should already fit the bit width
                Ok(Scalar::from_uint(v, Size::from_bits(width as u64)))
            },
            // float -> int
            Int(t) => {
                let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize);
                let v = f.to_i128(width).value;
                Ok(Scalar::from_int(v, Size::from_bits(width as u64)))
            },
            // float -> f32
            Float(FloatTy::F32) =>
                Ok(Scalar::from_f32(f.convert(&mut false).value)),
            // float -> f64
            Float(FloatTy::F64) =>
                Ok(Scalar::from_f64(f.convert(&mut false).value)),
            // That's it.
            _ => bug!("invalid float to {:?} cast", dest_ty),
        }
    }

    fn cast_from_ptr(
        &self,
        ptr: Pointer<M::PointerTag>,
        ty: Ty<'tcx>
    ) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
        use rustc::ty::TyKind::*;
        match ty.sty {
            // Casting to a reference or fn pointer is not permitted by rustc,
            // no need to support it here.
            RawPtr(_) |
            Int(IntTy::Isize) |
            Uint(UintTy::Usize) => Ok(ptr.into()),
            Int(_) | Uint(_) => err!(ReadPointerAsBytes),
            _ => err!(Unimplemented(format!("ptr to {:?} cast", ty))),
        }
    }

    fn unsize_into_ptr(
        &mut self,
        src: OpTy<'tcx, M::PointerTag>,
        dest: PlaceTy<'tcx, M::PointerTag>,
        // The pointee types
        sty: Ty<'tcx>,
        dty: Ty<'tcx>,
    ) -> InterpResult<'tcx> {
        // A<Struct> -> A<Trait> conversion
        let (src_pointee_ty, dest_pointee_ty) = self.tcx.struct_lockstep_tails(sty, dty);

        match (&src_pointee_ty.sty, &dest_pointee_ty.sty) {
            (&ty::Array(_, length), &ty::Slice(_)) => {
                let ptr = self.read_immediate(src)?.to_scalar_ptr()?;
                // u64 cast is from usize to u64, which is always good
                let val = Immediate::new_slice(
                    ptr,
                    length.unwrap_usize(self.tcx.tcx),
                    self,
                );
                self.write_immediate(val, dest)
            }
            (&ty::Dynamic(..), &ty::Dynamic(..)) => {
                // For now, upcasts are limited to changes in marker
                // traits, and hence never actually require an actual
                // change to the vtable.
                let val = self.read_immediate(src)?;
                self.write_immediate(*val, dest)
            }
            (_, &ty::Dynamic(ref data, _)) => {
                // Initial cast from sized to dyn trait
                let vtable = self.get_vtable(src_pointee_ty, data.principal())?;
                let ptr = self.read_immediate(src)?.to_scalar_ptr()?;
                let val = Immediate::new_dyn_trait(ptr, vtable);
                self.write_immediate(val, dest)
            }

            _ => bug!("invalid unsizing {:?} -> {:?}", src.layout.ty, dest.layout.ty),
        }
    }

    fn unsize_into(
        &mut self,
        src: OpTy<'tcx, M::PointerTag>,
        dest: PlaceTy<'tcx, M::PointerTag>,
    ) -> InterpResult<'tcx> {
        trace!("Unsizing {:?} into {:?}", src, dest);
        match (&src.layout.ty.sty, &dest.layout.ty.sty) {
            (&ty::Ref(_, s, _), &ty::Ref(_, d, _)) |
            (&ty::Ref(_, s, _), &ty::RawPtr(TypeAndMut { ty: d, .. })) |
            (&ty::RawPtr(TypeAndMut { ty: s, .. }),
             &ty::RawPtr(TypeAndMut { ty: d, .. })) => {
                self.unsize_into_ptr(src, dest, s, d)
            }
            (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
                assert_eq!(def_a, def_b);
                if def_a.is_box() || def_b.is_box() {
                    if !def_a.is_box() || !def_b.is_box() {
                        bug!("invalid unsizing between {:?} -> {:?}", src.layout, dest.layout);
                    }
                    return self.unsize_into_ptr(
                        src,
                        dest,
                        src.layout.ty.boxed_ty(),
                        dest.layout.ty.boxed_ty(),
                    );
                }

                // unsizing of generic struct with pointer fields
                // Example: `Arc<T>` -> `Arc<Trait>`
                // here we need to increase the size of every &T thin ptr field to a fat ptr
                for i in 0..src.layout.fields.count() {
                    let dst_field = self.place_field(dest, i as u64)?;
                    if dst_field.layout.is_zst() {
                        continue;
                    }
                    let src_field = self.operand_field(src, i as u64)?;
                    if src_field.layout.ty == dst_field.layout.ty {
                        self.copy_op(src_field, dst_field)?;
                    } else {
                        self.unsize_into(src_field, dst_field)?;
                    }
                }
                Ok(())
            }
            _ => {
                bug!(
                    "unsize_into: invalid conversion: {:?} -> {:?}",
                    src.layout,
                    dest.layout
                )
            }
        }
    }
}
<commit_msg>forgot about multivariant enum casts<commit_after>use rustc::ty::{self, Ty, TypeAndMut};
use rustc::ty::layout::{self, TyLayout, Size};
use rustc::ty::adjustment::{PointerCast};
use syntax::ast::{FloatTy, IntTy, UintTy};
use syntax::symbol::sym;

use rustc_apfloat::ieee::{Single, Double};
use rustc_apfloat::{Float, FloatConvert};
use rustc::mir::interpret::{
    Scalar, InterpResult, Pointer, PointerArithmetic, InterpError,
};
use rustc::mir::CastKind;

use super::{InterpretCx, Machine, PlaceTy, OpTy, Immediate};

impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, '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>,
        kind: CastKind,
        dest: PlaceTy<'tcx, M::PointerTag>,
    ) -> InterpResult<'tcx> {
        use rustc::mir::CastKind::*;
        match kind {
            Pointer(PointerCast::Unsize) => {
                self.unsize_into(src, dest)?;
            }

            Misc | Pointer(PointerCast::MutToConstPointer) => {
                let src = self.read_immediate(src)?;

                if self.type_is_fat_ptr(src.layout.ty) {
                    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
                            self.write_immediate(*src, dest)?;
                        }
                        // slices and trait objects to thin pointers (dropping the metadata)
                        (Immediate::ScalarPair(data, _), false) => {
                            self.write_scalar(data, dest)?;
                        }
                    }
                } 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 self.write_scalar(
                                    Scalar::from_uint(discr.val, dest.layout.size),
                                    dest);
                            }
                        }
                        layout::Variants::Multiple { .. } => {},
                    }

                    let dest_val = self.cast_scalar(src.to_scalar()?, src.layout, dest.layout)?;
                    self.write_scalar(dest_val, dest)?;
                }
            }

            Pointer(PointerCast::ReifyFnPointer) => {
                // The src operand does not matter, just its type
                match src.layout.ty.sty {
                    ty::FnDef(def_id, substs) => {
                        if self.tcx.has_attr(def_id, sym::rustc_args_required_const) {
                            bug!("reifying a fn ptr that requires const arguments");
                        }
                        let instance: InterpResult<'tcx, _> = ty::Instance::resolve(
                            *self.tcx,
                            self.param_env,
                            def_id,
                            substs,
                        ).ok_or_else(|| InterpError::TooGeneric.into());
                        let fn_ptr = self.memory.create_fn_alloc(instance?);
                        self.write_scalar(Scalar::Ptr(fn_ptr.into()), dest)?;
                    }
                    _ => bug!("reify fn pointer on {:?}", src.layout.ty),
                }
            }

            Pointer(PointerCast::UnsafeFnPointer) => {
                let src = self.read_immediate(src)?;
                match dest.layout.ty.sty {
                    ty::FnPtr(_) => {
                        // No change to value
                        self.write_immediate(*src, dest)?;
                    }
                    _ => bug!("fn to unsafe fn cast on {:?}", dest.layout.ty),
                }
            }

            Pointer(PointerCast::ClosureFnPointer(_)) => {
                // The src operand does not matter, just its type
                match src.layout.ty.sty {
                    ty::Closure(def_id, substs) => {
                        let substs = self.subst_and_normalize_erasing_regions(substs)?;
                        let instance = ty::Instance::resolve_closure(
                            *self.tcx,
                            def_id,
                            substs,
                            ty::ClosureKind::FnOnce,
                        );
                        let fn_ptr = self.memory.create_fn_alloc(instance);
                        let val = Immediate::Scalar(Scalar::Ptr(fn_ptr.into()).into());
                        self.write_immediate(val, dest)?;
                    }
                    _ => bug!("closure fn pointer on {:?}", src.layout.ty),
                }
            }
        }
        Ok(())
    }

    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);

        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).
            _ => {
                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, dest_layout.ty),
                    Ok(data) => self.cast_from_int(data, src_layout, dest_layout),
                }
            }
        }
    }

    fn cast_from_int(
        &self,
        v: u128, // raw bits
        src_layout: TyLayout<'tcx>,
        dest_layout: TyLayout<'tcx>,
    ) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
        // Let's make sure v is sign-extended *if* it has a signed type.
        let signed = src_layout.abi.is_signed();
        let v = if signed {
            self.sign_extend(v, src_layout)
        } else {
            v
        };
        trace!("cast_from_int: {}, {}, {}", v, src_layout.ty, dest_layout.ty);
        use rustc::ty::TyKind::*;
        match dest_layout.ty.sty {
            Int(_) | Uint(_) | RawPtr(_) => {
                let v = self.truncate(v, dest_layout);
                Ok(Scalar::from_uint(v, dest_layout.size))
            }

            Float(FloatTy::F32) if signed => Ok(Scalar::from_f32(
                Single::from_i128(v as i128).value
            )),
            Float(FloatTy::F64) if signed => Ok(Scalar::from_f64(
                Double::from_i128(v as i128).value
            )),
            Float(FloatTy::F32) => Ok(Scalar::from_f32(
                Single::from_u128(v).value
            )),
            Float(FloatTy::F64) => Ok(Scalar::from_f64(
                Double::from_u128(v).value
            )),

            Char => {
                // `u8` to `char` cast
                debug_assert_eq!(v as u8 as u128, v);
                Ok(Scalar::from_uint(v, Size::from_bytes(4)))
            },

            // Casts to bool are not permitted by rustc, no need to handle them here.
            _ => err!(Unimplemented(format!("int to {:?} cast", dest_layout.ty))),
        }
    }

    fn cast_from_float<F>(
        &self,
        f: F,
        dest_ty: Ty<'tcx>
    ) -> InterpResult<'tcx, Scalar<M::PointerTag>>
    where F: Float + Into<Scalar<M::PointerTag>> + FloatConvert<Single> + FloatConvert<Double>
    {
        use rustc::ty::TyKind::*;
        match dest_ty.sty {
            // float -> uint
            Uint(t) => {
                let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize);
                let v = f.to_u128(width).value;
                // This should already fit the bit width
                Ok(Scalar::from_uint(v, Size::from_bits(width as u64)))
            },
            // float -> int
            Int(t) => {
                let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize);
                let v = f.to_i128(width).value;
                Ok(Scalar::from_int(v, Size::from_bits(width as u64)))
            },
            // float -> f32
            Float(FloatTy::F32) =>
                Ok(Scalar::from_f32(f.convert(&mut false).value)),
            // float -> f64
            Float(FloatTy::F64) =>
                Ok(Scalar::from_f64(f.convert(&mut false).value)),
            // That's it.
            _ => bug!("invalid float to {:?} cast", dest_ty),
        }
    }

    fn cast_from_ptr(
        &self,
        ptr: Pointer<M::PointerTag>,
        ty: Ty<'tcx>
    ) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
        use rustc::ty::TyKind::*;
        match ty.sty {
            // Casting to a reference or fn pointer is not permitted by rustc,
            // no need to support it here.
            RawPtr(_) |
            Int(IntTy::Isize) |
            Uint(UintTy::Usize) => Ok(ptr.into()),
            Int(_) | Uint(_) => err!(ReadPointerAsBytes),
            _ => err!(Unimplemented(format!("ptr to {:?} cast", ty))),
        }
    }

    fn unsize_into_ptr(
        &mut self,
        src: OpTy<'tcx, M::PointerTag>,
        dest: PlaceTy<'tcx, M::PointerTag>,
        // The pointee types
        sty: Ty<'tcx>,
        dty: Ty<'tcx>,
    ) -> InterpResult<'tcx> {
        // A<Struct> -> A<Trait> conversion
        let (src_pointee_ty, dest_pointee_ty) = self.tcx.struct_lockstep_tails(sty, dty);

        match (&src_pointee_ty.sty, &dest_pointee_ty.sty) {
            (&ty::Array(_, length), &ty::Slice(_)) => {
                let ptr = self.read_immediate(src)?.to_scalar_ptr()?;
                // u64 cast is from usize to u64, which is always good
                let val = Immediate::new_slice(
                    ptr,
                    length.unwrap_usize(self.tcx.tcx),
                    self,
                );
                self.write_immediate(val, dest)
            }
            (&ty::Dynamic(..), &ty::Dynamic(..)) => {
                // For now, upcasts are limited to changes in marker
                // traits, and hence never actually require an actual
                // change to the vtable.
                let val = self.read_immediate(src)?;
                self.write_immediate(*val, dest)
            }
            (_, &ty::Dynamic(ref data, _)) => {
                // Initial cast from sized to dyn trait
                let vtable = self.get_vtable(src_pointee_ty, data.principal())?;
                let ptr = self.read_immediate(src)?.to_scalar_ptr()?;
                let val = Immediate::new_dyn_trait(ptr, vtable);
                self.write_immediate(val, dest)
            }

            _ => bug!("invalid unsizing {:?} -> {:?}", src.layout.ty, dest.layout.ty),
        }
    }

    fn unsize_into(
        &mut self,
        src: OpTy<'tcx, M::PointerTag>,
        dest: PlaceTy<'tcx, M::PointerTag>,
    ) -> InterpResult<'tcx> {
        trace!("Unsizing {:?} into {:?}", src, dest);
        match (&src.layout.ty.sty, &dest.layout.ty.sty) {
            (&ty::Ref(_, s, _), &ty::Ref(_, d, _)) |
            (&ty::Ref(_, s, _), &ty::RawPtr(TypeAndMut { ty: d, .. })) |
            (&ty::RawPtr(TypeAndMut { ty: s, .. }),
             &ty::RawPtr(TypeAndMut { ty: d, .. })) => {
                self.unsize_into_ptr(src, dest, s, d)
            }
            (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
                assert_eq!(def_a, def_b);
                if def_a.is_box() || def_b.is_box() {
                    if !def_a.is_box() || !def_b.is_box() {
                        bug!("invalid unsizing between {:?} -> {:?}", src.layout, dest.layout);
                    }
                    return self.unsize_into_ptr(
                        src,
                        dest,
                        src.layout.ty.boxed_ty(),
                        dest.layout.ty.boxed_ty(),
                    );
                }

                // unsizing of generic struct with pointer fields
                // Example: `Arc<T>` -> `Arc<Trait>`
                // here we need to increase the size of every &T thin ptr field to a fat ptr
                for i in 0..src.layout.fields.count() {
                    let dst_field = self.place_field(dest, i as u64)?;
                    if dst_field.layout.is_zst() {
                        continue;
                    }
                    let src_field = self.operand_field(src, i as u64)?;
                    if src_field.layout.ty == dst_field.layout.ty {
                        self.copy_op(src_field, dst_field)?;
                    } else {
                        self.unsize_into(src_field, dst_field)?;
                    }
                }
                Ok(())
            }
            _ => {
                bug!(
                    "unsize_into: invalid conversion: {:?} -> {:?}",
                    src.layout,
                    dest.layout
                )
            }
        }
    }
}
<|endoftext|>


<commit_before>use rustc::ty::{self, Ty, TypeAndMut};
use rustc::ty::layout::{self, TyLayout, Size};
use rustc::ty::adjustment::{PointerCast};
use syntax::ast::FloatTy;
use syntax::symbol::sym;

use rustc_apfloat::ieee::{Single, Double};
use rustc_apfloat::{Float, FloatConvert};
use rustc::mir::interpret::{
    Scalar, InterpResult, PointerArithmetic,
};
use rustc::mir::CastKind;

use super::{InterpCx, Machine, PlaceTy, OpTy, ImmTy, Immediate, FnVal};

impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
    pub fn cast(
        &mut self,
        src: OpTy<'tcx, M::PointerTag>,
        kind: CastKind,
        dest: PlaceTy<'tcx, M::PointerTag>,
    ) -> InterpResult<'tcx> {
        use rustc::mir::CastKind::*;
        match kind {
            Pointer(PointerCast::Unsize) => {
                self.unsize_into(src, dest)?;
            }

            Misc | Pointer(PointerCast::MutToConstPointer) => {
                let src = self.read_immediate(src)?;
                let res = self.cast_immediate(src, dest.layout)?;
                self.write_immediate(res, dest)?;
            }

            Pointer(PointerCast::ReifyFnPointer) => {
                // The src operand does not matter, just its type
                match src.layout.ty.sty {
                    ty::FnDef(def_id, substs) => {
                        if self.tcx.has_attr(def_id, sym::rustc_args_required_const) {
                            bug!("reifying a fn ptr that requires const arguments");
                        }
                        let instance = self.resolve(def_id, substs)?;
                        let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
                        self.write_scalar(Scalar::Ptr(fn_ptr.into()), dest)?;
                    }
                    _ => bug!("reify fn pointer on {:?}", src.layout.ty),
                }
            }

            Pointer(PointerCast::UnsafeFnPointer) => {
                let src = self.read_immediate(src)?;
                match dest.layout.ty.sty {
                    ty::FnPtr(_) => {
                        // No change to value
                        self.write_immediate(*src, dest)?;
                    }
                    _ => bug!("fn to unsafe fn cast on {:?}", dest.layout.ty),
                }
            }

            Pointer(PointerCast::ClosureFnPointer(_)) => {
                // The src operand does not matter, just its type
                match src.layout.ty.sty {
                    ty::Closure(def_id, substs) => {
                        let instance = ty::Instance::resolve_closure(
                            *self.tcx,
                            def_id,
                            substs,
                            ty::ClosureKind::FnOnce,
                        );
                        let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
                        let val = Immediate::Scalar(Scalar::Ptr(fn_ptr.into()).into());
                        self.write_immediate(val, dest)?;
                    }
                    _ => bug!("closure fn pointer on {:?}", src.layout.ty),
                }
            }
        }
        Ok(())
    }

    fn cast_immediate(
        &self,
        src: ImmTy<'tcx, M::PointerTag>,
        dest_layout: TyLayout<'tcx>,
    ) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
        use rustc::ty::TyKind::*;
        trace!("Casting {:?}: {:?} to {:?}", *src, src.layout.ty, dest_layout.ty);

        match src.layout.ty.sty {
            // Floating point
            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_any_ptr(),
                    "Unexpected cast from type {:?}", src.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 casting the metadata away from a fat pointer.
        if src.layout.ty.is_unsafe_ptr() && dest_layout.ty.is_unsafe_ptr() &&
            dest_layout.size != src.layout.size
        {
            assert_eq!(src.layout.size, 2*self.memory.pointer_size());
            assert_eq!(dest_layout.size, self.memory.pointer_size());
            assert!(dest_layout.ty.is_unsafe_ptr());
            match *src {
                Immediate::ScalarPair(data, _) =>
                    return Ok(data.into()),
                Immediate::Scalar(..) =>
                    bug!(
                        "{:?} input to a fat-to-thin cast ({:?} -> {:?})",
                        *src, src.layout.ty, dest_layout.ty
                    ),
            };
        }

        // Handle casting any ptr to raw ptr (might be a fat ptr).
        if src.layout.ty.is_any_ptr() && dest_layout.ty.is_unsafe_ptr()
        {
            // The only possible size-unequal case was handled above.
            assert_eq!(src.layout.size, dest_layout.size);
            return Ok(*src);
        }

        // For all remaining casts, we either
        // (a) cast a raw ptr to usize, or
        // (b) cast from an integer-like (including bool, char, enums).
        // In both cases we want the bits.
        let bits = self.force_bits(src.to_scalar()?, src.layout.size)?;
        Ok(self.cast_from_int(bits, src.layout, dest_layout)?.into())
    }

    fn cast_from_int(
        &self,
        v: u128, // raw bits
        src_layout: TyLayout<'tcx>,
        dest_layout: TyLayout<'tcx>,
    ) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
        // Let's make sure v is sign-extended *if* it has a signed type.
        let signed = src_layout.abi.is_signed();
        let v = if signed {
            self.sign_extend(v, src_layout)
        } else {
            v
        };
        trace!("cast_from_int: {}, {}, {}", v, src_layout.ty, dest_layout.ty);
        use rustc::ty::TyKind::*;
        match dest_layout.ty.sty {
            Int(_) | Uint(_) | RawPtr(_) => {
                let v = self.truncate(v, dest_layout);
                Ok(Scalar::from_uint(v, dest_layout.size))
            }

            Float(FloatTy::F32) if signed => Ok(Scalar::from_f32(
                Single::from_i128(v as i128).value
            )),
            Float(FloatTy::F64) if signed => Ok(Scalar::from_f64(
                Double::from_i128(v as i128).value
            )),
            Float(FloatTy::F32) => Ok(Scalar::from_f32(
                Single::from_u128(v).value
            )),
            Float(FloatTy::F64) => Ok(Scalar::from_f64(
                Double::from_u128(v).value
            )),

            Char => {
                // `u8` to `char` cast
                debug_assert_eq!(v as u8 as u128, v);
                Ok(Scalar::from_uint(v, Size::from_bytes(4)))
            },

            // Casts to bool are not permitted by rustc, no need to handle them here.
            _ => bug!("invalid int to {:?} cast", dest_layout.ty),
        }
    }

    fn cast_from_float<F>(
        &self,
        f: F,
        dest_ty: Ty<'tcx>
    ) -> InterpResult<'tcx, Scalar<M::PointerTag>>
    where F: Float + Into<Scalar<M::PointerTag>> + FloatConvert<Single> + FloatConvert<Double>
    {
        use rustc::ty::TyKind::*;
        match dest_ty.sty {
            // float -> uint
            Uint(t) => {
                let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize);
                let v = f.to_u128(width).value;
                // This should already fit the bit width
                Ok(Scalar::from_uint(v, Size::from_bits(width as u64)))
            },
            // float -> int
            Int(t) => {
                let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize);
                let v = f.to_i128(width).value;
                Ok(Scalar::from_int(v, Size::from_bits(width as u64)))
            },
            // float -> f32
            Float(FloatTy::F32) =>
                Ok(Scalar::from_f32(f.convert(&mut false).value)),
            // float -> f64
            Float(FloatTy::F64) =>
                Ok(Scalar::from_f64(f.convert(&mut false).value)),
            // That's it.
            _ => bug!("invalid float to {:?} cast", dest_ty),
        }
    }

    fn unsize_into_ptr(
        &mut self,
        src: OpTy<'tcx, M::PointerTag>,
        dest: PlaceTy<'tcx, M::PointerTag>,
        // The pointee types
        sty: Ty<'tcx>,
        dty: Ty<'tcx>,
    ) -> InterpResult<'tcx> {
        // A<Struct> -> A<Trait> conversion
        let (src_pointee_ty, dest_pointee_ty) =
            self.tcx.struct_lockstep_tails_erasing_lifetimes(sty, dty, self.param_env);

        match (&src_pointee_ty.sty, &dest_pointee_ty.sty) {
            (&ty::Array(_, length), &ty::Slice(_)) => {
                let ptr = self.read_immediate(src)?.to_scalar_ptr()?;
                // u64 cast is from usize to u64, which is always good
                let val = Immediate::new_slice(
                    ptr,
                    length.eval_usize(self.tcx.tcx, self.param_env),
                    self,
                );
                self.write_immediate(val, dest)
            }
            (&ty::Dynamic(..), &ty::Dynamic(..)) => {
                // For now, upcasts are limited to changes in marker
                // traits, and hence never actually require an actual
                // change to the vtable.
                let val = self.read_immediate(src)?;
                self.write_immediate(*val, dest)
            }
            (_, &ty::Dynamic(ref data, _)) => {
                // Initial cast from sized to dyn trait
                let vtable = self.get_vtable(src_pointee_ty, data.principal())?;
                let ptr = self.read_immediate(src)?.to_scalar_ptr()?;
                let val = Immediate::new_dyn_trait(ptr, vtable);
                self.write_immediate(val, dest)
            }

            _ => bug!("invalid unsizing {:?} -> {:?}", src.layout.ty, dest.layout.ty),
        }
    }

    fn unsize_into(
        &mut self,
        src: OpTy<'tcx, M::PointerTag>,
        dest: PlaceTy<'tcx, M::PointerTag>,
    ) -> InterpResult<'tcx> {
        trace!("Unsizing {:?} into {:?}", src, dest);
        match (&src.layout.ty.sty, &dest.layout.ty.sty) {
            (&ty::Ref(_, s, _), &ty::Ref(_, d, _)) |
            (&ty::Ref(_, s, _), &ty::RawPtr(TypeAndMut { ty: d, .. })) |
            (&ty::RawPtr(TypeAndMut { ty: s, .. }),
             &ty::RawPtr(TypeAndMut { ty: d, .. })) => {
                self.unsize_into_ptr(src, dest, s, d)
            }
            (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
                assert_eq!(def_a, def_b);
                if def_a.is_box() || def_b.is_box() {
                    if !def_a.is_box() || !def_b.is_box() {
                        bug!("invalid unsizing between {:?} -> {:?}", src.layout, dest.layout);
                    }
                    return self.unsize_into_ptr(
                        src,
                        dest,
                        src.layout.ty.boxed_ty(),
                        dest.layout.ty.boxed_ty(),
                    );
                }

                // unsizing of generic struct with pointer fields
                // Example: `Arc<T>` -> `Arc<Trait>`
                // here we need to increase the size of every &T thin ptr field to a fat ptr
                for i in 0..src.layout.fields.count() {
                    let dst_field = self.place_field(dest, i as u64)?;
                    if dst_field.layout.is_zst() {
                        continue;
                    }
                    let src_field = self.operand_field(src, i as u64)?;
                    if src_field.layout.ty == dst_field.layout.ty {
                        self.copy_op(src_field, dst_field)?;
                    } else {
                        self.unsize_into(src_field, dst_field)?;
                    }
                }
                Ok(())
            }
            _ => {
                bug!(
                    "unsize_into: invalid conversion: {:?} -> {:?}",
                    src.layout,
                    dest.layout
                )
            }
        }
    }
}
<commit_msg>rustc_mir: disallow non-monomorphic reifications.<commit_after>use rustc::ty::{self, Ty, TypeAndMut, TypeFoldable};
use rustc::ty::layout::{self, TyLayout, Size};
use rustc::ty::adjustment::{PointerCast};
use syntax::ast::FloatTy;
use syntax::symbol::sym;

use rustc_apfloat::ieee::{Single, Double};
use rustc_apfloat::{Float, FloatConvert};
use rustc::mir::interpret::{
    Scalar, InterpResult, PointerArithmetic,
};
use rustc::mir::CastKind;

use super::{InterpCx, Machine, PlaceTy, OpTy, ImmTy, Immediate, FnVal};

impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
    pub fn cast(
        &mut self,
        src: OpTy<'tcx, M::PointerTag>,
        kind: CastKind,
        dest: PlaceTy<'tcx, M::PointerTag>,
    ) -> InterpResult<'tcx> {
        use rustc::mir::CastKind::*;
        match kind {
            Pointer(PointerCast::Unsize) => {
                self.unsize_into(src, dest)?;
            }

            Misc | Pointer(PointerCast::MutToConstPointer) => {
                let src = self.read_immediate(src)?;
                let res = self.cast_immediate(src, dest.layout)?;
                self.write_immediate(res, dest)?;
            }

            Pointer(PointerCast::ReifyFnPointer) => {
                // The src operand does not matter, just its type
                match src.layout.ty.sty {
                    ty::FnDef(def_id, substs) => {
                        // All reifications must be monomorphic, bail out otherwise.
                        if src.layout.ty.needs_subst() {
                            throw_inval!(TooGeneric);
                        }

                        if self.tcx.has_attr(def_id, sym::rustc_args_required_const) {
                            bug!("reifying a fn ptr that requires const arguments");
                        }
                        let instance = self.resolve(def_id, substs)?;
                        let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
                        self.write_scalar(Scalar::Ptr(fn_ptr.into()), dest)?;
                    }
                    _ => bug!("reify fn pointer on {:?}", src.layout.ty),
                }
            }

            Pointer(PointerCast::UnsafeFnPointer) => {
                let src = self.read_immediate(src)?;
                match dest.layout.ty.sty {
                    ty::FnPtr(_) => {
                        // No change to value
                        self.write_immediate(*src, dest)?;
                    }
                    _ => bug!("fn to unsafe fn cast on {:?}", dest.layout.ty),
                }
            }

            Pointer(PointerCast::ClosureFnPointer(_)) => {
                // The src operand does not matter, just its type
                match src.layout.ty.sty {
                    ty::Closure(def_id, substs) => {
                        // All reifications must be monomorphic, bail out otherwise.
                        if src.layout.ty.needs_subst() {
                            throw_inval!(TooGeneric);
                        }

                        let instance = ty::Instance::resolve_closure(
                            *self.tcx,
                            def_id,
                            substs,
                            ty::ClosureKind::FnOnce,
                        );
                        let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
                        let val = Immediate::Scalar(Scalar::Ptr(fn_ptr.into()).into());
                        self.write_immediate(val, dest)?;
                    }
                    _ => bug!("closure fn pointer on {:?}", src.layout.ty),
                }
            }
        }
        Ok(())
    }

    fn cast_immediate(
        &self,
        src: ImmTy<'tcx, M::PointerTag>,
        dest_layout: TyLayout<'tcx>,
    ) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
        use rustc::ty::TyKind::*;
        trace!("Casting {:?}: {:?} to {:?}", *src, src.layout.ty, dest_layout.ty);

        match src.layout.ty.sty {
            // Floating point
            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_any_ptr(),
                    "Unexpected cast from type {:?}", src.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 casting the metadata away from a fat pointer.
        if src.layout.ty.is_unsafe_ptr() && dest_layout.ty.is_unsafe_ptr() &&
            dest_layout.size != src.layout.size
        {
            assert_eq!(src.layout.size, 2*self.memory.pointer_size());
            assert_eq!(dest_layout.size, self.memory.pointer_size());
            assert!(dest_layout.ty.is_unsafe_ptr());
            match *src {
                Immediate::ScalarPair(data, _) =>
                    return Ok(data.into()),
                Immediate::Scalar(..) =>
                    bug!(
                        "{:?} input to a fat-to-thin cast ({:?} -> {:?})",
                        *src, src.layout.ty, dest_layout.ty
                    ),
            };
        }

        // Handle casting any ptr to raw ptr (might be a fat ptr).
        if src.layout.ty.is_any_ptr() && dest_layout.ty.is_unsafe_ptr()
        {
            // The only possible size-unequal case was handled above.
            assert_eq!(src.layout.size, dest_layout.size);
            return Ok(*src);
        }

        // For all remaining casts, we either
        // (a) cast a raw ptr to usize, or
        // (b) cast from an integer-like (including bool, char, enums).
        // In both cases we want the bits.
        let bits = self.force_bits(src.to_scalar()?, src.layout.size)?;
        Ok(self.cast_from_int(bits, src.layout, dest_layout)?.into())
    }

    fn cast_from_int(
        &self,
        v: u128, // raw bits
        src_layout: TyLayout<'tcx>,
        dest_layout: TyLayout<'tcx>,
    ) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
        // Let's make sure v is sign-extended *if* it has a signed type.
        let signed = src_layout.abi.is_signed();
        let v = if signed {
            self.sign_extend(v, src_layout)
        } else {
            v
        };
        trace!("cast_from_int: {}, {}, {}", v, src_layout.ty, dest_layout.ty);
        use rustc::ty::TyKind::*;
        match dest_layout.ty.sty {
            Int(_) | Uint(_) | RawPtr(_) => {
                let v = self.truncate(v, dest_layout);
                Ok(Scalar::from_uint(v, dest_layout.size))
            }

            Float(FloatTy::F32) if signed => Ok(Scalar::from_f32(
                Single::from_i128(v as i128).value
            )),
            Float(FloatTy::F64) if signed => Ok(Scalar::from_f64(
                Double::from_i128(v as i128).value
            )),
            Float(FloatTy::F32) => Ok(Scalar::from_f32(
                Single::from_u128(v).value
            )),
            Float(FloatTy::F64) => Ok(Scalar::from_f64(
                Double::from_u128(v).value
            )),

            Char => {
                // `u8` to `char` cast
                debug_assert_eq!(v as u8 as u128, v);
                Ok(Scalar::from_uint(v, Size::from_bytes(4)))
            },

            // Casts to bool are not permitted by rustc, no need to handle them here.
            _ => bug!("invalid int to {:?} cast", dest_layout.ty),
        }
    }

    fn cast_from_float<F>(
        &self,
        f: F,
        dest_ty: Ty<'tcx>
    ) -> InterpResult<'tcx, Scalar<M::PointerTag>>
    where F: Float + Into<Scalar<M::PointerTag>> + FloatConvert<Single> + FloatConvert<Double>
    {
        use rustc::ty::TyKind::*;
        match dest_ty.sty {
            // float -> uint
            Uint(t) => {
                let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize);
                let v = f.to_u128(width).value;
                // This should already fit the bit width
                Ok(Scalar::from_uint(v, Size::from_bits(width as u64)))
            },
            // float -> int
            Int(t) => {
                let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize);
                let v = f.to_i128(width).value;
                Ok(Scalar::from_int(v, Size::from_bits(width as u64)))
            },
            // float -> f32
            Float(FloatTy::F32) =>
                Ok(Scalar::from_f32(f.convert(&mut false).value)),
            // float -> f64
            Float(FloatTy::F64) =>
                Ok(Scalar::from_f64(f.convert(&mut false).value)),
            // That's it.
            _ => bug!("invalid float to {:?} cast", dest_ty),
        }
    }

    fn unsize_into_ptr(
        &mut self,
        src: OpTy<'tcx, M::PointerTag>,
        dest: PlaceTy<'tcx, M::PointerTag>,
        // The pointee types
        sty: Ty<'tcx>,
        dty: Ty<'tcx>,
    ) -> InterpResult<'tcx> {
        // A<Struct> -> A<Trait> conversion
        let (src_pointee_ty, dest_pointee_ty) =
            self.tcx.struct_lockstep_tails_erasing_lifetimes(sty, dty, self.param_env);

        match (&src_pointee_ty.sty, &dest_pointee_ty.sty) {
            (&ty::Array(_, length), &ty::Slice(_)) => {
                let ptr = self.read_immediate(src)?.to_scalar_ptr()?;
                // u64 cast is from usize to u64, which is always good
                let val = Immediate::new_slice(
                    ptr,
                    length.eval_usize(self.tcx.tcx, self.param_env),
                    self,
                );
                self.write_immediate(val, dest)
            }
            (&ty::Dynamic(..), &ty::Dynamic(..)) => {
                // For now, upcasts are limited to changes in marker
                // traits, and hence never actually require an actual
                // change to the vtable.
                let val = self.read_immediate(src)?;
                self.write_immediate(*val, dest)
            }
            (_, &ty::Dynamic(ref data, _)) => {
                // Initial cast from sized to dyn trait
                let vtable = self.get_vtable(src_pointee_ty, data.principal())?;
                let ptr = self.read_immediate(src)?.to_scalar_ptr()?;
                let val = Immediate::new_dyn_trait(ptr, vtable);
                self.write_immediate(val, dest)
            }

            _ => bug!("invalid unsizing {:?} -> {:?}", src.layout.ty, dest.layout.ty),
        }
    }

    fn unsize_into(
        &mut self,
        src: OpTy<'tcx, M::PointerTag>,
        dest: PlaceTy<'tcx, M::PointerTag>,
    ) -> InterpResult<'tcx> {
        trace!("Unsizing {:?} into {:?}", src, dest);
        match (&src.layout.ty.sty, &dest.layout.ty.sty) {
            (&ty::Ref(_, s, _), &ty::Ref(_, d, _)) |
            (&ty::Ref(_, s, _), &ty::RawPtr(TypeAndMut { ty: d, .. })) |
            (&ty::RawPtr(TypeAndMut { ty: s, .. }),
             &ty::RawPtr(TypeAndMut { ty: d, .. })) => {
                self.unsize_into_ptr(src, dest, s, d)
            }
            (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
                assert_eq!(def_a, def_b);
                if def_a.is_box() || def_b.is_box() {
                    if !def_a.is_box() || !def_b.is_box() {
                        bug!("invalid unsizing between {:?} -> {:?}", src.layout, dest.layout);
                    }
                    return self.unsize_into_ptr(
                        src,
                        dest,
                        src.layout.ty.boxed_ty(),
                        dest.layout.ty.boxed_ty(),
                    );
                }

                // unsizing of generic struct with pointer fields
                // Example: `Arc<T>` -> `Arc<Trait>`
                // here we need to increase the size of every &T thin ptr field to a fat ptr
                for i in 0..src.layout.fields.count() {
                    let dst_field = self.place_field(dest, i as u64)?;
                    if dst_field.layout.is_zst() {
                        continue;
                    }
                    let src_field = self.operand_field(src, i as u64)?;
                    if src_field.layout.ty == dst_field.layout.ty {
                        self.copy_op(src_field, dst_field)?;
                    } else {
                        self.unsize_into(src_field, dst_field)?;
                    }
                }
                Ok(())
            }
            _ => {
                bug!(
                    "unsize_into: invalid conversion: {:?} -> {:?}",
                    src.layout,
                    dest.layout
                )
            }
        }
    }
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

extern crate glutin;
extern crate cgmath;
extern crate serialize;

use cgmath::{Vector2, Vector3};
use core_types::{Size2, ZInt, MapPos};
use visualizer_types::{ZFloat, Color3, Color4, ColorId, MatId, WorldPos, ScreenPos, VertexCoord};
use zgl::{Zgl, Mesh};
use camera::Camera;
use shader::{Shader};
use geom;
use core_map::{MapPosIter};

static VS_SRC: &'static str = "\
    #version 100\n\
    uniform mat4 mvp_mat;\n\
    attribute vec2 position;\n\
    void main() {\n\
        gl_Position = mvp_mat * vec4(position, 0.0, 1.0);\n\
    }\n\
";

static FS_SRC: &'static str = "\
    #version 100\n\
    precision mediump float;
    uniform vec4 col;\n\
    void main() {\n\
        gl_FragColor = col;\n\
    }\n\
";

fn get_win_size(window: &glutin::Window) -> Size2<ZInt> {
    let (w, h) = window.get_inner_size().expect("Can`t get window size");
    Size2{w: w as ZInt, h: h as ZInt}
}

fn get_max_camera_pos(map_size: &Size2<ZInt>) -> WorldPos {
    let pos = geom::map_pos_to_world_pos(
        MapPos{v: Vector2{x: map_size.w, y: map_size.h}});
    WorldPos{v: Vector3{x: -pos.v.x, y: -pos.v.y, z: 0.0}}
}

fn generate_mesh(map_size: &Size2<ZInt>, zgl: &Zgl) -> Mesh {
    let mut vertex_data = Vec::new();
    for tile_pos in MapPosIter::new(map_size) {
        let pos = geom::map_pos_to_world_pos(tile_pos);
        // TODO: range(0, 6) -> some dir iterator
        for num in range(0i32, 6) {
            let vertex = geom::index_to_hex_vertex(num);
            let next_vertex = geom::index_to_hex_vertex(num + 1);
            vertex_data.push(VertexCoord{v: pos.v + vertex.v});
            vertex_data.push(VertexCoord{v: pos.v + next_vertex.v});
            vertex_data.push(VertexCoord{v: pos.v});
        }
    }
    Mesh::new(zgl, vertex_data.as_slice())
}

pub struct Visualizer {
    zgl: Zgl,
    window: glutin::Window,
    should_close: bool,
    color_counter: i32, // TODO: remove
    test_color: Color4,
    shader: Shader,
    color_uniform_location: ColorId,
    mvp_uniform_location: MatId,
    camera: Camera,
    mouse_pos: ScreenPos,
    is_lmb_pressed: bool,
    win_size: Size2<ZInt>,
    mesh: Mesh,
}

impl Visualizer {
    pub fn new() -> Visualizer {
        let window_builder = glutin::WindowBuilder::new().with_gl_version((2, 0));
        let window = window_builder.build().ok().expect("Can`t create window");
        unsafe {
            window.make_current();
        };
        let win_size = get_win_size(&window);
        let mut zgl = Zgl::new(|s| window.get_proc_address(s));
        zgl.print_gl_info();
        let shader = Shader::new(&zgl, VS_SRC, FS_SRC);
        let color_uniform_location = shader.get_uniform_color(&zgl, "col");
        let mvp_uniform_location = shader.get_uniform_mat(&zgl, "mvp_mat");
        zgl.set_clear_color(Color3{r: 0.0, g: 0.0, b: 0.4});
        let mut camera = Camera::new(&win_size);
        let map_size = Size2{w: 5, h: 2};
        camera.set_max_pos(get_max_camera_pos(&map_size));
        let mesh = generate_mesh(&map_size, &zgl);
        Visualizer {
            zgl: zgl,
            window: window,
            should_close: false,
            color_counter: 0,
            test_color: Color4{r: 0.0, g: 0.0, b: 0.0, a: 0.0},
            shader: shader,
            color_uniform_location: color_uniform_location,
            mvp_uniform_location: mvp_uniform_location,
            camera: camera,
            mouse_pos: ScreenPos{v: Vector2::from_value(0)},
            is_lmb_pressed: false,
            win_size: win_size,
            mesh: mesh,
        }
    }

    pub fn is_running(&self) -> bool {
        !self.should_close
    }

    fn handle_event(&mut self, event: &glutin::Event) {
        match *event {
            glutin::Event::Closed => {
                self.should_close = true;
            },
            glutin::Event::Resized(w, h) => {
                self.win_size = Size2{w: w as ZInt, h: h as ZInt};
                self.zgl.set_viewport(&self.win_size);
            },
            glutin::Event::MouseMoved((x, y)) => {
                let new_pos = ScreenPos{v: Vector2{x: x as ZInt, y: y as ZInt}};
                if self.is_lmb_pressed {
                    let diff = new_pos.v - self.mouse_pos.v;
                    let win_w = self.win_size.w as ZFloat;
                    let win_h = self.win_size.h as ZFloat;
                    self.camera.add_z_angle(diff.x as ZFloat * (360.0 / win_w));
                    self.camera.add_x_angle(diff.y as ZFloat * (360.0 / win_h));
                }
                self.mouse_pos = new_pos;
            },
            glutin::Event::MouseInput(
                glutin::ElementState::Pressed,
                glutin::MouseButton::LeftMouseButton,
            ) => {
                self.is_lmb_pressed = true;
            },
            glutin::Event::MouseInput(
                glutin::ElementState::Released,
                glutin::MouseButton::LeftMouseButton,
            ) => {
                self.is_lmb_pressed = false;
                let (r, g, b, a) = self.zgl.read_pixel_bytes(
                    &self.win_size, &self.mouse_pos);
                println!("r: {}, g: {}, b: {}, a: {}", r, g, b, a);
            },
            glutin::Event::KeyboardInput(_, _, Some(key)) => match key {
                glutin::VirtualKeyCode::Q | glutin::VirtualKeyCode::Escape => {
                    self.should_close = true;
                },
                glutin::VirtualKeyCode::W => self.camera.move_camera(270.0, 0.1),
                glutin::VirtualKeyCode::S => self.camera.move_camera(90.0, 0.1),
                glutin::VirtualKeyCode::D => self.camera.move_camera(0.0, 0.1),
                glutin::VirtualKeyCode::A => self.camera.move_camera(180.0, 0.1),
                glutin::VirtualKeyCode::Minus => self.camera.change_zoom(1.3),
                glutin::VirtualKeyCode::Equals => self.camera.change_zoom(0.7),
                _ => {},
            },
            _ => {},
        }
    }

    fn handle_events(&mut self) {
        let events = self.window.poll_events().collect::<Vec<_>>();
        if events.is_empty() {
            return;
        }
        // println!("{}", events);
        for event in events.iter() {
            self.handle_event(event);
        }
    }

    fn update_test_color(&mut self) {
        self.test_color = match self.color_counter {
            0 => Color4{r: 1.0, g: 0.0, b: 0.0, a: 1.0},
            30 => Color4{r: 0.0, g: 1.0, b: 0.0, a: 1.0},
            60 => Color4{r: 0.0, g: 0.0, b: 1.0, a: 1.0},
            _ => self.test_color.clone(),
        };
        self.color_counter += 1;
        if self.color_counter > 90 {
            self.color_counter = -1;
        }
    }

    fn draw(&mut self) {
        self.zgl.clear_screen();
        self.shader.activate(&self.zgl);
        self.shader.set_uniform_color(
            &self.zgl, &self.color_uniform_location, &self.test_color);
        self.shader.set_uniform_mat4f(
            &self.zgl, &self.mvp_uniform_location, &self.camera.mat(&self.zgl));
        self.mesh.draw(&self.zgl);
        self.window.swap_buffers();
    }

    pub fn tick(&mut self) {
        self.handle_events();
        // self.logic();
        self.update_test_color();
        self.draw();
        // self.update_time();
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>src/visualizer.rs: Fixed get_max_camera_pos: h - 1<commit_after>// See LICENSE file for copyright and license details.

extern crate glutin;
extern crate cgmath;
extern crate serialize;

use cgmath::{Vector2, Vector3};
use core_types::{Size2, ZInt, MapPos};
use visualizer_types::{ZFloat, Color3, Color4, ColorId, MatId, WorldPos, ScreenPos, VertexCoord};
use zgl::{Zgl, Mesh};
use camera::Camera;
use shader::{Shader};
use geom;
use core_map::{MapPosIter};

static VS_SRC: &'static str = "\
    #version 100\n\
    uniform mat4 mvp_mat;\n\
    attribute vec2 position;\n\
    void main() {\n\
        gl_Position = mvp_mat * vec4(position, 0.0, 1.0);\n\
    }\n\
";

static FS_SRC: &'static str = "\
    #version 100\n\
    precision mediump float;
    uniform vec4 col;\n\
    void main() {\n\
        gl_FragColor = col;\n\
    }\n\
";

fn get_win_size(window: &glutin::Window) -> Size2<ZInt> {
    let (w, h) = window.get_inner_size().expect("Can`t get window size");
    Size2{w: w as ZInt, h: h as ZInt}
}

fn get_max_camera_pos(map_size: &Size2<ZInt>) -> WorldPos {
    let pos = geom::map_pos_to_world_pos(
        MapPos{v: Vector2{x: map_size.w, y: map_size.h - 1}});
    WorldPos{v: Vector3{x: -pos.v.x, y: -pos.v.y, z: 0.0}}
}

fn generate_mesh(map_size: &Size2<ZInt>, zgl: &Zgl) -> Mesh {
    let mut vertex_data = Vec::new();
    for tile_pos in MapPosIter::new(map_size) {
        let pos = geom::map_pos_to_world_pos(tile_pos);
        // TODO: range(0, 6) -> some dir iterator
        for num in range(0i32, 6) {
            let vertex = geom::index_to_hex_vertex(num);
            let next_vertex = geom::index_to_hex_vertex(num + 1);
            vertex_data.push(VertexCoord{v: pos.v + vertex.v});
            vertex_data.push(VertexCoord{v: pos.v + next_vertex.v});
            vertex_data.push(VertexCoord{v: pos.v});
        }
    }
    Mesh::new(zgl, vertex_data.as_slice())
}

pub struct Visualizer {
    zgl: Zgl,
    window: glutin::Window,
    should_close: bool,
    color_counter: i32, // TODO: remove
    test_color: Color4,
    shader: Shader,
    color_uniform_location: ColorId,
    mvp_uniform_location: MatId,
    camera: Camera,
    mouse_pos: ScreenPos,
    is_lmb_pressed: bool,
    win_size: Size2<ZInt>,
    mesh: Mesh,
}

impl Visualizer {
    pub fn new() -> Visualizer {
        let window_builder = glutin::WindowBuilder::new().with_gl_version((2, 0));
        let window = window_builder.build().ok().expect("Can`t create window");
        unsafe {
            window.make_current();
        };
        let win_size = get_win_size(&window);
        let mut zgl = Zgl::new(|s| window.get_proc_address(s));
        zgl.print_gl_info();
        let shader = Shader::new(&zgl, VS_SRC, FS_SRC);
        let color_uniform_location = shader.get_uniform_color(&zgl, "col");
        let mvp_uniform_location = shader.get_uniform_mat(&zgl, "mvp_mat");
        zgl.set_clear_color(Color3{r: 0.0, g: 0.0, b: 0.4});
        let mut camera = Camera::new(&win_size);
        let map_size = Size2{w: 5, h: 2};
        camera.set_max_pos(get_max_camera_pos(&map_size));
        let mesh = generate_mesh(&map_size, &zgl);
        Visualizer {
            zgl: zgl,
            window: window,
            should_close: false,
            color_counter: 0,
            test_color: Color4{r: 0.0, g: 0.0, b: 0.0, a: 0.0},
            shader: shader,
            color_uniform_location: color_uniform_location,
            mvp_uniform_location: mvp_uniform_location,
            camera: camera,
            mouse_pos: ScreenPos{v: Vector2::from_value(0)},
            is_lmb_pressed: false,
            win_size: win_size,
            mesh: mesh,
        }
    }

    pub fn is_running(&self) -> bool {
        !self.should_close
    }

    fn handle_event(&mut self, event: &glutin::Event) {
        match *event {
            glutin::Event::Closed => {
                self.should_close = true;
            },
            glutin::Event::Resized(w, h) => {
                self.win_size = Size2{w: w as ZInt, h: h as ZInt};
                self.zgl.set_viewport(&self.win_size);
            },
            glutin::Event::MouseMoved((x, y)) => {
                let new_pos = ScreenPos{v: Vector2{x: x as ZInt, y: y as ZInt}};
                if self.is_lmb_pressed {
                    let diff = new_pos.v - self.mouse_pos.v;
                    let win_w = self.win_size.w as ZFloat;
                    let win_h = self.win_size.h as ZFloat;
                    self.camera.add_z_angle(diff.x as ZFloat * (360.0 / win_w));
                    self.camera.add_x_angle(diff.y as ZFloat * (360.0 / win_h));
                }
                self.mouse_pos = new_pos;
            },
            glutin::Event::MouseInput(
                glutin::ElementState::Pressed,
                glutin::MouseButton::LeftMouseButton,
            ) => {
                self.is_lmb_pressed = true;
            },
            glutin::Event::MouseInput(
                glutin::ElementState::Released,
                glutin::MouseButton::LeftMouseButton,
            ) => {
                self.is_lmb_pressed = false;
                let (r, g, b, a) = self.zgl.read_pixel_bytes(
                    &self.win_size, &self.mouse_pos);
                println!("r: {}, g: {}, b: {}, a: {}", r, g, b, a);
            },
            glutin::Event::KeyboardInput(_, _, Some(key)) => match key {
                glutin::VirtualKeyCode::Q | glutin::VirtualKeyCode::Escape => {
                    self.should_close = true;
                },
                glutin::VirtualKeyCode::W => self.camera.move_camera(270.0, 0.1),
                glutin::VirtualKeyCode::S => self.camera.move_camera(90.0, 0.1),
                glutin::VirtualKeyCode::D => self.camera.move_camera(0.0, 0.1),
                glutin::VirtualKeyCode::A => self.camera.move_camera(180.0, 0.1),
                glutin::VirtualKeyCode::Minus => self.camera.change_zoom(1.3),
                glutin::VirtualKeyCode::Equals => self.camera.change_zoom(0.7),
                _ => {},
            },
            _ => {},
        }
    }

    fn handle_events(&mut self) {
        let events = self.window.poll_events().collect::<Vec<_>>();
        if events.is_empty() {
            return;
        }
        // println!("{}", events);
        for event in events.iter() {
            self.handle_event(event);
        }
    }

    fn update_test_color(&mut self) {
        self.test_color = match self.color_counter {
            0 => Color4{r: 1.0, g: 0.0, b: 0.0, a: 1.0},
            30 => Color4{r: 0.0, g: 1.0, b: 0.0, a: 1.0},
            60 => Color4{r: 0.0, g: 0.0, b: 1.0, a: 1.0},
            _ => self.test_color.clone(),
        };
        self.color_counter += 1;
        if self.color_counter > 90 {
            self.color_counter = -1;
        }
    }

    fn draw(&mut self) {
        self.zgl.clear_screen();
        self.shader.activate(&self.zgl);
        self.shader.set_uniform_color(
            &self.zgl, &self.color_uniform_location, &self.test_color);
        self.shader.set_uniform_mat4f(
            &self.zgl, &self.mvp_uniform_location, &self.camera.mat(&self.zgl));
        self.mesh.draw(&self.zgl);
        self.window.swap_buffers();
    }

    pub fn tick(&mut self) {
        self.handle_events();
        // self.logic();
        self.update_test_color();
        self.draw();
        // self.update_time();
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>


<commit_before>use crate::syntax::{ExternFn, Ref, Signature, Ty1, Type};
use std::hash::{Hash, Hasher};
use std::mem;
use std::ops::Deref;

impl Deref for ExternFn {
    type Target = Signature;

    fn deref(&self) -> &Self::Target {
        &self.sig
    }
}

impl Hash for Type {
    fn hash<H: Hasher>(&self, state: &mut H) {
        mem::discriminant(self).hash(state);
        match self {
            Type::Ident(t) => t.hash(state),
            Type::RustBox(t) => t.hash(state),
            Type::UniquePtr(t) => t.hash(state),
            Type::Ref(t) => t.hash(state),
            Type::Str(t) => t.hash(state),
            Type::Void(_) => {}
        }
    }
}

impl Eq for Type {}

impl PartialEq for Type {
    fn eq(&self, other: &Type) -> bool {
        match (self, other) {
            (Type::Ident(lhs), Type::Ident(rhs)) => lhs == rhs,
            (Type::RustBox(lhs), Type::RustBox(rhs)) => lhs == rhs,
            (Type::UniquePtr(lhs), Type::UniquePtr(rhs)) => lhs == rhs,
            (Type::Ref(lhs), Type::Ref(rhs)) => lhs == rhs,
            (Type::Str(lhs), Type::Str(rhs)) => lhs == rhs,
            (Type::Void(_), Type::Void(_)) => true,
            (_, _) => false,
        }
    }
}

impl Eq for Ty1 {}

impl PartialEq for Ty1 {
    fn eq(&self, other: &Ty1) -> bool {
        self.name == other.name && self.inner == other.inner
    }
}

impl Hash for Ty1 {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.name.hash(state);
        self.inner.hash(state);
    }
}

impl Eq for Ref {}

impl PartialEq for Ref {
    fn eq(&self, other: &Ref) -> bool {
        self.inner == other.inner
    }
}

impl Hash for Ref {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.inner.hash(state);
    }
}
<commit_msg>Prevent forgetting fields in PartialEq and Hash impls<commit_after>use crate::syntax::{ExternFn, Ref, Signature, Ty1, Type};
use std::hash::{Hash, Hasher};
use std::mem;
use std::ops::Deref;

impl Deref for ExternFn {
    type Target = Signature;

    fn deref(&self) -> &Self::Target {
        &self.sig
    }
}

impl Hash for Type {
    fn hash<H: Hasher>(&self, state: &mut H) {
        mem::discriminant(self).hash(state);
        match self {
            Type::Ident(t) => t.hash(state),
            Type::RustBox(t) => t.hash(state),
            Type::UniquePtr(t) => t.hash(state),
            Type::Ref(t) => t.hash(state),
            Type::Str(t) => t.hash(state),
            Type::Void(_) => {}
        }
    }
}

impl Eq for Type {}

impl PartialEq for Type {
    fn eq(&self, other: &Type) -> bool {
        match (self, other) {
            (Type::Ident(lhs), Type::Ident(rhs)) => lhs == rhs,
            (Type::RustBox(lhs), Type::RustBox(rhs)) => lhs == rhs,
            (Type::UniquePtr(lhs), Type::UniquePtr(rhs)) => lhs == rhs,
            (Type::Ref(lhs), Type::Ref(rhs)) => lhs == rhs,
            (Type::Str(lhs), Type::Str(rhs)) => lhs == rhs,
            (Type::Void(_), Type::Void(_)) => true,
            (_, _) => false,
        }
    }
}

impl Eq for Ty1 {}

impl PartialEq for Ty1 {
    fn eq(&self, other: &Ty1) -> bool {
        let Ty1 {
            name,
            langle: _,
            inner,
            rangle: _,
        } = self;
        let Ty1 {
            name: name2,
            langle: _,
            inner: inner2,
            rangle: _,
        } = other;
        name == name2 && inner == inner2
    }
}

impl Hash for Ty1 {
    fn hash<H: Hasher>(&self, state: &mut H) {
        let Ty1 {
            name,
            langle: _,
            inner,
            rangle: _,
        } = self;
        name.hash(state);
        inner.hash(state);
    }
}

impl Eq for Ref {}

impl PartialEq for Ref {
    fn eq(&self, other: &Ref) -> bool {
        let Ref {
            ampersand: _,
            mutability,
            inner,
        } = self;
        let Ref {
            ampersand: _,
            mutability: mutability2,
            inner: inner2,
        } = other;
        mutability.is_some() == mutability2.is_some() && inner == inner2
    }
}

impl Hash for Ref {
    fn hash<H: Hasher>(&self, state: &mut H) {
        let Ref {
            ampersand: _,
            mutability,
            inner,
        } = self;
        mutability.is_some().hash(state);
        inner.hash(state);
    }
}
<|endoftext|>