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 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
//! 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 Rvalue {
pub fn unit_value() -> Self {
Rvalue::Aggregate(
AggregateKind::Adt(
TypeId::Tuple,
None,
None,
GenericArgs::empty(GenericsSource::Builtin),
),
Vec::new(),
)
}
}
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.elem_count()
== type_decl.generics.regions.elem_count()
);
assert!(
generics.types.elem_count() == type_decl.generics.types.elem_count()
);
assert!(
generics.const_generics.elem_count()
== type_decl.generics.const_generics.elem_count()
);
assert!(
generics.trait_refs.elem_count()
== type_decl.generics.trait_clauses.elem_count()
);
use TypeDeclKind::*;
match &type_decl.kind {
Struct(fields) | Union(fields) => {
if variant_id.is_some() {
return Err(());
};
fields
.get(*field_id)
.ok_or(())?
.ty
.clone()
.substitute(generics)
}
Enum(variants) => {
let variant_id = variant_id.ok_or(())?;
let variant = variants.get(variant_id).ok_or(())?;
variant
.fields
.get(*field_id)
.ok_or(())?
.ty
.clone()
.substitute(generics)
}
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(),
})
}
}