1 use crate::ty;
2 use crate::ty::Ty;
3 
4 use rustc_hir::HirId;
5 use rustc_target::abi::VariantIdx;
6 
7 #[derive(
8     Clone,
9     Copy,
10     Debug,
11     PartialEq,
12     Eq,
13     Hash,
14     TyEncodable,
15     TyDecodable,
16     TypeFoldable,
17     HashStable
18 )]
19 pub enum PlaceBase {
20     /// A temporary variable.
21     Rvalue,
22     /// A named `static` item.
23     StaticItem,
24     /// A named local variable.
25     Local(HirId),
26     /// An upvar referenced by closure env.
27     Upvar(ty::UpvarId),
28 }
29 
30 #[derive(
31     Clone,
32     Copy,
33     Debug,
34     PartialEq,
35     Eq,
36     Hash,
37     TyEncodable,
38     TyDecodable,
39     TypeFoldable,
40     HashStable
41 )]
42 pub enum ProjectionKind {
43     /// A dereference of a pointer, reference or `Box<T>` of the given type.
44     Deref,
45 
46     /// `B.F` where `B` is the base expression and `F` is
47     /// the field. The field is identified by which variant
48     /// it appears in along with a field index. The variant
49     /// is used for enums.
50     Field(u32, VariantIdx),
51 
52     /// Some index like `B[x]`, where `B` is the base
53     /// expression. We don't preserve the index `x` because
54     /// we won't need it.
55     Index,
56 
57     /// A subslice covering a range of values like `B[x..y]`.
58     Subslice,
59 }
60 
61 #[derive(
62     Clone,
63     Copy,
64     Debug,
65     PartialEq,
66     Eq,
67     Hash,
68     TyEncodable,
69     TyDecodable,
70     TypeFoldable,
71     HashStable
72 )]
73 pub struct Projection<'tcx> {
74     /// Type after the projection is applied.
75     pub ty: Ty<'tcx>,
76 
77     /// Defines the kind of access made by the projection.
78     pub kind: ProjectionKind,
79 }
80 
81 /// A `Place` represents how a value is located in memory.
82 ///
83 /// This is an HIR version of [`rustc_middle::mir::Place`].
84 #[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
85 pub struct Place<'tcx> {
86     /// The type of the `PlaceBase`
87     pub base_ty: Ty<'tcx>,
88     /// The "outermost" place that holds this value.
89     pub base: PlaceBase,
90     /// How this place is derived from the base place.
91     pub projections: Vec<Projection<'tcx>>,
92 }
93 
94 /// A `PlaceWithHirId` represents how a value is located in memory.
95 ///
96 /// This is an HIR version of [`rustc_middle::mir::Place`].
97 #[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
98 pub struct PlaceWithHirId<'tcx> {
99     /// `HirId` of the expression or pattern producing this value.
100     pub hir_id: HirId,
101 
102     /// Information about the `Place`.
103     pub place: Place<'tcx>,
104 }
105 
106 impl<'tcx> PlaceWithHirId<'tcx> {
new( hir_id: HirId, base_ty: Ty<'tcx>, base: PlaceBase, projections: Vec<Projection<'tcx>>, ) -> PlaceWithHirId<'tcx>107     pub fn new(
108         hir_id: HirId,
109         base_ty: Ty<'tcx>,
110         base: PlaceBase,
111         projections: Vec<Projection<'tcx>>,
112     ) -> PlaceWithHirId<'tcx> {
113         PlaceWithHirId { hir_id, place: Place { base_ty, base, projections } }
114     }
115 }
116 
117 impl<'tcx> Place<'tcx> {
118     /// Returns an iterator of the types that have to be dereferenced to access
119     /// the `Place`.
120     ///
121     /// The types are in the reverse order that they are applied. So if
122     /// `x: &*const u32` and the `Place` is `**x`, then the types returned are
123     ///`*const u32` then `&*const u32`.
deref_tys(&self) -> impl Iterator<Item = Ty<'tcx>> + '_124     pub fn deref_tys(&self) -> impl Iterator<Item = Ty<'tcx>> + '_ {
125         self.projections.iter().enumerate().rev().filter_map(move |(index, proj)| {
126             if ProjectionKind::Deref == proj.kind {
127                 Some(self.ty_before_projection(index))
128             } else {
129                 None
130             }
131         })
132     }
133 
134     /// Returns the type of this `Place` after all projections have been applied.
ty(&self) -> Ty<'tcx>135     pub fn ty(&self) -> Ty<'tcx> {
136         self.projections.last().map_or(self.base_ty, |proj| proj.ty)
137     }
138 
139     /// Returns the type of this `Place` immediately before `projection_index`th projection
140     /// is applied.
ty_before_projection(&self, projection_index: usize) -> Ty<'tcx>141     pub fn ty_before_projection(&self, projection_index: usize) -> Ty<'tcx> {
142         assert!(projection_index < self.projections.len());
143         if projection_index == 0 { self.base_ty } else { self.projections[projection_index - 1].ty }
144     }
145 }
146