charon_lib/ast/
expressions_utils.rs

1//! This file groups everything which is linked to implementations about [crate::expressions]
2use crate::ast::*;
3
4impl Place {
5    pub fn new(local_id: LocalId, ty: Ty) -> Place {
6        Place {
7            kind: PlaceKind::Local(local_id),
8            ty,
9        }
10    }
11
12    pub fn new_global(global: GlobalDeclRef, ty: Ty) -> Place {
13        Place {
14            kind: PlaceKind::Global(global),
15            ty,
16        }
17    }
18
19    pub fn ty(&self) -> &Ty {
20        &self.ty
21    }
22
23    /// Whether this place corresponds to a local variable without any projections.
24    pub fn is_local(&self) -> bool {
25        self.as_local().is_some()
26    }
27
28    /// If this place corresponds to an unprojected local, return the variable id.
29    pub fn as_local(&self) -> Option<LocalId> {
30        self.kind.as_local().copied()
31    }
32
33    pub fn as_projection(&self) -> Option<(&Self, &ProjectionElem)> {
34        self.kind.as_projection().map(|(pl, pj)| (pl.as_ref(), pj))
35    }
36
37    #[deprecated(note = "use `local_id` instead")]
38    pub fn var_id(&self) -> Option<LocalId> {
39        self.local_id()
40    }
41    pub fn local_id(&self) -> Option<LocalId> {
42        match &self.kind {
43            PlaceKind::Local(var_id) => Some(*var_id),
44            PlaceKind::Projection(subplace, _) => subplace.local_id(),
45            PlaceKind::Global(_) => None,
46        }
47    }
48
49    pub fn project(self, elem: ProjectionElem, ty: Ty) -> Self {
50        Self {
51            kind: PlaceKind::Projection(Box::new(self), elem),
52            ty,
53        }
54    }
55
56    pub fn project_auto_ty(
57        self,
58        krate: &TranslatedCrate,
59        proj: ProjectionElem,
60    ) -> Result<Self, ()> {
61        Ok(Place {
62            ty: proj.project_type(krate, &self.ty)?,
63            kind: PlaceKind::Projection(Box::new(self), proj),
64        })
65    }
66
67    /// Dereferences the place. Panics if the type cannot be dereferenced.
68    pub fn deref(self) -> Place {
69        use TyKind::*;
70        let proj_ty = match self.ty.kind() {
71            Ref(_, ty, _) | RawPtr(ty, _) => ty.clone(),
72            Adt(tref) if matches!(tref.id, TypeId::Builtin(BuiltinTy::Box)) => {
73                tref.generics.types[0].clone()
74            }
75            Adt(..) | TypeVar(_) | Literal(_) | Never | TraitType(..) | DynTrait(..)
76            | FnPtr(..) | FnDef(..) | PtrMetadata(..) | Array(..) | Slice(_) | Error(..) => {
77                panic!("internal type error")
78            }
79        };
80        Place {
81            ty: proj_ty,
82            kind: PlaceKind::Projection(Box::new(self), ProjectionElem::Deref),
83        }
84    }
85
86    pub fn projections<'a>(&'a self) -> impl Iterator<Item = &'a ProjectionElem> {
87        let mut place = self;
88        std::iter::from_fn(move || {
89            let (new_place, proj) = place.as_projection()?;
90            place = new_place;
91            Some(proj)
92        })
93    }
94}
95
96impl Operand {
97    pub fn mk_const_unit() -> Self {
98        Operand::Const(Box::new(ConstantExpr {
99            kind: ConstantExprKind::Adt(None, Vec::new()),
100            ty: Ty::mk_unit(),
101        }))
102    }
103
104    pub fn ty(&self) -> &Ty {
105        match self {
106            Operand::Copy(place) | Operand::Move(place) => place.ty(),
107            Operand::Const(constant_expr) => &constant_expr.ty,
108        }
109    }
110}
111
112impl Rvalue {
113    pub fn unit_value() -> Self {
114        Rvalue::Aggregate(
115            AggregateKind::Adt(
116                TypeDeclRef {
117                    id: TypeId::Tuple,
118                    generics: Box::new(GenericArgs::empty()),
119                },
120                None,
121                None,
122            ),
123            Vec::new(),
124        )
125    }
126}
127
128impl BorrowKind {
129    pub fn mutable(x: bool) -> Self {
130        if x { Self::Mut } else { Self::Shared }
131    }
132}
133
134impl From<BorrowKind> for RefKind {
135    fn from(value: BorrowKind) -> Self {
136        match value {
137            BorrowKind::Shared | BorrowKind::Shallow => RefKind::Shared,
138            BorrowKind::Mut | BorrowKind::TwoPhaseMut | BorrowKind::UniqueImmutable => RefKind::Mut,
139        }
140    }
141}
142
143impl From<RefKind> for BorrowKind {
144    fn from(value: RefKind) -> Self {
145        match value {
146            RefKind::Shared => BorrowKind::Shared,
147            RefKind::Mut => BorrowKind::Mut,
148        }
149    }
150}
151
152impl ProjectionElem {
153    /// Compute the type obtained when applying the current projection to a place of type `ty`.
154    pub fn project_type(&self, krate: &TranslatedCrate, ty: &Ty) -> Result<Ty, ()> {
155        use ProjectionElem::*;
156        Ok(match self {
157            Deref => {
158                use TyKind::*;
159                match ty.kind() {
160                    Ref(_, ty, _) | RawPtr(ty, _) => ty.clone(),
161                    Adt(tref) if matches!(tref.id, TypeId::Builtin(BuiltinTy::Box)) => {
162                        tref.generics.types[0].clone()
163                    }
164                    Adt(..) | TypeVar(_) | Literal(_) | Never | TraitType(..) | DynTrait(..)
165                    | Array(..) | Slice(..) | FnPtr(..) | FnDef(..) | PtrMetadata(..)
166                    | Error(..) => {
167                        // Type error
168                        return Err(());
169                    }
170                }
171            }
172            Field(pkind, field_id) => {
173                // Lookup the type decl
174                use FieldProjKind::*;
175                match pkind {
176                    Adt(type_decl_id, variant_id) => {
177                        // Can fail if the type declaration was not translated.
178                        let type_decl = krate.type_decls.get(*type_decl_id).ok_or(())?;
179                        let tref = ty.as_adt().ok_or(())?;
180                        assert!(TypeId::Adt(*type_decl_id) == tref.id);
181                        use TypeDeclKind::*;
182                        match &type_decl.kind {
183                            Struct(fields) | Union(fields) => {
184                                if variant_id.is_some() {
185                                    return Err(());
186                                };
187                                fields
188                                    .get(*field_id)
189                                    .ok_or(())?
190                                    .ty
191                                    .clone()
192                                    .substitute(&tref.generics)
193                            }
194                            Enum(variants) => {
195                                let variant_id = variant_id.ok_or(())?;
196                                let variant = variants.get(variant_id).ok_or(())?;
197                                variant
198                                    .fields
199                                    .get(*field_id)
200                                    .ok_or(())?
201                                    .ty
202                                    .clone()
203                                    .substitute(&tref.generics)
204                            }
205                            Opaque | Alias(_) | Error(_) => return Err(()),
206                        }
207                    }
208                    Tuple(_) => ty
209                        .as_tuple()
210                        .ok_or(())?
211                        .get(TypeVarId::from(usize::from(*field_id)))
212                        .ok_or(())?
213                        .clone(),
214                }
215            }
216            PtrMetadata => ty.get_ptr_metadata(krate).into_type(),
217            Index { .. } | Subslice { .. } => ty.as_array_or_slice().ok_or(())?.clone(),
218        })
219    }
220}
221
222impl From<ConstGeneric> for ConstantExprKind {
223    fn from(cg: ConstGeneric) -> Self {
224        match cg {
225            ConstGeneric::Global(id) => ConstantExprKind::Global(GlobalDeclRef {
226                id,
227                generics: Box::new(GenericArgs::empty()),
228            }),
229            ConstGeneric::Var(var) => ConstantExprKind::Var(var),
230            ConstGeneric::Value(lit) => ConstantExprKind::Literal(lit),
231        }
232    }
233}
234
235impl BinOp {
236    pub fn with_overflow(&self, overflow: OverflowMode) -> Self {
237        match self {
238            BinOp::Add(_) | BinOp::AddChecked => BinOp::Add(overflow),
239            BinOp::Sub(_) | BinOp::SubChecked => BinOp::Sub(overflow),
240            BinOp::Mul(_) | BinOp::MulChecked => BinOp::Mul(overflow),
241            BinOp::Div(_) => BinOp::Div(overflow),
242            BinOp::Rem(_) => BinOp::Rem(overflow),
243            BinOp::Shl(_) => BinOp::Shl(overflow),
244            BinOp::Shr(_) => BinOp::Shr(overflow),
245            _ => {
246                panic!(
247                    "Cannot set overflow mode for this binary operator: {:?}",
248                    self
249                );
250            }
251        }
252    }
253}
254
255impl UnOp {
256    pub fn with_overflow(&self, overflow: OverflowMode) -> Self {
257        match self {
258            UnOp::Neg(_) => UnOp::Neg(overflow),
259            _ => {
260                panic!(
261                    "Cannot set overflow mode for this unary operator: {:?}",
262                    self
263                );
264            }
265        }
266    }
267}
268
269impl FnPtr {
270    pub fn new(kind: FnPtrKind, generics: impl Into<BoxedArgs>) -> Self {
271        Self {
272            kind: Box::new(kind),
273            generics: generics.into(),
274        }
275    }
276
277    /// Get the generics for the pre-monomorphization item.
278    pub fn pre_mono_generics<'a>(&'a self, krate: &'a TranslatedCrate) -> &'a GenericArgs {
279        match *self.kind {
280            FnPtrKind::Fun(FunId::Regular(fun_id)) => krate
281                .item_name(fun_id)
282                .unwrap()
283                .mono_args()
284                .unwrap_or(&self.generics),
285            //  We don't mono builtins.
286            FnPtrKind::Fun(FunId::Builtin(..)) => &self.generics,
287            // Can't happen in mono mode.
288            FnPtrKind::Trait(..) => &self.generics,
289        }
290    }
291}