Skip to main content

hax_lib/
implementation.rs

1mod abstraction;
2pub use abstraction::*;
3
4pub mod int;
5pub use int::*;
6
7pub mod prop;
8pub use prop::*;
9
10#[cfg(feature = "macros")]
11pub use crate::proc_macros::*;
12
13#[doc(hidden)]
14#[cfg(hax)]
15#[macro_export]
16macro_rules! proxy_macro_if_not_hax {
17    ($macro:path, no, $($arg:tt)*) => {
18        ()
19    };
20    ($macro:path, $f:expr, $cond:expr$(, $($arg:tt)*)?) => {
21        $f($cond)
22    };
23}
24
25#[cfg(not(debug_assertions))]
26#[doc(hidden)]
27#[cfg(not(hax))]
28#[macro_export]
29macro_rules! proxy_macro_if_not_hax {
30    ($macro:path, $f:expr, $($arg:tt)*) => {};
31}
32
33#[cfg(debug_assertions)]
34#[doc(hidden)]
35#[cfg(not(hax))]
36#[macro_export]
37macro_rules! proxy_macro_if_not_hax {
38    ($macro:path, $f:expr, $($arg:tt)*) => {
39        $macro!($($arg)*)
40    };
41}
42
43#[macro_export]
44/// Proxy to `std::debug_assert!`. Compiled with `hax`, this
45/// disappears.
46macro_rules! debug_assert {
47    ($($arg:tt)*) => {
48        $crate::proxy_macro_if_not_hax!(::core::debug_assert, no, $($arg)*)
49    };
50}
51
52#[macro_export]
53/// Proxy to `std::assert!`. Compiled with `hax`, this is transformed
54/// into a `assert` in the backend.
55macro_rules! assert {
56    ($($arg:tt)*) => {
57        $crate::proxy_macro_if_not_hax!(::core::assert, $crate::assert, $($arg)*)
58    };
59}
60
61#[doc(hidden)]
62#[cfg(hax)]
63/// This function exists only when compiled with `hax`, and is not
64/// meant to be used directly. It is called by `assert!` only in
65/// appropriate situations.
66pub fn assert(_formula: bool) {}
67
68#[macro_export]
69/// Assert a logical proposition [`Prop`]: this exists only in the backends of
70/// hax. In Rust, this macro expands to an empty block `{ }`.
71macro_rules! assert_prop {
72    ($($arg:tt)*) => {
73        {
74            #[cfg(hax)]
75            {
76                $crate::assert_prop(::hax_lib::Prop::from($($arg)*));
77            }
78        }
79    };
80}
81
82#[doc(hidden)]
83#[cfg(hax)]
84/// This function exists only when compiled with `hax`, and is not meant to be
85/// used directly. It is called by `assert_prop!` only in appropriate
86/// situations.
87pub fn assert_prop(_formula: Prop) {}
88
89#[doc(hidden)]
90#[cfg(hax)]
91/// This function exists only when compiled with `hax`, and is not
92/// meant to be used directly. It is called by `assume!` only in
93/// appropriate situations.
94pub fn assume(_formula: Prop) {}
95
96#[cfg(hax)]
97#[macro_export]
98macro_rules! assume {
99    ($formula:expr) => {
100        $crate::assume(::hax_lib::Prop::from($formula))
101    };
102}
103
104/// Assume a proposition holds. In Rust, this is expanded to the
105/// expression `()`. While extracted with Hax, this gets expanded to a
106/// call to an `assume` function.
107///
108/// # Example:
109///
110/// ```rust
111/// fn sum(x: u32, y: u32) -> u32 {
112///   hax_lib::assume!(x < 4242 && y < 424242);
113///   x + y
114/// }
115/// ```
116#[cfg(not(hax))]
117#[macro_export]
118macro_rules! assume {
119    ($formula:expr) => {
120        ()
121    };
122}
123
124/// Dummy function that carries a string to be printed as such in the output language
125#[doc(hidden)]
126pub fn inline(_: &str) {}
127
128/// Similar to `inline`, but allows for any type. Do not use directly.
129#[doc(hidden)]
130pub fn inline_unsafe<T>(_: &str) -> T {
131    unreachable!()
132}
133
134/// Sink for any value into unit. This is used internally by hax to capture
135/// value of any type. Specifically, this is useful for the `decreases` clauses
136/// for the F* backend.
137#[doc(hidden)]
138pub fn any_to_unit<T>(_: T) -> () {
139    unreachable!()
140}
141
142/// A dummy function that holds a loop invariant.
143#[doc(hidden)]
144pub fn _internal_loop_invariant<T, R: Into<Prop>, P: FnOnce(T) -> R>(_: P) {}
145
146/// A dummy function that holds a while loop invariant.
147#[doc(hidden)]
148pub const fn _internal_while_loop_invariant(_: Prop) {}
149
150/// A dummy function that holds a loop variant.
151#[doc(hidden)]
152pub fn _internal_loop_decreases(_: Int) {}
153
154/// A type that implements `Refinement` should be a newtype for a
155/// type `T`. The field holding the value of type `T` should be
156/// private, and `Refinement` should be the only interface to the
157/// type.
158///
159/// Please never implement this trait yourself, use the
160/// `refinement_type` macro instead.
161pub trait Refinement {
162    /// The base type
163    type InnerType;
164    /// Smart constructor capturing an invariant. Its extraction will
165    /// yield a proof obligation.
166    fn new(x: Self::InnerType) -> Self;
167    /// Destructor for the refined type
168    fn get(self) -> Self::InnerType;
169    /// Gets a mutable reference to a refinement
170    fn get_mut(&mut self) -> &mut Self::InnerType;
171    /// Tests wether a value satisfies the refinement
172    fn invariant(value: Self::InnerType) -> Prop;
173}
174
175/// A utilitary trait that provides a `into_checked` method on traits
176/// that have a refined counter part. This trait is parametrized by a
177/// type `Target`: a base type can be refined in multiple ways.
178///
179/// Please never implement this trait yourself, use the
180/// `refinement_type` macro instead.
181pub trait RefineAs<RefinedType> {
182    /// Smart constructor for `RefinedType`, checking the invariant
183    /// `RefinedType::invariant`. The check is done statically via
184    /// extraction to hax: extracted code will yield static proof
185    /// obligations.
186    ///
187    /// In addition, in debug mode, the invariant is checked at
188    /// run-time, unless this behavior was disabled when defining the
189    /// refinement type `RefinedType` with the `refinement_type` macro
190    /// and its `no_debug_runtime_check` option.
191    fn into_checked(self) -> RefinedType;
192}