charon_lib/ast/expressions_utils.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
//! This file groups everything which is linked to implementations about [crate::expressions]
use crate::ast::*;
use crate::ids::Vector;
impl Place {
pub fn new(var_id: VarId, ty: Ty) -> Place {
Place {
kind: PlaceKind::Base(var_id),
ty,
}
}
pub fn ty(&self) -> &Ty {
&self.ty
}
/// Whether this place corresponds to a local variable without any projections.
pub fn is_local(&self) -> bool {
self.as_local().is_some()
}
/// If this place corresponds to an unprojected local, return the variable id.
pub fn as_local(&self) -> Option<VarId> {
self.kind.as_base().copied()
}
pub fn as_projection(&self) -> Option<(&Self, &ProjectionElem)> {
self.kind.as_projection().map(|(pl, pj)| (pl.as_ref(), pj))
}
pub fn var_id(&self) -> VarId {
match &self.kind {
PlaceKind::Base(var_id) => *var_id,
PlaceKind::Projection(subplace, _) => subplace.var_id(),
}
}
pub fn project(self, elem: ProjectionElem, ty: Ty) -> Self {
Self {
kind: PlaceKind::Projection(Box::new(self), elem),
ty,
}
}
}
impl BorrowKind {
pub fn mutable(x: bool) -> Self {
if x {
Self::Mut
} else {
Self::Shared
}
}
}
impl ProjectionElem {
/// Compute the type obtained when applying the current projection to a place of type `ty`.
pub fn project_type(
&self,
type_decls: &Vector<TypeDeclId, TypeDecl>,
ty: &Ty,
) -> Result<Ty, ()> {
use ProjectionElem::*;
Ok(match self {
Deref => {
use TyKind::*;
match ty.kind() {
Ref(_, ty, _) | RawPtr(ty, _) => ty.clone(),
Adt(TypeId::Builtin(BuiltinTy::Box), args) => {
args.types.get(TypeVarId::new(0)).unwrap().clone()
}
Adt(..) | TypeVar(_) | Literal(_) | Never | TraitType(..) | DynTrait(_)
| Arrow(..) => {
// Type error
return Err(());
}
}
}
Field(pkind, field_id) => {
// Lookup the type decl
use FieldProjKind::*;
match pkind {
Adt(type_decl_id, variant_id) => {
// Can fail if the type declaration was not translated.
let type_decl = type_decls.get(*type_decl_id).ok_or(())?;
let (type_id, generics) = ty.as_adt().ok_or(())?;
assert!(TypeId::Adt(*type_decl_id) == type_id);
assert!(generics.regions.len() == type_decl.generics.regions.len());
assert!(generics.types.len() == type_decl.generics.types.len());
assert!(
generics.const_generics.len()
== type_decl.generics.const_generics.len()
);
assert!(
generics.trait_refs.len() == type_decl.generics.trait_clauses.len()
);
use TypeDeclKind::*;
match &type_decl.kind {
Struct(fields) | Union(fields) => {
if variant_id.is_some() {
return Err(());
};
let mut ty = fields.get(*field_id).ok_or(())?.ty.clone();
ty.substitute(generics);
ty
}
Enum(variants) => {
let variant_id = variant_id.ok_or(())?;
let variant = variants.get(variant_id).ok_or(())?;
let mut ty = variant.fields.get(*field_id).ok_or(())?.ty.clone();
ty.substitute(generics);
ty
}
Opaque | Alias(_) | Error(_) => return Err(()),
}
}
Tuple(_) => ty
.as_tuple()
.ok_or(())?
.get(TypeVarId::from(usize::from(*field_id)))
.ok_or(())?
.clone(),
ClosureState => return Err(()),
}
}
Index { .. } | Subslice { .. } => ty.as_array_or_slice().ok_or(())?.clone(),
})
}
}