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