1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use crate::ty;
use crate::ty::Ty;

use rustc_hir::HirId;
use rustc_target::abi::VariantIdx;

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
pub enum PlaceBase {
    /// A temporary variable
    Rvalue,
    /// A named `static` item
    StaticItem,
    /// A named local variable
    Local(HirId),
    /// An upvar referenced by closure env
    Upvar(ty::UpvarId),
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
pub enum ProjectionKind {
    /// A dereference of a pointer, reference or `Box<T>` of the given type
    Deref,

    /// `B.F` where `B` is the base expression and `F` is
    /// the field. The field is identified by which variant
    /// it appears in along with a field index. The variant
    /// is used for enums.
    Field(u32, VariantIdx),

    /// Some index like `B[x]`, where `B` is the base
    /// expression. We don't preserve the index `x` because
    /// we won't need it.
    Index,

    /// A subslice covering a range of values like `B[x..y]`.
    Subslice,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
pub struct Projection<'tcx> {
    /// Type after the projection is being applied.
    pub ty: Ty<'tcx>,

    /// Defines the type of access
    pub kind: ProjectionKind,
}

/// A `Place` represents how a value is located in memory.
///
/// This is an HIR version of `mir::Place`
#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
pub struct Place<'tcx> {
    /// The type of the `PlaceBase`
    pub base_ty: Ty<'tcx>,
    /// The "outermost" place that holds this value.
    pub base: PlaceBase,
    /// How this place is derived from the base place.
    pub projections: Vec<Projection<'tcx>>,
}

/// A `PlaceWithHirId` represents how a value is located in memory.
///
/// This is an HIR version of `mir::Place`
#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
pub struct PlaceWithHirId<'tcx> {
    /// `HirId` of the expression or pattern producing this value.
    pub hir_id: HirId,

    /// Information about the `Place`
    pub place: Place<'tcx>,
}

impl<'tcx> PlaceWithHirId<'tcx> {
    pub fn new(
        hir_id: HirId,
        base_ty: Ty<'tcx>,
        base: PlaceBase,
        projections: Vec<Projection<'tcx>>,
    ) -> PlaceWithHirId<'tcx> {
        PlaceWithHirId {
            hir_id: hir_id,
            place: Place { base_ty: base_ty, base: base, projections: projections },
        }
    }
}

impl<'tcx> Place<'tcx> {
    /// Returns an iterator of the types that have to be dereferenced to access
    /// the `Place`.
    ///
    /// The types are in the reverse order that they are applied. So if
    /// `x: &*const u32` and the `Place` is `**x`, then the types returned are
    ///`*const u32` then `&*const u32`.
    pub fn deref_tys(&self) -> impl Iterator<Item = Ty<'tcx>> + '_ {
        self.projections.iter().enumerate().rev().filter_map(move |(index, proj)| {
            if ProjectionKind::Deref == proj.kind {
                Some(self.ty_before_projection(index))
            } else {
                None
            }
        })
    }

    /// Returns the type of this `Place` after all projections have been applied.
    pub fn ty(&self) -> Ty<'tcx> {
        self.projections.last().map_or(self.base_ty, |proj| proj.ty)
    }

    /// Returns the type of this `Place` immediately before `projection_index`th projection
    /// is applied.
    pub fn ty_before_projection(&self, projection_index: usize) -> Ty<'tcx> {
        assert!(projection_index < self.projections.len());
        if projection_index == 0 { self.base_ty } else { self.projections[projection_index - 1].ty }
    }
}