rustc_middle/hir/place.rs
1use rustc_abi::{FieldIdx, VariantIdx};
2use rustc_hir::HirId;
3use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
4
5use crate::ty;
6use crate::ty::Ty;
7
8#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
9#[derive(TypeFoldable, TypeVisitable)]
10pub 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)]
23pub 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 ///
44 /// This is unused if `-Znext-solver` is enabled.
45 OpaqueCast,
46}
47
48#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
49#[derive(TypeFoldable, TypeVisitable)]
50pub struct Projection<'tcx> {
51 /// Type after the projection is applied.
52 pub ty: Ty<'tcx>,
53
54 /// Defines the kind of access made by the projection.
55 pub kind: ProjectionKind,
56}
57
58/// A `Place` represents how a value is located in memory. This does not
59/// always correspond to a syntactic place expression. For example, when
60/// processing a pattern, a `Place` can be used to refer to the sub-value
61/// currently being inspected.
62///
63/// This is an HIR version of [`rustc_middle::mir::Place`].
64#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
65#[derive(TypeFoldable, TypeVisitable)]
66pub struct Place<'tcx> {
67 /// The type of the `PlaceBase`
68 pub base_ty: Ty<'tcx>,
69 /// The "outermost" place that holds this value.
70 pub base: PlaceBase,
71 /// How this place is derived from the base place.
72 pub projections: Vec<Projection<'tcx>>,
73}
74
75/// A `PlaceWithHirId` represents how a value is located in memory. This does not
76/// always correspond to a syntactic place expression. For example, when
77/// processing a pattern, a `Place` can be used to refer to the sub-value
78/// currently being inspected.
79///
80/// This is an HIR version of [`rustc_middle::mir::Place`].
81#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
82pub struct PlaceWithHirId<'tcx> {
83 /// `HirId` of the expression or pattern producing this value.
84 pub hir_id: HirId,
85
86 /// Information about the `Place`.
87 pub place: Place<'tcx>,
88}
89
90impl<'tcx> PlaceWithHirId<'tcx> {
91 pub fn new(
92 hir_id: HirId,
93 base_ty: Ty<'tcx>,
94 base: PlaceBase,
95 projections: Vec<Projection<'tcx>>,
96 ) -> PlaceWithHirId<'tcx> {
97 PlaceWithHirId { hir_id, place: Place { base_ty, base, projections } }
98 }
99}
100
101impl<'tcx> Place<'tcx> {
102 /// Returns an iterator of the types that have to be dereferenced to access
103 /// the `Place`.
104 ///
105 /// The types are in the reverse order that they are applied. So if
106 /// `x: &*const u32` and the `Place` is `**x`, then the types returned are
107 ///`*const u32` then `&*const u32`.
108 pub fn deref_tys(&self) -> impl Iterator<Item = Ty<'tcx>> {
109 self.projections.iter().enumerate().rev().filter_map(move |(index, proj)| {
110 if ProjectionKind::Deref == proj.kind {
111 Some(self.ty_before_projection(index))
112 } else {
113 None
114 }
115 })
116 }
117
118 /// Returns the type of this `Place` after all projections have been applied.
119 pub fn ty(&self) -> Ty<'tcx> {
120 self.projections.last().map_or(self.base_ty, |proj| proj.ty)
121 }
122
123 /// Returns the type of this `Place` immediately before `projection_index`th projection
124 /// is applied.
125 pub fn ty_before_projection(&self, projection_index: usize) -> Ty<'tcx> {
126 assert!(projection_index < self.projections.len());
127 if projection_index == 0 { self.base_ty } else { self.projections[projection_index - 1].ty }
128 }
129}