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