hax icon indicating copy to clipboard operation
hax copied to clipboard

Improve Pre- and Post-Conditions on `impl` blocks

Open karthikbhargavan opened this issue 1 year ago • 0 comments
trafficstars

When writing the following contracts on an impl block, several errors are triggered:

#[hax_lib::attributes]
impl<const N: usize> TryDecodeOps<U8> for [U32; N] {
    #[hax_lib::requires(N < 65536 / 4)]
    #[hax_lib::ensures(|result| if x.len() == N * 4 {result.is_ok()} else {result.is_err()})] 
    fn try_from_le_bytes(x:&[U8]) -> Result<Self,()> {
        try_from_le_bytes(x)
    }
    #[hax_lib::requires(N < 65536 / 4)]
    #[hax_lib::ensures(|result| if x.len() == N * 4 {result.is_ok()} else {result.is_err()})] 
    fn try_from_be_bytes(x:&[U8]) -> Result<Self,()> {
        try_from_be_bytes(x)
    }
}

First, we must remove the hax_lib:: prefix from all the pre- and post-conditions inside the impl.

Second, we must remove Self and replace it by [U32; N]

Third, in the generated F* code, the pre-condition is not provided to the post-condition, so we end up having to repeat the pre-condition in the post-condition.

The version that works after these changes is the following:

#[hax_lib::attributes]
impl<const N: usize> TryDecodeOps<U8> for [U32; N] {
    #[requires(N < 65536 / 4)]
    #[ensures(|result| N < 65536 / 4 && (if x.len() == N * 4 {result.is_ok()} else {result.is_err()}))] 
    fn try_from_le_bytes(x:&[U8]) -> Result<[U32; N],()> {
        try_from_le_bytes(x)
    }
    #[requires(N < 65536 / 4)]
    #[ensures(|result| N < 65536 / 4 && (if x.len() == N * 4 {result.is_ok()} else {result.is_err()}))] 
    fn try_from_be_bytes(x:&[U8]) -> Result<[U32; N],()> {
        try_from_be_bytes(x)
    }
}

Individual issues:

  • #782
  • #783
  • #784

karthikbhargavan avatar Jul 17 '24 19:07 karthikbhargavan