charon_lib/ast/gast.rs
1//! Definitions common to [crate::ullbc_ast] and [crate::llbc_ast]
2use crate::ast::*;
3use crate::ids::IndexMap;
4use crate::ids::IndexVec;
5use crate::llbc_ast;
6use crate::ullbc_ast;
7use derive_generic_visitor::{Drive, DriveMut};
8use macros::EnumAsGetters;
9use macros::{EnumIsA, EnumToGetters};
10use serde_state::DeserializeState;
11use serde_state::SerializeState;
12
13/// A variable
14#[derive(Debug, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
15pub struct Local {
16 /// Unique index identifying the variable
17 pub index: LocalId,
18 /// Variable name - may be `None` if the variable was introduced by Rust
19 /// through desugaring.
20 #[drive(skip)]
21 pub name: Option<String>,
22 /// The variable type
23 #[charon::rename("local_ty")]
24 pub ty: Ty,
25}
26#[deprecated(note = "use `Local` intead")]
27pub type Var = Local;
28#[deprecated(note = "use `LocalId` intead")]
29pub type VarId = LocalId;
30
31/// The local variables of a body.
32#[derive(Debug, Default, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
33pub struct Locals {
34 /// The number of local variables used for the input arguments.
35 #[drive(skip)]
36 pub arg_count: usize,
37 /// The local variables.
38 /// We always have, in the following order:
39 /// - the local used for the return value (index 0)
40 /// - the `arg_count` input arguments
41 /// - the remaining locals, used for the intermediate computations
42 pub locals: IndexVec<LocalId, Local>,
43}
44
45/// An expression body.
46/// TODO: arg_count should be stored in GFunDecl below. But then,
47/// the print is obfuscated and Aeneas may need some refactoring.
48#[derive(Debug, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
49#[charon::rename("GexprBody")]
50pub struct GExprBody<T> {
51 pub span: Span,
52 /// The number of regions existentially bound in this body. We introduce fresh such regions
53 /// during translation instead of the erased regions that rustc gives us.
54 #[drive(skip)]
55 pub bound_body_regions: usize,
56 /// The local variables.
57 pub locals: Locals,
58 /// The statements and blocks that compose this body.
59 pub body: T,
60 /// For each line inside the body, we record any whole-line `//` comments found before it. They
61 /// are added to statements in the late `recover_body_comments` pass.
62 #[charon::opaque]
63 #[drive(skip)]
64 pub comments: Vec<(usize, Vec<String>)>,
65}
66
67/// The body of a function.
68#[derive(
69 Debug,
70 Clone,
71 SerializeState,
72 DeserializeState,
73 Drive,
74 DriveMut,
75 EnumIsA,
76 EnumAsGetters,
77 EnumToGetters,
78)]
79pub enum Body {
80 /// Body represented as a CFG. This is what ullbc is made of, and what we get after translating MIR.
81 Unstructured(ullbc_ast::ExprBody),
82 /// Body represented with structured control flow. This is what llbc is made of. We restructure
83 /// the control flow in the `ullbc_to_llbc` pass.
84 Structured(llbc_ast::ExprBody),
85 /// The body of the function item we add for each trait method declaration, if the trait
86 /// doesn't provide a default for that method.
87 TraitMethodWithoutDefault,
88 /// A body that the user chose not to translate, based on opacity settings like
89 /// `--include`/`--opaque`.
90 Opaque,
91 /// A body that was not available. Typically that's function bodies for non-generic and
92 /// non-inlineable std functions, as these are not present in the compiled standard library
93 /// `.rmeta` file shipped with a rust toolchain.
94 Missing,
95 /// We encountered an error while translating this body.
96 #[drive(skip)]
97 #[serde_state(stateless)]
98 Error(Error),
99}
100
101/// Item kind: whether this function/const is part of a trait declaration, trait implementation, or
102/// neither.
103///
104/// Example:
105/// ```text
106/// trait Foo {
107/// fn bar(x : u32) -> u32; // trait item decl without default
108///
109/// fn baz(x : bool) -> bool { x } // trait item decl with default
110/// }
111///
112/// impl Foo for ... {
113/// fn bar(x : u32) -> u32 { x } // trait item implementation
114/// }
115///
116/// fn test(...) { ... } // regular
117///
118/// impl Type {
119/// fn test(...) { ... } // regular
120/// }
121/// ```
122#[derive(Debug, Clone, SerializeState, DeserializeState, Drive, DriveMut, PartialEq, Eq)]
123#[charon::variants_suffix("Item")]
124pub enum ItemSource {
125 /// This item stands on its own.
126 TopLevel,
127 /// This is a closure in a function body.
128 Closure { info: ClosureInfo },
129 /// This is an associated item in a trait declaration. It has a body if and only if the trait
130 /// provided a default implementation.
131 TraitDecl {
132 /// The trait declaration this item belongs to.
133 trait_ref: TraitDeclRef,
134 /// The name of the item.
135 // TODO: also include method generics so we can recover a full `FnPtr::TraitMethod`
136 #[drive(skip)]
137 item_name: TraitItemName,
138 /// Whether the trait declaration provides a default implementation.
139 #[drive(skip)]
140 has_default: bool,
141 },
142 /// This is an associated item in a trait implementation.
143 TraitImpl {
144 /// The trait implementation the method belongs to.
145 impl_ref: TraitImplRef,
146 /// The trait declaration that the impl block implements.
147 trait_ref: TraitDeclRef,
148 /// The name of the item
149 // TODO: also include method generics so we can recover a full `FnPtr::TraitMethod`
150 #[drive(skip)]
151 item_name: TraitItemName,
152 /// True if the trait decl had a default implementation for this function/const and this
153 /// item is a copy of the default item.
154 #[drive(skip)]
155 reuses_default: bool,
156 },
157 /// This is a vtable struct for a trait.
158 VTableTy {
159 /// The `dyn Trait` predicate implemented by this vtable.
160 dyn_predicate: DynPredicate,
161 /// Record what each vtable field means.
162 field_map: IndexVec<FieldId, VTableField>,
163 /// For each implied clause that is also a supertrait clause, reords which field id
164 /// corresponds to it.
165 supertrait_map: IndexMap<TraitClauseId, Option<FieldId>>,
166 },
167 /// This is a vtable value for an impl.
168 VTableInstance { impl_ref: TraitImplRef },
169 /// The method shim wraps a concrete implementation of a method into a function that takes `dyn
170 /// Trait` as its `Self` type. This shim casts the receiver to the known concrete type and
171 /// calls the real method.
172 VTableMethodShim,
173}
174
175#[derive(Debug, Clone, SerializeState, DeserializeState, Drive, DriveMut, PartialEq, Eq)]
176#[charon::variants_prefix("VTable")]
177pub enum VTableField {
178 Size,
179 Align,
180 Drop,
181 Method(TraitItemName),
182 SuperTrait(TraitClauseId),
183}
184
185/// A function definition
186#[derive(Debug, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
187pub struct FunDecl {
188 #[drive(skip)]
189 pub def_id: FunDeclId,
190 /// The meta data associated with the declaration.
191 pub item_meta: ItemMeta,
192 pub generics: GenericParams,
193 /// The signature contains the inputs/output types *with* non-erased regions.
194 /// It also contains the list of region and type parameters.
195 pub signature: FunSig,
196 /// The function kind: "regular" function, trait method declaration, etc.
197 pub src: ItemSource,
198 /// Whether this function is in fact the body of a constant/static that we turned into an
199 /// initializer function.
200 pub is_global_initializer: Option<GlobalDeclId>,
201 /// The function body, unless the function is opaque.
202 /// Opaque functions are: external functions, or local functions tagged
203 /// as opaque.
204 pub body: Body,
205}
206
207/// Reference to a function declaration.
208#[derive(Debug, Clone, SerializeState, DeserializeState, PartialEq, Eq, Hash, Drive, DriveMut)]
209pub struct FunDeclRef {
210 pub id: FunDeclId,
211 /// Generic arguments passed to the function.
212 pub generics: BoxedArgs,
213}
214
215#[derive(Debug, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
216pub enum GlobalKind {
217 /// A static.
218 Static,
219 /// A const with a name (either top-level or an associated const in a trait).
220 NamedConst,
221 /// A const without a name:
222 /// - An inline const expression (`const { 1 + 1 }`);
223 /// - A const expression in a type (`[u8; sizeof::<T>()]`);
224 /// - A promoted constant, automatically lifted from a body (`&0`).
225 AnonConst,
226}
227
228/// A global variable definition (constant or static).
229#[derive(Debug, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
230pub struct GlobalDecl {
231 #[drive(skip)]
232 pub def_id: GlobalDeclId,
233 /// The meta data associated with the declaration.
234 pub item_meta: ItemMeta,
235 pub generics: GenericParams,
236 pub ty: Ty,
237 /// The context of the global: distinguishes top-level items from trait-associated items.
238 pub src: ItemSource,
239 /// The kind of global (static or const).
240 #[drive(skip)]
241 pub global_kind: GlobalKind,
242 /// The initializer function used to compute the initial value for this constant/static. It
243 /// uses the same generic parameters as the global.
244 pub init: FunDeclId,
245}
246
247/// Reference to a global declaration.
248#[derive(Debug, Clone, SerializeState, DeserializeState, PartialEq, Eq, Hash, Drive, DriveMut)]
249pub struct GlobalDeclRef {
250 pub id: GlobalDeclId,
251 pub generics: BoxedArgs,
252}
253
254#[derive(
255 Debug,
256 Clone,
257 Copy,
258 SerializeState,
259 DeserializeState,
260 Drive,
261 DriveMut,
262 PartialEq,
263 Eq,
264 Hash,
265 PartialOrd,
266 Ord,
267)]
268#[drive(skip)]
269#[serde_state(stateless)]
270pub struct TraitItemName(pub ustr::Ustr);
271
272/// A trait **declaration**.
273///
274/// For instance:
275/// ```text
276/// trait Foo {
277/// type Bar;
278///
279/// fn baz(...); // required method (see below)
280///
281/// fn test() -> bool { true } // provided method (see below)
282/// }
283/// ```
284///
285/// In case of a trait declaration, we don't include the provided methods (the methods
286/// with a default implementation): they will be translated on a per-need basis. This is
287/// important for two reasons:
288/// - this makes the trait definitions a lot smaller (the Iterator trait
289/// has *one* declared function and more than 70 provided functions)
290/// - this is important for the external traits, whose provided methods
291/// often use features we don't support yet
292///
293/// Remark:
294/// In Aeneas, we still translate the provided methods on an individual basis,
295/// and in such a way thay they take as input a trait instance. This means that
296/// we can use default methods *but*:
297/// - implementations of required methods shoudln't call default methods
298/// - trait implementations shouldn't redefine required methods
299/// The use case we have in mind is [std::iter::Iterator]: it declares one required
300/// method (`next`) that should be implemented for every iterator, and defines many
301/// helpers like `all`, `map`, etc. that shouldn't be re-implemented.
302/// Of course, this forbids other useful use cases such as visitors implemented
303/// by means of traits.
304#[allow(clippy::type_complexity)]
305#[derive(Debug, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
306pub struct TraitDecl {
307 #[drive(skip)]
308 pub def_id: TraitDeclId,
309 pub item_meta: ItemMeta,
310 pub generics: GenericParams,
311 /// The "parent" clauses: the supertraits.
312 ///
313 /// Supertraits are actually regular where clauses, but we decided to have
314 /// a custom treatment.
315 /// ```text
316 /// trait Foo : Bar {
317 /// ^^^
318 /// supertrait, that we treat as a parent predicate
319 /// }
320 /// ```
321 /// TODO: actually, as of today, we consider that all trait clauses of
322 /// trait declarations are parent clauses.
323 pub implied_clauses: IndexMap<TraitClauseId, TraitParam>,
324 /// The associated constants declared in the trait.
325 pub consts: Vec<TraitAssocConst>,
326 /// The associated types declared in the trait. The binder binds the generic parameters of the
327 /// type if it is a GAT (Generic Associated Type). For a plain associated type the binder binds
328 /// nothing.
329 pub types: Vec<Binder<TraitAssocTy>>,
330 /// The methods declared by the trait. The binder binds the generic parameters of the method.
331 ///
332 /// ```rust
333 /// trait Trait<T> {
334 /// // The `Binder` for this method binds `'a` and `U`.
335 /// fn method<'a, U>(x: &'a U);
336 /// }
337 /// ```
338 pub methods: Vec<Binder<TraitMethod>>,
339 /// The virtual table struct for this trait, if it has one.
340 /// It is guaranteed that the trait has a vtable iff it is dyn-compatible.
341 pub vtable: Option<TypeDeclRef>,
342}
343
344/// An associated constant in a trait.
345#[derive(Debug, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
346pub struct TraitAssocConst {
347 pub name: TraitItemName,
348 pub ty: Ty,
349 pub default: Option<GlobalDeclRef>,
350}
351
352/// An associated type in a trait.
353#[derive(Debug, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
354pub struct TraitAssocTy {
355 pub name: TraitItemName,
356 pub default: Option<Ty>,
357 /// List of trait clauses that apply to this type.
358 pub implied_clauses: IndexMap<TraitClauseId, TraitParam>,
359}
360
361/// A trait method.
362#[derive(Debug, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
363pub struct TraitMethod {
364 pub name: TraitItemName,
365 /// Each method declaration is represented by a function item. That function contains the
366 /// signature of the method as well as information like attributes. It has a body iff the
367 /// method declaration has a default implementation; otherwise it has an `Opaque` body.
368 pub item: FunDeclRef,
369}
370
371/// A trait **implementation**.
372///
373/// For instance:
374/// ```text
375/// impl Foo for List {
376/// type Bar = ...
377///
378/// fn baz(...) { ... }
379/// }
380/// ```
381#[derive(Debug, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
382pub struct TraitImpl {
383 #[drive(skip)]
384 pub def_id: TraitImplId,
385 pub item_meta: ItemMeta,
386 /// The information about the implemented trait.
387 /// Note that this contains the instantiation of the "parent"
388 /// clauses.
389 pub impl_trait: TraitDeclRef,
390 pub generics: GenericParams,
391 /// The trait references for the parent clauses (see [TraitDecl]).
392 pub implied_trait_refs: IndexMap<TraitClauseId, TraitRef>,
393 /// The implemented associated constants.
394 pub consts: Vec<(TraitItemName, GlobalDeclRef)>,
395 /// The implemented associated types.
396 pub types: Vec<(TraitItemName, Binder<TraitAssocTyImpl>)>,
397 /// The implemented methods
398 pub methods: Vec<(TraitItemName, Binder<FunDeclRef>)>,
399 /// The virtual table instance for this trait implementation. This is `Some` iff the trait is
400 /// dyn-compatible.
401 pub vtable: Option<GlobalDeclRef>,
402}
403
404/// The value of a trait associated type.
405#[derive(Debug, Clone, PartialEq, Eq, Hash, SerializeState, DeserializeState, Drive, DriveMut)]
406pub struct TraitAssocTyImpl {
407 pub value: Ty,
408 /// This matches the corresponding vector in `TraitAssocTy`. In the same way, this is empty
409 /// after the `lift_associated_item_clauses` pass.
410 #[charon::opaque]
411 pub implied_trait_refs: IndexMap<TraitClauseId, TraitRef>,
412}
413
414/// A function operand is used in function calls.
415/// It either designates a top-level function, or a place in case
416/// we are using function pointers stored in local variables.
417#[derive(Debug, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
418#[charon::variants_prefix("FnOp")]
419pub enum FnOperand {
420 /// Regular case: call to a top-level function, trait method, etc.
421 Regular(FnPtr),
422 /// Use of a function pointer.
423 Dynamic(Operand),
424}
425
426#[derive(Debug, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
427pub struct Call {
428 pub func: FnOperand,
429 pub args: Vec<Operand>,
430 pub dest: Place,
431}
432
433#[derive(Debug, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
434pub struct CopyNonOverlapping {
435 pub src: Operand,
436 pub dst: Operand,
437 pub count: Operand,
438}
439
440/// The kind of a built-in assertion, which may panic and unwind. These are removed
441/// by `reconstruct_fallible_operations` because they're implicit in the semantics of (U)LLBC.
442/// This kind should only be used for error-reporting purposes, as the check itself
443/// is performed in the instructions preceding the assert.
444#[derive(Debug, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
445pub enum BuiltinAssertKind {
446 BoundsCheck { len: Operand, index: Operand },
447 Overflow(BinOp, Operand, Operand),
448 OverflowNeg(Operand),
449 DivisionByZero(Operand),
450 RemainderByZero(Operand),
451 MisalignedPointerDereference { required: Operand, found: Operand },
452 NullPointerDereference,
453 InvalidEnumConstruction(Operand),
454}
455
456/// (U)LLBC is a language with side-effects: a statement may abort in a way that isn't tracked by
457/// control-flow. The three kinds of abort are:
458/// - Panic
459/// - Undefined behavior (caused by an "assume")
460/// - Unwind termination
461#[derive(Debug, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
462pub enum AbortKind {
463 /// A built-in panicking function, or a panic due to a failed built-in check (e.g. for out-of-bounds accesses).
464 Panic(Option<Name>),
465 /// Undefined behavior in the rust abstract machine.
466 UndefinedBehavior,
467 /// Unwind had to stop for ABI reasons or because cleanup code panicked again.
468 UnwindTerminate,
469}
470
471/// A `Drop` statement/terminator can mean two things, depending on what MIR phase we retrieved
472/// from rustc: it could be a real drop, or it could be a "conditional drop", which is where drop
473/// may happen depending on whether the borrow-checker determines a drop is needed.
474#[derive(Debug, Clone, Copy, SerializeState, DeserializeState, Drive, DriveMut)]
475pub enum DropKind {
476 /// A real drop. This calls `<T as Destruct>::drop_in_place(&raw mut place)` and marks the
477 /// place as moved-out-of. Use `--desugar-drops` to transform all such drops to an actual
478 /// function call.
479 ///
480 /// The `drop_in_place` method is added by Charon to the `Destruct` trait to make it possible
481 /// to track drop code in polymorphic code. It contains the same code as the
482 /// `core::ptr::drop_in_place<T>` builtin would.
483 ///
484 /// Drop are precise in MIR `elaborated` and `optimized`.
485 Precise,
486 /// A conditional drop, which may or may not end up running drop code depending on the code
487 /// path that led to it. A conditional drop may also become a partial drop (dropping only the
488 /// subplaces that haven't been moved out of), may be conditional on the code path that led to
489 /// it, or become an async drop. The exact semantics are left intentionally unspecified by
490 /// rustc developers. To elaborate such drops into precise drops, pass `--precise-drops` to
491 /// Charon.
492 ///
493 /// A conditional drop may also be passed an unaligned place when dropping fields of packed
494 /// structs. Such a thing is UB for a precise drop.
495 ///
496 /// Drop are conditional in MIR `built` and `promoted`.
497 Conditional,
498}
499
500/// Check the value of an operand and abort if the value is not expected. This is introduced to
501/// avoid a lot of small branches.
502///
503/// We translate MIR asserts (introduced for out-of-bounds accesses or divisions by zero for
504/// instance) to this. We then eliminate them in [crate::transform::resugar::reconstruct_fallible_operations],
505/// because they're implicit in the semantics of our array accesses etc. Finally we introduce new asserts in
506/// [crate::transform::resugar::reconstruct_asserts].
507#[derive(Debug, Clone, SerializeState, DeserializeState, Drive, DriveMut)]
508#[charon::rename("Assertion")]
509pub struct Assert {
510 pub cond: Operand,
511 /// The value that the operand should evaluate to for the assert to succeed.
512 #[drive(skip)]
513 pub expected: bool,
514 /// The kind of check performed by this assert. This is only used for error reporting, as the check
515 /// is actually performed by the instructions preceding the assert.
516 pub check_kind: Option<BuiltinAssertKind>,
517}
518
519/// A generic `*DeclRef`-shaped struct, used when we're generic over the type of item.
520#[derive(Debug, Clone, Drive, DriveMut)]
521pub struct DeclRef<Id> {
522 pub id: Id,
523 pub generics: BoxedArgs,
524 /// If the item is a trait associated item, `generics` are only those of the item, and this
525 /// contains a reference to the trait.
526 pub trait_ref: Option<TraitRef>,
527}
528
529impl DeclRef<ItemId> {
530 pub fn try_convert_id<Id>(self) -> Result<DeclRef<Id>, <ItemId as TryInto<Id>>::Error>
531 where
532 ItemId: TryInto<Id>,
533 {
534 Ok(DeclRef {
535 id: self.id.try_into()?,
536 generics: self.generics,
537 trait_ref: self.trait_ref,
538 })
539 }
540}
541
542// Implement `DeclRef<_>` -> `FooDeclRef` conversions.
543macro_rules! convert_item_ref {
544 ($item_ref_ty:ident($id:ident)) => {
545 impl TryFrom<DeclRef<ItemId>> for $item_ref_ty {
546 type Error = ();
547 fn try_from(item: DeclRef<ItemId>) -> Result<Self, ()> {
548 assert!(item.trait_ref.is_none());
549 Ok($item_ref_ty {
550 id: item.id.try_into()?,
551 generics: item.generics,
552 })
553 }
554 }
555 impl From<DeclRef<$id>> for $item_ref_ty {
556 fn from(item: DeclRef<$id>) -> Self {
557 assert!(item.trait_ref.is_none());
558 $item_ref_ty {
559 id: item.id,
560 generics: item.generics,
561 }
562 }
563 }
564 };
565}
566convert_item_ref!(TypeDeclRef(TypeId));
567convert_item_ref!(FunDeclRef(FunDeclId));
568convert_item_ref!(GlobalDeclRef(GlobalDeclId));
569convert_item_ref!(TraitDeclRef(TraitDeclId));
570convert_item_ref!(TraitImplRef(TraitImplId));
571impl TryFrom<DeclRef<ItemId>> for FnPtr {
572 type Error = ();
573 fn try_from(item: DeclRef<ItemId>) -> Result<Self, ()> {
574 let id: FunId = item.id.try_into()?;
575 Ok(FnPtr::new(id.into(), item.generics))
576 }
577}
578
579impl TryFrom<DeclRef<ItemId>> for MaybeBuiltinFunDeclRef {
580 type Error = ();
581 fn try_from(item: DeclRef<ItemId>) -> Result<Self, ()> {
582 Ok(item.try_convert_id::<FunId>()?.into())
583 }
584}
585impl From<DeclRef<FunId>> for MaybeBuiltinFunDeclRef {
586 fn from(item: DeclRef<FunId>) -> Self {
587 MaybeBuiltinFunDeclRef {
588 id: item.id,
589 generics: item.generics,
590 trait_ref: item.trait_ref,
591 }
592 }
593}