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 new_global(global: GlobalDeclRef, ty: Ty) -> Place {
14        Place {
15            kind: PlaceKind::Global(global),
16            ty,
17        }
18    }
19
20    pub fn ty(&self) -> &Ty {
21        &self.ty
22    }
23
24    /// Whether this place corresponds to a local variable without any projections.
25    pub fn is_local(&self) -> bool {
26        self.as_local().is_some()
27    }
28
29    /// If this place corresponds to an unprojected local, return the variable id.
30    pub fn as_local(&self) -> Option<LocalId> {
31        self.kind.as_local().copied()
32    }
33
34    pub fn as_projection(&self) -> Option<(&Self, &ProjectionElem)> {
35        self.kind.as_projection().map(|(pl, pj)| (pl.as_ref(), pj))
36    }
37
38    #[deprecated(note = "use `local_id` instead")]
39    pub fn var_id(&self) -> Option<LocalId> {
40        self.local_id()
41    }
42    pub fn local_id(&self) -> Option<LocalId> {
43        match &self.kind {
44            PlaceKind::Local(var_id) => Some(*var_id),
45            PlaceKind::Projection(subplace, _) => subplace.local_id(),
46            PlaceKind::Global(_) => None,
47        }
48    }
49
50    pub fn project(self, elem: ProjectionElem, ty: Ty) -> Self {
51        Self {
52            kind: PlaceKind::Projection(Box::new(self), elem),
53            ty,
54        }
55    }
56
57    pub fn project_auto_ty(
58        self,
59        type_decls: &Vector<TypeDeclId, TypeDecl>,
60        proj: ProjectionElem,
61    ) -> Result<Self, ()> {
62        Ok(Place {
63            ty: proj.project_type(type_decls, &self.ty)?,
64            kind: PlaceKind::Projection(Box::new(self), proj),
65        })
66    }
67
68    /// Dereferences the place. Panics if the type cannot be dereferenced.
69    pub fn deref(self) -> Place {
70        use TyKind::*;
71        let proj_ty = match self.ty.kind() {
72            Ref(_, ty, _) | RawPtr(ty, _) => ty.clone(),
73            Adt(tref) if matches!(tref.id, TypeId::Builtin(BuiltinTy::Box)) => {
74                tref.generics.types[0].clone()
75            }
76            Adt(..) | TypeVar(_) | Literal(_) | Never | TraitType(..) | DynTrait(..)
77            | FnPtr(..) | FnDef(..) | Error(..) => panic!("internal type error"),
78        };
79        Place {
80            ty: proj_ty,
81            kind: PlaceKind::Projection(Box::new(self), ProjectionElem::Deref),
82        }
83    }
84
85    pub fn projections<'a>(&'a self) -> impl Iterator<Item = &'a ProjectionElem> {
86        let mut place = self;
87        std::iter::from_fn(move || {
88            let (new_place, proj) = place.as_projection()?;
89            place = new_place;
90            Some(proj)
91        })
92    }
93}
94
95impl Rvalue {
96    pub fn unit_value() -> Self {
97        Rvalue::Aggregate(
98            AggregateKind::Adt(
99                TypeDeclRef {
100                    id: TypeId::Tuple,
101                    generics: Box::new(GenericArgs::empty()),
102                },
103                None,
104                None,
105            ),
106            Vec::new(),
107        )
108    }
109}
110
111impl BorrowKind {
112    pub fn mutable(x: bool) -> Self {
113        if x { Self::Mut } else { Self::Shared }
114    }
115}
116
117impl ProjectionElem {
118    /// Compute the type obtained when applying the current projection to a place of type `ty`.
119    pub fn project_type(
120        &self,
121        type_decls: &Vector<TypeDeclId, TypeDecl>,
122        ty: &Ty,
123    ) -> Result<Ty, ()> {
124        use ProjectionElem::*;
125        Ok(match self {
126            Deref => {
127                use TyKind::*;
128                match ty.kind() {
129                    Ref(_, ty, _) | RawPtr(ty, _) => ty.clone(),
130                    Adt(tref) if matches!(tref.id, TypeId::Builtin(BuiltinTy::Box)) => {
131                        tref.generics.types[0].clone()
132                    }
133                    Adt(..) | TypeVar(_) | Literal(_) | Never | TraitType(..) | DynTrait(..)
134                    | FnPtr(..) | FnDef(..) | Error(..) => {
135                        // Type error
136                        return Err(());
137                    }
138                }
139            }
140            Field(pkind, field_id) => {
141                // Lookup the type decl
142                use FieldProjKind::*;
143                match pkind {
144                    Adt(type_decl_id, variant_id) => {
145                        // Can fail if the type declaration was not translated.
146                        let type_decl = type_decls.get(*type_decl_id).ok_or(())?;
147                        let tref = ty.as_adt().ok_or(())?;
148                        assert!(TypeId::Adt(*type_decl_id) == tref.id);
149                        use TypeDeclKind::*;
150                        match &type_decl.kind {
151                            Struct(fields) | Union(fields) => {
152                                if variant_id.is_some() {
153                                    return Err(());
154                                };
155                                fields
156                                    .get(*field_id)
157                                    .ok_or(())?
158                                    .ty
159                                    .clone()
160                                    .substitute(&tref.generics)
161                            }
162                            Enum(variants) => {
163                                let variant_id = variant_id.ok_or(())?;
164                                let variant = variants.get(variant_id).ok_or(())?;
165                                variant
166                                    .fields
167                                    .get(*field_id)
168                                    .ok_or(())?
169                                    .ty
170                                    .clone()
171                                    .substitute(&tref.generics)
172                            }
173                            Opaque | Alias(_) | Error(_) => return Err(()),
174                        }
175                    }
176                    Tuple(_) => ty
177                        .as_tuple()
178                        .ok_or(())?
179                        .get(TypeVarId::from(usize::from(*field_id)))
180                        .ok_or(())?
181                        .clone(),
182                }
183            }
184            Index { .. } | Subslice { .. } => ty.as_array_or_slice().ok_or(())?.clone(),
185        })
186    }
187}
188
189impl From<ConstGeneric> for RawConstantExpr {
190    fn from(cg: ConstGeneric) -> Self {
191        match cg {
192            ConstGeneric::Global(id) => RawConstantExpr::Global(GlobalDeclRef {
193                id,
194                generics: Box::new(GenericArgs::empty()),
195            }),
196            ConstGeneric::Var(var) => RawConstantExpr::Var(var),
197            ConstGeneric::Value(lit) => RawConstantExpr::Literal(lit),
198        }
199    }
200}
201
202impl BinOp {
203    pub fn with_overflow(&self, overflow: OverflowMode) -> Self {
204        match self {
205            BinOp::Add(_) | BinOp::AddChecked => BinOp::Add(overflow),
206            BinOp::Sub(_) | BinOp::SubChecked => BinOp::Sub(overflow),
207            BinOp::Mul(_) | BinOp::MulChecked => BinOp::Mul(overflow),
208            BinOp::Div(_) => BinOp::Div(overflow),
209            BinOp::Rem(_) => BinOp::Rem(overflow),
210            BinOp::Shl(_) => BinOp::Shl(overflow),
211            BinOp::Shr(_) => BinOp::Shr(overflow),
212            _ => {
213                panic!(
214                    "Cannot set overflow mode for this binary operator: {:?}",
215                    self
216                );
217            }
218        }
219    }
220}
221
222impl UnOp {
223    pub fn with_overflow(&self, overflow: OverflowMode) -> Self {
224        match self {
225            UnOp::Neg(_) => UnOp::Neg(overflow),
226            _ => {
227                panic!(
228                    "Cannot set overflow mode for this unary operator: {:?}",
229                    self
230                );
231            }
232        }
233    }
234}