creusot_contracts/ghost.rs
1//! Definitions for ghost code
2//!
3//! Ghost code is code that will be erased during the normal compilation of the program.
4//! To use ghost code in creusot, you must use the [`ghost!`] macro:
5//!
6//! ```
7//! # use creusot_contracts::prelude::*;
8//! let x: Ghost<i32> = ghost!(1);
9//! ghost! {
10//! let y: i32 = *x;
11//! assert!(y == 1);
12//! };
13//! ```
14//!
15//! There are restrictions on the values that can enter/exit a `ghost!` block: see
16//! [`Ghost`] and [`ghost!`] for more details.
17
18use crate::{logic::ops::Fin, prelude::*};
19use std::{
20 marker::PhantomData,
21 ops::{Deref, DerefMut},
22};
23
24mod fn_ghost;
25pub mod local_invariant;
26mod ptr_own;
27pub mod resource;
28pub use fn_ghost::{FnGhost, FnGhostWrapper};
29pub use ptr_own::PtrOwn;
30
31/// A type that can be used in [`ghost!`] context.
32///
33/// This type may be used to make more complicated proofs possible. In particular, some
34/// proof may need a notion of non-duplicable token to carry around.
35///
36/// Conceptually, a `Ghost<T>` is an object of type `T` that resides in a special "ghost"
37/// heap. This heap is inaccessible from normal code, and `Ghost` values cannot be used
38/// to influence the behavior of normal code.
39///
40/// This box can be accessed in a [`ghost!`] block:
41/// ```compile_fail
42/// let b: Ghost<i32> = Ghost::new(1);
43/// ghost! {
44/// let value: i32 = b.into_inner();
45/// // use value here
46/// }
47/// let value: i32 = b.into_inner(); // compile error !
48/// ```
49#[opaque]
50#[intrinsic("ghost")]
51
52pub struct Ghost<T: ?Sized>(PhantomData<T>);
53
54impl<T: Copy> Copy for Ghost<T> {}
55
56// FIXME: we would like to have an instance that does not require T: Copy, but it would
57// require the underlying clone instance to be #[check(ghost)], which we cannot require in general
58impl<T: Clone + Copy> Clone for Ghost<T> {
59 #[check(ghost)]
60 #[ensures(result == *self)]
61 fn clone(&self) -> Self {
62 ghost!(**self)
63 }
64}
65
66impl<T: ?Sized> Deref for Ghost<T> {
67 type Target = T;
68
69 /// This function can only be called in `ghost!` context
70 #[trusted]
71 #[check(ghost)]
72 #[requires(false)] // If called from generic context, false precondition
73 #[ensures(result == &**self)]
74 #[intrinsic("ghost_deref")]
75 fn deref(&self) -> &Self::Target {
76 panic!()
77 }
78}
79impl<T: ?Sized> DerefMut for Ghost<T> {
80 /// This function can only be called in `ghost!` context
81 #[trusted]
82 #[check(ghost)]
83 #[requires(false)] // If called from generic context, false precondition
84 #[ensures(result == &mut **self)]
85 #[intrinsic("ghost_deref_mut")]
86 fn deref_mut(&mut self) -> &mut Self::Target {
87 panic!()
88 }
89}
90
91impl<T: ?Sized + Fin> Fin for Ghost<T> {
92 type Target = T::Target;
93
94 #[logic(open, prophetic, inline)]
95 fn fin<'a>(self) -> &'a Self::Target {
96 pearlite! { &^*self }
97 }
98}
99
100impl<T: ?Sized> Invariant for Ghost<T> {
101 #[logic(open, prophetic, inline)]
102 #[creusot::trusted_trivial_if_param_trivial]
103 fn invariant(self) -> bool {
104 inv(*self)
105 }
106}
107
108impl<T: ?Sized> Ghost<T> {
109 /// Transforms a `&Ghost<T>` into `Ghost<&T>`
110 #[trusted]
111 #[erasure(_)]
112 #[check(ghost)]
113 #[ensures(**result == **self)]
114 pub fn borrow(&self) -> Ghost<&T> {
115 Ghost::conjure()
116 }
117
118 /// Transforms a `&mut Ghost<T>` into a `Ghost<&mut T>`.
119 #[trusted]
120 #[erasure(_)]
121 #[check(ghost)]
122 #[ensures(*result == &mut **self)]
123 pub fn borrow_mut(&mut self) -> Ghost<&mut T> {
124 Ghost::conjure()
125 }
126
127 /// Conjures a `Ghost<T>` out of thin air.
128 ///
129 /// This would be unsound in verified code, hence the `false` precondition.
130 /// This function is nevertheless useful to create a `Ghost` in "trusted"
131 /// contexts, when axiomatizing an API that is believed to be sound for
132 /// external reasons.
133 #[trusted]
134 #[erasure(_)]
135 #[check(ghost)]
136 #[requires(false)]
137 pub fn conjure() -> Self {
138 Ghost(PhantomData)
139 }
140
141 // Internal function to easily create a `Ghost` in non-creusot mode.
142 #[cfg(not(creusot))]
143 #[doc(hidden)]
144 pub fn from_fn(_: impl FnOnce() -> T) -> Self {
145 Ghost::conjure()
146 }
147}
148
149impl<T: ?Sized> Ghost<T> {
150 /// Creates a new ghost variable.
151 ///
152 /// This function can only be called in `ghost!` code.
153 #[trusted]
154 #[check(ghost)]
155 #[ensures(*result == x)]
156 #[intrinsic("ghost_new")]
157 pub fn new(x: T) -> Self
158 where
159 T: Sized,
160 {
161 let _ = x;
162 panic!()
163 }
164
165 #[trusted]
166 #[logic(opaque)]
167 #[ensures(*result == x)]
168 pub fn new_logic(x: T) -> Self {
169 dead
170 }
171
172 /// Returns the inner value of the `Ghost`.
173 ///
174 /// This function can only be called in `ghost!` context.
175 #[trusted]
176 #[check(ghost)]
177 #[ensures(result == *self)]
178 #[intrinsic("ghost_into_inner")]
179 pub fn into_inner(self) -> T
180 where
181 T: Sized,
182 {
183 panic!()
184 }
185
186 /// Returns the inner value of the `Ghost`.
187 ///
188 /// You should prefer the dereference operator `*` instead.
189 #[logic]
190 #[builtin("identity")]
191 pub fn inner_logic(self) -> T
192 where
193 T: Sized,
194 {
195 dead
196 }
197}
198
199impl<T, U: ?Sized> Ghost<(T, U)> {
200 #[check(ghost)]
201 #[trusted]
202 #[erasure(_)]
203 #[ensures((*self).0 == *result.0)]
204 #[ensures((*self).1 == *result.1)]
205 pub fn split(self) -> (Ghost<T>, Ghost<U>) {
206 (Ghost::conjure(), Ghost::conjure())
207 }
208}
209
210/// A marker trait for types that can be extracted from snapshots in ghost code.
211/// These are type that only contain plain data and whose onership does not convey
212/// any additional information.
213///
214/// For example, Booleans and integers are plain, but references are not, be they
215/// mutable or not. Indeed, the ownership of a shared reference can be used to deduce
216/// facts, for example with `PtrOwn::disjoint_lemma`.
217#[trusted]
218pub trait Plain: Copy {}
219
220#[trusted]
221impl Plain for bool {}
222
223#[trusted]
224impl<T> Plain for *const T {}
225
226#[trusted]
227impl<T> Plain for *mut T {}