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(..) | Error(..) => panic!("internal type error"),
77        };
78        Place {
79            ty: proj_ty,
80            kind: PlaceKind::Projection(Box::new(self), ProjectionElem::Deref),
81        }
82    }
83
84    pub fn projections<'a>(&'a self) -> impl Iterator<Item = &'a ProjectionElem> {
85        let mut place = self;
86        std::iter::from_fn(move || {
87            let (new_place, proj) = place.as_projection()?;
88            place = new_place;
89            Some(proj)
90        })
91    }
92}
93
94impl Operand {
95    pub fn mk_const_unit() -> Self {
96        Operand::Const(Box::new(ConstantExpr {
97            kind: ConstantExprKind::Adt(None, Vec::new()),
98            ty: Ty::mk_unit(),
99        }))
100    }
101
102    pub fn ty(&self) -> &Ty {
103        match self {
104            Operand::Copy(place) | Operand::Move(place) => place.ty(),
105            Operand::Const(constant_expr) => &constant_expr.ty,
106        }
107    }
108}
109
110impl Rvalue {
111    pub fn unit_value() -> Self {
112        Rvalue::Aggregate(
113            AggregateKind::Adt(
114                TypeDeclRef {
115                    id: TypeId::Tuple,
116                    generics: Box::new(GenericArgs::empty()),
117                },
118                None,
119                None,
120            ),
121            Vec::new(),
122        )
123    }
124}
125
126impl BorrowKind {
127    pub fn mutable(x: bool) -> Self {
128        if x { Self::Mut } else { Self::Shared }
129    }
130}
131
132impl ProjectionElem {
133    /// Compute the type obtained when applying the current projection to a place of type `ty`.
134    pub fn project_type(&self, krate: &TranslatedCrate, ty: &Ty) -> Result<Ty, ()> {
135        use ProjectionElem::*;
136        Ok(match self {
137            Deref => {
138                use TyKind::*;
139                match ty.kind() {
140                    Ref(_, ty, _) | RawPtr(ty, _) => ty.clone(),
141                    Adt(tref) if matches!(tref.id, TypeId::Builtin(BuiltinTy::Box)) => {
142                        tref.generics.types[0].clone()
143                    }
144                    Adt(..) | TypeVar(_) | Literal(_) | Never | TraitType(..) | DynTrait(..)
145                    | FnPtr(..) | FnDef(..) | PtrMetadata(..) | Error(..) => {
146                        // Type error
147                        return Err(());
148                    }
149                }
150            }
151            Field(pkind, field_id) => {
152                // Lookup the type decl
153                use FieldProjKind::*;
154                match pkind {
155                    Adt(type_decl_id, variant_id) => {
156                        // Can fail if the type declaration was not translated.
157                        let type_decl = krate.type_decls.get(*type_decl_id).ok_or(())?;
158                        let tref = ty.as_adt().ok_or(())?;
159                        assert!(TypeId::Adt(*type_decl_id) == tref.id);
160                        use TypeDeclKind::*;
161                        match &type_decl.kind {
162                            Struct(fields) | Union(fields) => {
163                                if variant_id.is_some() {
164                                    return Err(());
165                                };
166                                fields
167                                    .get(*field_id)
168                                    .ok_or(())?
169                                    .ty
170                                    .clone()
171                                    .substitute(&tref.generics)
172                            }
173                            Enum(variants) => {
174                                let variant_id = variant_id.ok_or(())?;
175                                let variant = variants.get(variant_id).ok_or(())?;
176                                variant
177                                    .fields
178                                    .get(*field_id)
179                                    .ok_or(())?
180                                    .ty
181                                    .clone()
182                                    .substitute(&tref.generics)
183                            }
184                            Opaque | Alias(_) | Error(_) => return Err(()),
185                        }
186                    }
187                    Tuple(_) => ty
188                        .as_tuple()
189                        .ok_or(())?
190                        .get(TypeVarId::from(usize::from(*field_id)))
191                        .ok_or(())?
192                        .clone(),
193                }
194            }
195            PtrMetadata => ty.get_ptr_metadata(krate).into_type(),
196            Index { .. } | Subslice { .. } => ty.as_array_or_slice().ok_or(())?.clone(),
197        })
198    }
199}
200
201impl From<ConstGeneric> for ConstantExprKind {
202    fn from(cg: ConstGeneric) -> Self {
203        match cg {
204            ConstGeneric::Global(id) => ConstantExprKind::Global(GlobalDeclRef {
205                id,
206                generics: Box::new(GenericArgs::empty()),
207            }),
208            ConstGeneric::Var(var) => ConstantExprKind::Var(var),
209            ConstGeneric::Value(lit) => ConstantExprKind::Literal(lit),
210        }
211    }
212}
213
214impl BinOp {
215    pub fn with_overflow(&self, overflow: OverflowMode) -> Self {
216        match self {
217            BinOp::Add(_) | BinOp::AddChecked => BinOp::Add(overflow),
218            BinOp::Sub(_) | BinOp::SubChecked => BinOp::Sub(overflow),
219            BinOp::Mul(_) | BinOp::MulChecked => BinOp::Mul(overflow),
220            BinOp::Div(_) => BinOp::Div(overflow),
221            BinOp::Rem(_) => BinOp::Rem(overflow),
222            BinOp::Shl(_) => BinOp::Shl(overflow),
223            BinOp::Shr(_) => BinOp::Shr(overflow),
224            _ => {
225                panic!(
226                    "Cannot set overflow mode for this binary operator: {:?}",
227                    self
228                );
229            }
230        }
231    }
232}
233
234impl UnOp {
235    pub fn with_overflow(&self, overflow: OverflowMode) -> Self {
236        match self {
237            UnOp::Neg(_) => UnOp::Neg(overflow),
238            _ => {
239                panic!(
240                    "Cannot set overflow mode for this unary operator: {:?}",
241                    self
242                );
243            }
244        }
245    }
246}