charon_lib/ast/
expressions_utils.rs1use 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 pub fn is_local(&self) -> bool {
19 self.as_local().is_some()
20 }
21
22 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 project_auto_ty(
50 self,
51 type_decls: &Vector<TypeDeclId, TypeDecl>,
52 proj: ProjectionElem,
53 ) -> Result<Self, ()> {
54 Ok(Place {
55 ty: proj.project_type(type_decls, &self.ty)?,
56 kind: PlaceKind::Projection(Box::new(self), proj),
57 })
58 }
59
60 pub fn deref(self) -> Place {
62 use TyKind::*;
63 let proj_ty = match self.ty.kind() {
64 Ref(_, ty, _) | RawPtr(ty, _) => ty.clone(),
65 Adt(tref) if matches!(tref.id, TypeId::Builtin(BuiltinTy::Box)) => {
66 tref.generics.types[0].clone()
67 }
68 Adt(..) | TypeVar(_) | Literal(_) | Never | TraitType(..) | DynTrait(_) | FnPtr(..)
69 | FnDef(..) | Error(..) => panic!("internal type error"),
70 };
71 Place {
72 ty: proj_ty,
73 kind: PlaceKind::Projection(Box::new(self), ProjectionElem::Deref),
74 }
75 }
76
77 pub fn projections<'a>(&'a self) -> impl Iterator<Item = &'a ProjectionElem> {
78 let mut place = self;
79 std::iter::from_fn(move || {
80 let (new_place, proj) = place.as_projection()?;
81 place = new_place;
82 Some(proj)
83 })
84 }
85}
86
87impl Rvalue {
88 pub fn unit_value() -> Self {
89 Rvalue::Aggregate(
90 AggregateKind::Adt(
91 TypeDeclRef {
92 id: TypeId::Tuple,
93 generics: Box::new(GenericArgs::empty()),
94 },
95 None,
96 None,
97 ),
98 Vec::new(),
99 )
100 }
101}
102
103impl BorrowKind {
104 pub fn mutable(x: bool) -> Self {
105 if x { Self::Mut } else { Self::Shared }
106 }
107}
108
109impl ProjectionElem {
110 pub fn project_type(
112 &self,
113 type_decls: &Vector<TypeDeclId, TypeDecl>,
114 ty: &Ty,
115 ) -> Result<Ty, ()> {
116 use ProjectionElem::*;
117 Ok(match self {
118 Deref => {
119 use TyKind::*;
120 match ty.kind() {
121 Ref(_, ty, _) | RawPtr(ty, _) => ty.clone(),
122 Adt(tref) if matches!(tref.id, TypeId::Builtin(BuiltinTy::Box)) => {
123 tref.generics.types[0].clone()
124 }
125 Adt(..) | TypeVar(_) | Literal(_) | Never | TraitType(..) | DynTrait(_)
126 | FnPtr(..) | FnDef(..) | Error(..) => {
127 return Err(());
129 }
130 }
131 }
132 Field(pkind, field_id) => {
133 use FieldProjKind::*;
135 match pkind {
136 Adt(type_decl_id, variant_id) => {
137 let type_decl = type_decls.get(*type_decl_id).ok_or(())?;
139 let tref = ty.as_adt().ok_or(())?;
140 assert!(TypeId::Adt(*type_decl_id) == tref.id);
141 use TypeDeclKind::*;
142 match &type_decl.kind {
143 Struct(fields) | Union(fields) => {
144 if variant_id.is_some() {
145 return Err(());
146 };
147 fields
148 .get(*field_id)
149 .ok_or(())?
150 .ty
151 .clone()
152 .substitute(&tref.generics)
153 }
154 Enum(variants) => {
155 let variant_id = variant_id.ok_or(())?;
156 let variant = variants.get(variant_id).ok_or(())?;
157 variant
158 .fields
159 .get(*field_id)
160 .ok_or(())?
161 .ty
162 .clone()
163 .substitute(&tref.generics)
164 }
165 Opaque | Alias(_) | Error(_) => return Err(()),
166 }
167 }
168 Tuple(_) => ty
169 .as_tuple()
170 .ok_or(())?
171 .get(TypeVarId::from(usize::from(*field_id)))
172 .ok_or(())?
173 .clone(),
174 }
175 }
176 Index { .. } | Subslice { .. } => ty.as_array_or_slice().ok_or(())?.clone(),
177 })
178 }
179}
180
181impl From<ConstGeneric> for RawConstantExpr {
182 fn from(cg: ConstGeneric) -> Self {
183 match cg {
184 ConstGeneric::Global(id) => RawConstantExpr::Global(GlobalDeclRef {
185 id,
186 generics: Box::new(GenericArgs::empty()),
187 }),
188 ConstGeneric::Var(var) => RawConstantExpr::Var(var),
189 ConstGeneric::Value(lit) => RawConstantExpr::Literal(lit),
190 }
191 }
192}
193
194impl BinOp {
195 pub fn with_overflow(&self, overflow: OverflowMode) -> Self {
196 match self {
197 BinOp::Add(_) | BinOp::AddChecked => BinOp::Add(overflow),
198 BinOp::Sub(_) | BinOp::SubChecked => BinOp::Sub(overflow),
199 BinOp::Mul(_) | BinOp::MulChecked => BinOp::Mul(overflow),
200 BinOp::Div(_) => BinOp::Div(overflow),
201 BinOp::Rem(_) => BinOp::Rem(overflow),
202 BinOp::Shl(_) => BinOp::Shl(overflow),
203 BinOp::Shr(_) => BinOp::Shr(overflow),
204 _ => {
205 panic!(
206 "Cannot set overflow mode for this binary operator: {:?}",
207 self
208 );
209 }
210 }
211 }
212}
213
214impl UnOp {
215 pub fn with_overflow(&self, overflow: OverflowMode) -> Self {
216 match self {
217 UnOp::Neg(_) => UnOp::Neg(overflow),
218 _ => {
219 panic!(
220 "Cannot set overflow mode for this unary operator: {:?}",
221 self
222 );
223 }
224 }
225 }
226}