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 = HashConsSerializerState)] 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 #[drive(skip)]
76 from_end: bool,
77 },
78 Subslice {
82 from: Box<Operand>,
83 to: Box<Operand>,
84 #[drive(skip)]
85 from_end: bool,
86 },
87}
88
89impl Place {
90 pub fn new(local_id: LocalId, ty: Ty) -> Place {
91 Place {
92 kind: PlaceKind::Local(local_id),
93 ty,
94 }
95 }
96
97 pub fn new_global(global: GlobalDeclRef, ty: Ty) -> Place {
98 Place {
99 kind: PlaceKind::Global(global),
100 ty,
101 }
102 }
103
104 pub fn ty(&self) -> &Ty {
105 &self.ty
106 }
107
108 pub fn is_local(&self) -> bool {
110 self.as_local().is_some()
111 }
112
113 pub fn as_local(&self) -> Option<LocalId> {
115 self.kind.as_local().copied()
116 }
117
118 pub fn as_projection(&self) -> Option<(&Self, &ProjectionElem)> {
119 self.kind.as_projection().map(|(pl, pj)| (pl.as_ref(), pj))
120 }
121
122 #[deprecated(note = "use `local_id` instead")]
123 pub fn var_id(&self) -> Option<LocalId> {
124 self.local_id()
125 }
126 pub fn local_id(&self) -> Option<LocalId> {
127 match &self.kind {
128 PlaceKind::Local(var_id) => Some(*var_id),
129 PlaceKind::Projection(subplace, _) => subplace.local_id(),
130 PlaceKind::Global(_) => None,
131 }
132 }
133
134 pub fn project(self, elem: ProjectionElem, ty: Ty) -> Self {
135 Self {
136 kind: PlaceKind::Projection(Box::new(self), elem),
137 ty,
138 }
139 }
140
141 pub fn project_auto_ty(self, krate: &TranslatedCrate, proj: ProjectionElem) -> Option<Self> {
142 Some(Place {
143 ty: proj.project_type(krate, &self.ty)?,
144 kind: PlaceKind::Projection(Box::new(self), proj),
145 })
146 }
147
148 pub fn deref(self) -> Place {
150 use TyKind::*;
151 let proj_ty = match self.ty.kind() {
152 Ref(_, ty, _) | RawPtr(ty, _) => ty.clone(),
153 Adt(tref) if tref.is_box() => tref.generics.types[0].clone(),
154 Adt(..) | TypeVar(_) | Literal(_) | Never | TraitType(..) | DynTrait(..)
155 | FnPtr(..) | FnDef(..) | PtrMetadata(..) | Array(..) | Slice(_) | Pattern(..)
156 | Error(..) => {
157 panic!("internal type error")
158 }
159 };
160 Place {
161 ty: proj_ty,
162 kind: PlaceKind::Projection(Box::new(self), ProjectionElem::Deref),
163 }
164 }
165
166 pub fn projections(&self) -> impl Iterator<Item = &ProjectionElem> {
167 let mut place = self;
168 std::iter::from_fn(move || {
169 let (new_place, proj) = place.as_projection()?;
170 place = new_place;
171 Some(proj)
172 })
173 }
174}
175
176impl ProjectionElem {
177 pub fn project_type(&self, krate: &TranslatedCrate, ty: &Ty) -> Option<Ty> {
179 use ProjectionElem::*;
180 Some(match self {
181 Deref => {
182 use TyKind::*;
183 match ty.kind() {
184 Ref(_, ty, _) | RawPtr(ty, _) => ty.clone(),
185 Adt(tref) if tref.is_box() => tref.generics.types[0].clone(),
186 Adt(..) | TypeVar(_) | Literal(_) | Never | TraitType(..) | DynTrait(..)
187 | Array(..) | Slice(..) | FnPtr(..) | FnDef(..) | PtrMetadata(..)
188 | Pattern(..) | Error(..) => {
189 return None;
191 }
192 }
193 }
194 Field(variant_id, field_id) => {
195 let tref = ty.as_adt()?;
196 match tref.as_builtin() {
197 None => {
198 let type_decl = krate.type_decls.get(tref.adt_id())?;
200 use TypeDeclKind::*;
201 match &type_decl.kind {
202 Struct(fields) | Union(fields) => {
203 if variant_id.is_some() {
204 return None;
205 };
206 fields.get(*field_id)?.ty.clone().substitute(&tref.generics)
207 }
208 Enum(variants) => {
209 let variant_id = (*variant_id)?;
210 let variant = variants.get(variant_id)?;
211 variant
212 .fields
213 .get(*field_id)?
214 .ty
215 .clone()
216 .substitute(&tref.generics)
217 }
218 Opaque | Alias(_) | Error(_) => return None,
219 }
220 }
221 Some(BuiltinTy::Tuple) => tref
222 .generics
223 .types
224 .get(TypeVarId::from(usize::from(*field_id)))?
225 .clone(),
226 Some(_) => return None,
227 }
228 }
229 PtrMetadata => ty.get_ptr_metadata(krate).into_type(),
230 Index { .. } | Subslice { .. } => ty.as_array_or_slice()?.clone(),
231 })
232 }
233}