charon_lib/ast/
expressions_utils.rs

1//! This file groups everything which is linked to implementations about [crate::expressions]
2use crate::ast::*;
3use crate::ids::Vector;
4
5impl Place {
6    pub fn new(local_id: LocalId, ty: Ty) -> Place {
7        Place {
8            kind: PlaceKind::Local(local_id),
9            ty,
10        }
11    }
12
13    pub fn ty(&self) -> &Ty {
14        &self.ty
15    }
16
17    /// Whether this place corresponds to a local variable without any projections.
18    pub fn is_local(&self) -> bool {
19        self.as_local().is_some()
20    }
21
22    /// If this place corresponds to an unprojected local, return the variable id.
23    pub fn as_local(&self) -> Option<LocalId> {
24        self.kind.as_local().copied()
25    }
26
27    pub fn as_projection(&self) -> Option<(&Self, &ProjectionElem)> {
28        self.kind.as_projection().map(|(pl, pj)| (pl.as_ref(), pj))
29    }
30
31    #[deprecated(note = "use `local_id` instead")]
32    pub fn var_id(&self) -> LocalId {
33        self.local_id()
34    }
35    pub fn local_id(&self) -> LocalId {
36        match &self.kind {
37            PlaceKind::Local(var_id) => *var_id,
38            PlaceKind::Projection(subplace, _) => subplace.local_id(),
39        }
40    }
41
42    pub fn project(self, elem: ProjectionElem, ty: Ty) -> Self {
43        Self {
44            kind: PlaceKind::Projection(Box::new(self), elem),
45            ty,
46        }
47    }
48
49    pub fn project_auto_ty(
50        self,
51        type_decls: &Vector<TypeDeclId, TypeDecl>,
52        proj: ProjectionElem,
53    ) -> Result<Self, ()> {
54        Ok(Place {
55            ty: proj.project_type(type_decls, &self.ty)?,
56            kind: PlaceKind::Projection(Box::new(self), proj),
57        })
58    }
59
60    /// Dereferences the place. Panics if the type cannot be dereferenced.
61    pub fn deref(self) -> Place {
62        use TyKind::*;
63        let proj_ty = match self.ty.kind() {
64            Ref(_, ty, _) | RawPtr(ty, _) => ty.clone(),
65            Adt(tref) if matches!(tref.id, TypeId::Builtin(BuiltinTy::Box)) => {
66                tref.generics.types[0].clone()
67            }
68            Adt(..) | TypeVar(_) | Literal(_) | Never | TraitType(..) | DynTrait(_) | FnPtr(..)
69            | FnDef(..) | Error(..) => panic!("internal type error"),
70        };
71        Place {
72            ty: proj_ty,
73            kind: PlaceKind::Projection(Box::new(self), ProjectionElem::Deref),
74        }
75    }
76
77    pub fn projections<'a>(&'a self) -> impl Iterator<Item = &'a ProjectionElem> {
78        let mut place = self;
79        std::iter::from_fn(move || {
80            let (new_place, proj) = place.as_projection()?;
81            place = new_place;
82            Some(proj)
83        })
84    }
85}
86
87impl Rvalue {
88    pub fn unit_value() -> Self {
89        Rvalue::Aggregate(
90            AggregateKind::Adt(
91                TypeDeclRef {
92                    id: TypeId::Tuple,
93                    generics: Box::new(GenericArgs::empty()),
94                },
95                None,
96                None,
97            ),
98            Vec::new(),
99        )
100    }
101}
102
103impl BorrowKind {
104    pub fn mutable(x: bool) -> Self {
105        if x {
106            Self::Mut
107        } else {
108            Self::Shared
109        }
110    }
111}
112
113impl ProjectionElem {
114    /// Compute the type obtained when applying the current projection to a place of type `ty`.
115    pub fn project_type(
116        &self,
117        type_decls: &Vector<TypeDeclId, TypeDecl>,
118        ty: &Ty,
119    ) -> Result<Ty, ()> {
120        use ProjectionElem::*;
121        Ok(match self {
122            Deref => {
123                use TyKind::*;
124                match ty.kind() {
125                    Ref(_, ty, _) | RawPtr(ty, _) => ty.clone(),
126                    Adt(tref) if matches!(tref.id, TypeId::Builtin(BuiltinTy::Box)) => {
127                        tref.generics.types[0].clone()
128                    }
129                    Adt(..) | TypeVar(_) | Literal(_) | Never | TraitType(..) | DynTrait(_)
130                    | FnPtr(..) | FnDef(..) | Error(..) => {
131                        // Type error
132                        return Err(());
133                    }
134                }
135            }
136            Field(pkind, field_id) => {
137                // Lookup the type decl
138                use FieldProjKind::*;
139                match pkind {
140                    Adt(type_decl_id, variant_id) => {
141                        // Can fail if the type declaration was not translated.
142                        let type_decl = type_decls.get(*type_decl_id).ok_or(())?;
143                        let tref = ty.as_adt().ok_or(())?;
144                        assert!(TypeId::Adt(*type_decl_id) == tref.id);
145                        use TypeDeclKind::*;
146                        match &type_decl.kind {
147                            Struct(fields) | Union(fields) => {
148                                if variant_id.is_some() {
149                                    return Err(());
150                                };
151                                fields
152                                    .get(*field_id)
153                                    .ok_or(())?
154                                    .ty
155                                    .clone()
156                                    .substitute(&tref.generics)
157                            }
158                            Enum(variants) => {
159                                let variant_id = variant_id.ok_or(())?;
160                                let variant = variants.get(variant_id).ok_or(())?;
161                                variant
162                                    .fields
163                                    .get(*field_id)
164                                    .ok_or(())?
165                                    .ty
166                                    .clone()
167                                    .substitute(&tref.generics)
168                            }
169                            Opaque | Alias(_) | Error(_) => return Err(()),
170                        }
171                    }
172                    Tuple(_) => ty
173                        .as_tuple()
174                        .ok_or(())?
175                        .get(TypeVarId::from(usize::from(*field_id)))
176                        .ok_or(())?
177                        .clone(),
178                }
179            }
180            Index { .. } | Subslice { .. } => ty.as_array_or_slice().ok_or(())?.clone(),
181        })
182    }
183}