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 ty(&self) -> &Ty {
14        &self.ty
15    }
16
17    /// Whether this place corresponds to a local variable without any projections.
18    pub fn is_local(&self) -> bool {
19        self.as_local().is_some()
20    }
21
22    /// If this place corresponds to an unprojected local, return the variable id.
23    pub fn as_local(&self) -> Option<LocalId> {
24        self.kind.as_local().copied()
25    }
26
27    pub fn as_projection(&self) -> Option<(&Self, &ProjectionElem)> {
28        self.kind.as_projection().map(|(pl, pj)| (pl.as_ref(), pj))
29    }
30
31    #[deprecated(note = "use `local_id` instead")]
32    pub fn var_id(&self) -> LocalId {
33        self.local_id()
34    }
35    pub fn local_id(&self) -> LocalId {
36        match &self.kind {
37            PlaceKind::Local(var_id) => *var_id,
38            PlaceKind::Projection(subplace, _) => subplace.local_id(),
39        }
40    }
41
42    pub fn project(self, elem: ProjectionElem, ty: Ty) -> Self {
43        Self {
44            kind: PlaceKind::Projection(Box::new(self), elem),
45            ty,
46        }
47    }
48
49    pub fn projections<'a>(&'a self) -> impl Iterator<Item = &'a ProjectionElem> {
50        let mut place = self;
51        std::iter::from_fn(move || {
52            let (new_place, proj) = place.as_projection()?;
53            place = new_place;
54            Some(proj)
55        })
56    }
57}
58
59impl Rvalue {
60    pub fn unit_value() -> Self {
61        Rvalue::Aggregate(
62            AggregateKind::Adt(
63                TypeId::Tuple,
64                None,
65                None,
66                Box::new(GenericArgs::empty(GenericsSource::Builtin)),
67            ),
68            Vec::new(),
69        )
70    }
71}
72
73impl BorrowKind {
74    pub fn mutable(x: bool) -> Self {
75        if x {
76            Self::Mut
77        } else {
78            Self::Shared
79        }
80    }
81}
82
83impl ProjectionElem {
84    /// Compute the type obtained when applying the current projection to a place of type `ty`.
85    pub fn project_type(
86        &self,
87        type_decls: &Vector<TypeDeclId, TypeDecl>,
88        ty: &Ty,
89    ) -> Result<Ty, ()> {
90        use ProjectionElem::*;
91        Ok(match self {
92            Deref => {
93                use TyKind::*;
94                match ty.kind() {
95                    Ref(_, ty, _) | RawPtr(ty, _) => ty.clone(),
96                    Adt(TypeId::Builtin(BuiltinTy::Box), args) => {
97                        args.types.get(TypeVarId::new(0)).unwrap().clone()
98                    }
99                    Adt(..)
100                    | TypeVar(_)
101                    | Literal(_)
102                    | Never
103                    | TraitType(..)
104                    | DynTrait(_)
105                    | Arrow(..)
106                    | Closure { .. }
107                    | Error(..) => {
108                        // Type error
109                        return Err(());
110                    }
111                }
112            }
113            Field(pkind, field_id) => {
114                // Lookup the type decl
115                use FieldProjKind::*;
116                match pkind {
117                    Adt(type_decl_id, variant_id) => {
118                        // Can fail if the type declaration was not translated.
119                        let type_decl = type_decls.get(*type_decl_id).ok_or(())?;
120                        let (type_id, generics) = ty.as_adt().ok_or(())?;
121                        assert!(TypeId::Adt(*type_decl_id) == type_id);
122                        use TypeDeclKind::*;
123                        match &type_decl.kind {
124                            Struct(fields) | Union(fields) => {
125                                if variant_id.is_some() {
126                                    return Err(());
127                                };
128                                fields
129                                    .get(*field_id)
130                                    .ok_or(())?
131                                    .ty
132                                    .clone()
133                                    .substitute(generics)
134                            }
135                            Enum(variants) => {
136                                let variant_id = variant_id.ok_or(())?;
137                                let variant = variants.get(variant_id).ok_or(())?;
138                                variant
139                                    .fields
140                                    .get(*field_id)
141                                    .ok_or(())?
142                                    .ty
143                                    .clone()
144                                    .substitute(generics)
145                            }
146                            Opaque | Alias(_) | Error(_) => return Err(()),
147                        }
148                    }
149                    Tuple(_) => ty
150                        .as_tuple()
151                        .ok_or(())?
152                        .get(TypeVarId::from(usize::from(*field_id)))
153                        .ok_or(())?
154                        .clone(),
155                    ClosureState => return Err(()),
156                }
157            }
158            Index { .. } | Subslice { .. } => ty.as_array_or_slice().ok_or(())?.clone(),
159        })
160    }
161}