Skip to main content

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(self, krate: &TranslatedCrate, proj: ProjectionElem) -> Option<Self> {
57        Some(Place {
58            ty: proj.project_type(krate, &self.ty)?,
59            kind: PlaceKind::Projection(Box::new(self), proj),
60        })
61    }
62
63    /// Dereferences the place. Panics if the type cannot be dereferenced.
64    pub fn deref(self) -> Place {
65        use TyKind::*;
66        let proj_ty = match self.ty.kind() {
67            Ref(_, ty, _) | RawPtr(ty, _) => ty.clone(),
68            Adt(tref) if matches!(tref.id, TypeId::Builtin(BuiltinTy::Box)) => {
69                tref.generics.types[0].clone()
70            }
71            Adt(..) | TypeVar(_) | Literal(_) | Never | TraitType(..) | DynTrait(..)
72            | FnPtr(..) | FnDef(..) | PtrMetadata(..) | Array(..) | Slice(_) | Pattern(..)
73            | Error(..) => {
74                panic!("internal type error")
75            }
76        };
77        Place {
78            ty: proj_ty,
79            kind: PlaceKind::Projection(Box::new(self), ProjectionElem::Deref),
80        }
81    }
82
83    pub fn projections(&self) -> impl Iterator<Item = &ProjectionElem> {
84        let mut place = self;
85        std::iter::from_fn(move || {
86            let (new_place, proj) = place.as_projection()?;
87            place = new_place;
88            Some(proj)
89        })
90    }
91}
92
93impl ConstantExpr {
94    pub fn mk_unit() -> Self {
95        ConstantExpr {
96            kind: ConstantExprKind::Adt(None, Vec::new()),
97            ty: Ty::mk_unit(),
98        }
99    }
100
101    pub fn mk_usize(scalar: ScalarValue) -> Self {
102        ConstantExpr {
103            kind: ConstantExprKind::Literal(Literal::Scalar(scalar)),
104            ty: Ty::mk_usize(),
105        }
106    }
107}
108
109impl Operand {
110    pub fn mk_const_unit() -> Self {
111        Operand::Const(Box::new(ConstantExpr::mk_unit()))
112    }
113
114    pub fn ty(&self) -> &Ty {
115        match self {
116            Operand::Copy(place) | Operand::Move(place) => place.ty(),
117            Operand::Const(constant_expr) => &constant_expr.ty,
118        }
119    }
120}
121
122impl Rvalue {
123    pub fn unit_value() -> Self {
124        Rvalue::Aggregate(
125            AggregateKind::Adt(
126                TypeDeclRef {
127                    id: TypeId::Tuple,
128                    generics: Box::new(GenericArgs::empty()),
129                },
130                None,
131                None,
132            ),
133            Vec::new(),
134        )
135    }
136}
137
138impl BorrowKind {
139    pub fn mutable(x: bool) -> Self {
140        if x { Self::Mut } else { Self::Shared }
141    }
142}
143
144impl From<BorrowKind> for RefKind {
145    fn from(value: BorrowKind) -> Self {
146        match value {
147            BorrowKind::Shared | BorrowKind::Shallow => RefKind::Shared,
148            BorrowKind::Mut | BorrowKind::TwoPhaseMut | BorrowKind::UniqueImmutable => RefKind::Mut,
149        }
150    }
151}
152
153impl From<RefKind> for BorrowKind {
154    fn from(value: RefKind) -> Self {
155        match value {
156            RefKind::Shared => BorrowKind::Shared,
157            RefKind::Mut => BorrowKind::Mut,
158        }
159    }
160}
161
162impl ProjectionElem {
163    /// Compute the type obtained when applying the current projection to a place of type `ty`.
164    pub fn project_type(&self, krate: &TranslatedCrate, ty: &Ty) -> Option<Ty> {
165        use ProjectionElem::*;
166        Some(match self {
167            Deref => {
168                use TyKind::*;
169                match ty.kind() {
170                    Ref(_, ty, _) | RawPtr(ty, _) => ty.clone(),
171                    Adt(tref) if matches!(tref.id, TypeId::Builtin(BuiltinTy::Box)) => {
172                        tref.generics.types[0].clone()
173                    }
174                    Adt(..) | TypeVar(_) | Literal(_) | Never | TraitType(..) | DynTrait(..)
175                    | Array(..) | Slice(..) | FnPtr(..) | FnDef(..) | PtrMetadata(..)
176                    | Pattern(..) | Error(..) => {
177                        // Type error
178                        return None;
179                    }
180                }
181            }
182            Field(pkind, field_id) => {
183                // Lookup the type decl
184                use FieldProjKind::*;
185                match pkind {
186                    Adt(type_decl_id, variant_id) => {
187                        // Can fail if the type declaration was not translated.
188                        let type_decl = krate.type_decls.get(*type_decl_id)?;
189                        let tref = ty.as_adt()?;
190                        assert!(TypeId::Adt(*type_decl_id) == tref.id);
191                        use TypeDeclKind::*;
192                        match &type_decl.kind {
193                            Struct(fields) | Union(fields) => {
194                                if variant_id.is_some() {
195                                    return None;
196                                };
197                                fields.get(*field_id)?.ty.clone().substitute(&tref.generics)
198                            }
199                            Enum(variants) => {
200                                let variant_id = (*variant_id)?;
201                                let variant = variants.get(variant_id)?;
202                                variant
203                                    .fields
204                                    .get(*field_id)?
205                                    .ty
206                                    .clone()
207                                    .substitute(&tref.generics)
208                            }
209                            Opaque | Alias(_) | Error(_) => return None,
210                        }
211                    }
212                    Tuple(_) => ty
213                        .as_tuple()?
214                        .get(TypeVarId::from(usize::from(*field_id)))?
215                        .clone(),
216                }
217            }
218            PtrMetadata => ty.get_ptr_metadata(krate).into_type(),
219            Index { .. } | Subslice { .. } => ty.as_array_or_slice()?.clone(),
220        })
221    }
222}
223
224impl BinOp {
225    pub fn with_overflow(&self, overflow: OverflowMode) -> Self {
226        match self {
227            BinOp::Add(_) | BinOp::AddChecked => BinOp::Add(overflow),
228            BinOp::Sub(_) | BinOp::SubChecked => BinOp::Sub(overflow),
229            BinOp::Mul(_) | BinOp::MulChecked => BinOp::Mul(overflow),
230            BinOp::Div(_) => BinOp::Div(overflow),
231            BinOp::Rem(_) => BinOp::Rem(overflow),
232            BinOp::Shl(_) => BinOp::Shl(overflow),
233            BinOp::Shr(_) => BinOp::Shr(overflow),
234            _ => {
235                panic!(
236                    "Cannot set overflow mode for this binary operator: {:?}",
237                    self
238                );
239            }
240        }
241    }
242}
243
244impl UnOp {
245    pub fn with_overflow(&self, overflow: OverflowMode) -> Self {
246        match self {
247            UnOp::Neg(_) => UnOp::Neg(overflow),
248            _ => {
249                panic!(
250                    "Cannot set overflow mode for this unary operator: {:?}",
251                    self
252                );
253            }
254        }
255    }
256}
257
258impl FnPtr {
259    pub fn new(kind: FnPtrKind, generics: impl Into<BoxedArgs>) -> Self {
260        Self {
261            kind: Box::new(kind),
262            generics: generics.into(),
263        }
264    }
265
266    /// Get the generics for the pre-monomorphization item.
267    pub fn pre_mono_generics<'a>(&'a self, krate: &'a TranslatedCrate) -> &'a GenericArgs {
268        match *self.kind {
269            FnPtrKind::Fun(FunId::Regular(fun_id)) => krate
270                .item_name(fun_id)
271                .mono_args()
272                .unwrap_or(&self.generics),
273            //  We don't mono builtins.
274            FnPtrKind::Fun(FunId::Builtin(..)) => &self.generics,
275            // Can't happen in mono mode.
276            FnPtrKind::Trait(..) => &self.generics,
277        }
278    }
279}