1use crate::ast::*;
3use derive_generic_visitor::{Drive, DriveMut, DriveTwo};
4use macros::{EnumAsGetters, EnumIsA, EnumToGetters, VariantName};
5use serde_state::{DeserializeState, SerializeState};
6
7#[derive(
8 Debug, PartialEq, Eq, Clone, SerializeState, DeserializeState, Drive, DriveMut, DriveTwo,
9)]
10#[serde_state(state_implements = DedupSerializerState)] pub struct Place {
12 pub kind: PlaceKind,
13 pub ty: Ty,
14}
15
16#[derive(
17 Debug,
18 PartialEq,
19 Eq,
20 Clone,
21 EnumIsA,
22 EnumAsGetters,
23 EnumToGetters,
24 SerializeState,
25 DeserializeState,
26 Drive,
27 DriveMut,
28 DriveTwo,
29)]
30#[cfg_attr(feature = "charon_on_charon", charon::variants_prefix("Place"))]
31pub enum PlaceKind {
32 Local(LocalId),
34 Projection(Box<Place>, ProjectionElem),
36 Global(GlobalDeclRef),
39}
40
41#[derive(
43 Debug,
44 PartialEq,
45 Eq,
46 Clone,
47 EnumIsA,
48 EnumAsGetters,
49 EnumToGetters,
50 VariantName,
51 SerializeState,
52 DeserializeState,
53 Drive,
54 DriveMut,
55 DriveTwo,
56)]
57pub enum ProjectionElem {
58 Deref,
60 Field(Option<VariantId>, FieldId),
62 PtrMetadata,
69 #[cfg_attr(feature = "charon_on_charon", charon::rename("ProjIndex"))]
73 Index {
74 offset: Box<Operand>,
75 from_end: bool,
76 },
77 Subslice {
81 from: Box<Operand>,
82 to: Box<Operand>,
83 from_end: bool,
84 },
85}
86
87impl Place {
88 pub fn new(local_id: LocalId, ty: Ty) -> Place {
89 Place {
90 kind: PlaceKind::Local(local_id),
91 ty,
92 }
93 }
94
95 pub fn new_global(global: GlobalDeclRef, ty: Ty) -> Place {
96 Place {
97 kind: PlaceKind::Global(global),
98 ty,
99 }
100 }
101
102 pub fn ty(&self) -> &Ty {
103 &self.ty
104 }
105
106 pub fn is_local(&self) -> bool {
108 self.as_local().is_some()
109 }
110
111 pub fn as_local(&self) -> Option<LocalId> {
113 self.kind.as_local().copied()
114 }
115
116 pub fn as_projection(&self) -> Option<(&Self, &ProjectionElem)> {
117 self.kind.as_projection().map(|(pl, pj)| (pl.as_ref(), pj))
118 }
119
120 #[deprecated(note = "use `local_id` instead")]
121 pub fn var_id(&self) -> Option<LocalId> {
122 self.local_id()
123 }
124 pub fn local_id(&self) -> Option<LocalId> {
125 match &self.kind {
126 PlaceKind::Local(var_id) => Some(*var_id),
127 PlaceKind::Projection(subplace, _) => subplace.local_id(),
128 PlaceKind::Global(_) => None,
129 }
130 }
131
132 pub fn project(self, elem: ProjectionElem, ty: Ty) -> Self {
133 Self {
134 kind: PlaceKind::Projection(Box::new(self), elem),
135 ty,
136 }
137 }
138
139 pub fn project_auto_ty(self, krate: &TranslatedCrate, proj: ProjectionElem) -> Option<Self> {
140 Some(Place {
141 ty: proj.project_type(krate, &self.ty)?,
142 kind: PlaceKind::Projection(Box::new(self), proj),
143 })
144 }
145
146 pub fn deref(self) -> Place {
148 use TyKind::*;
149 let proj_ty = match self.ty.kind() {
150 Ref(_, ty, _) | RawPtr(ty, _) => ty.clone(),
151 Adt(tref) if tref.is_box() => tref.generics.types[0].clone(),
152 Adt(..) | TypeVar(_) | Scalar(_) | Never | TraitType(..) | DynTrait(..) | FnPtr(..)
153 | FnDef(..) | PtrMetadata(..) | Array(..) | Slice(..) | Pattern(..) | Error(..) => {
154 panic!("internal type error")
155 }
156 };
157 Place {
158 ty: proj_ty,
159 kind: PlaceKind::Projection(Box::new(self), ProjectionElem::Deref),
160 }
161 }
162
163 pub fn subplaces(&self) -> impl Iterator<Item = &Self> {
165 std::iter::successors(Some(self), |place| Some(place.as_projection()?.0))
166 }
167
168 pub fn projections(&self) -> impl Iterator<Item = &ProjectionElem> {
169 self.subplaces()
170 .filter_map(|place| Some(place.as_projection()?.1))
171 }
172}
173
174impl ProjectionElem {
175 pub fn project_type(&self, krate: &TranslatedCrate, ty: &Ty) -> Option<Ty> {
177 use ProjectionElem::*;
178 Some(match self {
179 Deref => {
180 use TyKind::*;
181 match ty.kind() {
182 Ref(_, ty, _) | RawPtr(ty, _) => ty.clone(),
183 Adt(tref) if tref.is_box() => tref.generics.types[0].clone(),
184 Adt(..) | TypeVar(_) | Scalar(_) | Never | TraitType(..) | DynTrait(..)
185 | Array(..) | Slice(..) | FnPtr(..) | FnDef(..) | PtrMetadata(..)
186 | Pattern(..) | Error(..) => {
187 return None;
189 }
190 }
191 }
192 Field(variant_id, field_id) => {
193 let tref = ty.as_adt().unwrap();
194 let type_decl = krate.type_decls.get(tref.id)?;
195 use TypeDeclKind::*;
196 match &type_decl.kind {
197 Struct(fields) | Union(fields) => {
198 if variant_id.is_some() {
199 return None;
200 };
201 fields.get(*field_id)?.ty.clone().substitute(&tref.generics)
202 }
203 Enum(variants) => {
204 let variant_id = (*variant_id)?;
205 let variant = variants.get(variant_id)?;
206 variant
207 .fields
208 .get(*field_id)?
209 .ty
210 .clone()
211 .substitute(&tref.generics)
212 }
213 Opaque | Alias(_) | Error(_) => return None,
214 }
215 }
216 PtrMetadata => ty.get_ptr_metadata(krate).into_type(),
217 Index { .. } | Subslice { .. } => ty.as_array_or_slice()?.clone(),
218 })
219 }
220}