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