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
50impl Rvalue {
51    pub fn unit_value() -> Self {
52        Rvalue::Aggregate(
53            AggregateKind::Adt(
54                TypeId::Tuple,
55                None,
56                None,
57                GenericArgs::empty(GenericsSource::Builtin),
58            ),
59            Vec::new(),
60        )
61    }
62}
63
64impl BorrowKind {
65    pub fn mutable(x: bool) -> Self {
66        if x {
67            Self::Mut
68        } else {
69            Self::Shared
70        }
71    }
72}
73
74impl ProjectionElem {
75    /// Compute the type obtained when applying the current projection to a place of type `ty`.
76    pub fn project_type(
77        &self,
78        type_decls: &Vector<TypeDeclId, TypeDecl>,
79        ty: &Ty,
80    ) -> Result<Ty, ()> {
81        use ProjectionElem::*;
82        Ok(match self {
83            Deref => {
84                use TyKind::*;
85                match ty.kind() {
86                    Ref(_, ty, _) | RawPtr(ty, _) => ty.clone(),
87                    Adt(TypeId::Builtin(BuiltinTy::Box), args) => {
88                        args.types.get(TypeVarId::new(0)).unwrap().clone()
89                    }
90                    Adt(..) | TypeVar(_) | Literal(_) | Never | TraitType(..) | DynTrait(_)
91                    | Arrow(..) | Error(..) => {
92                        // Type error
93                        return Err(());
94                    }
95                }
96            }
97            Field(pkind, field_id) => {
98                // Lookup the type decl
99                use FieldProjKind::*;
100                match pkind {
101                    Adt(type_decl_id, variant_id) => {
102                        // Can fail if the type declaration was not translated.
103                        let type_decl = type_decls.get(*type_decl_id).ok_or(())?;
104                        let (type_id, generics) = ty.as_adt().ok_or(())?;
105                        assert!(TypeId::Adt(*type_decl_id) == type_id);
106                        assert!(
107                            generics.regions.elem_count()
108                                == type_decl.generics.regions.elem_count()
109                        );
110                        assert!(
111                            generics.types.elem_count() == type_decl.generics.types.elem_count()
112                        );
113                        assert!(
114                            generics.const_generics.elem_count()
115                                == type_decl.generics.const_generics.elem_count()
116                        );
117                        assert!(
118                            generics.trait_refs.elem_count()
119                                == type_decl.generics.trait_clauses.elem_count()
120                        );
121                        use TypeDeclKind::*;
122                        match &type_decl.kind {
123                            Struct(fields) | Union(fields) => {
124                                if variant_id.is_some() {
125                                    return Err(());
126                                };
127                                fields
128                                    .get(*field_id)
129                                    .ok_or(())?
130                                    .ty
131                                    .clone()
132                                    .substitute(generics)
133                            }
134                            Enum(variants) => {
135                                let variant_id = variant_id.ok_or(())?;
136                                let variant = variants.get(variant_id).ok_or(())?;
137                                variant
138                                    .fields
139                                    .get(*field_id)
140                                    .ok_or(())?
141                                    .ty
142                                    .clone()
143                                    .substitute(generics)
144                            }
145                            Opaque | Alias(_) | Error(_) => return Err(()),
146                        }
147                    }
148                    Tuple(_) => ty
149                        .as_tuple()
150                        .ok_or(())?
151                        .get(TypeVarId::from(usize::from(*field_id)))
152                        .ok_or(())?
153                        .clone(),
154                    ClosureState => return Err(()),
155                }
156            }
157            Index { .. } | Subslice { .. } => ty.as_array_or_slice().ok_or(())?.clone(),
158        })
159    }
160}