Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Loop invariants #857

Merged
merged 13 commits into from
Aug 23, 2024
Merged

Loop invariants #857

merged 13 commits into from
Aug 23, 2024

Conversation

W95Psp
Copy link
Collaborator

@W95Psp W95Psp commented Aug 19, 2024

This PR recognizes and transforms in a particular way the following loops. It also injects invariants.

fn range() {
    let mut count = 0u64;
    for i in 0u8..10u8 {
        hax_lib::loop_invariant!(|i: u8| i <= 10);
        count += 1;
    }
}
fn range_step_by() {
    let mut count = 0u64;
    for i in (0u8..10u8).step_by(2) {
        hax_lib::loop_invariant!(|i: u8| i <= 10);
        count += 1;
    }
}
fn enumerated_slice<T>(slice: &[T]) {
    let mut count = 0u64;
    for i in slice.into_iter().enumerate() {
        hax_lib::loop_invariant!(|i: usize| i <= 10);
        count += 2;
    }
}
fn enumerated_chunked_slice<T>(slice: &[T]) {
    let mut count = 0u64;
    for i in slice.chunks_exact(3).enumerate() {
        hax_lib::loop_invariant!(|i: usize| { fstar!("$i <= ${slice.len()}") });
        count += 3;
    }
}

Open this code snippet in the playground

The design is not great, I copy paste here the documentation of loop_invariant:

/// Add an invariant to a loop which deals with an index. The
/// invariant cannot refer to any variable introduced within the
/// loop. An invariant is a closure that takes one argument, the
/// index, and returns a boolean.
///
/// Note that loop invariants are unstable (this will be handled in a
/// better way in the future, see
/// https://github.com/hacspec/hax/issues/858) and only supported on
/// specific `for` loops with specific iterators:
///
///  - `for i in start..end {...}`
///  - `for i in (start..end).step_by(n) {...}`
///  - `for i in slice.enumerate() {...}`
///  - `for i in slice.chunks_exact(n).enumerate() {...}`
///
/// This function must be called on the first line of a loop body to
/// be effective. Note that in the invariant expression, `forall`,
/// `exists`, and `BACKEND!` (`BACKEND` can be `fstar`, `proverif`,
/// `coq`...) are in scope.

This fixes #605.

Things left to do:

  • add F* definitions

@W95Psp W95Psp marked this pull request as draft August 19, 2024 11:33
@W95Psp W95Psp mentioned this pull request Aug 19, 2024
@W95Psp W95Psp requested review from franziskuskiefer, karthikbhargavan and mamonet and removed request for franziskuskiefer August 19, 2024 15:07
@W95Psp W95Psp marked this pull request as ready for review August 19, 2024 15:08
@karthikbhargavan karthikbhargavan added this pull request to the merge queue Aug 22, 2024
@W95Psp W95Psp removed this pull request from the merge queue due to a manual request Aug 22, 2024
@W95Psp W95Psp enabled auto-merge August 22, 2024 16:24
@W95Psp W95Psp added this pull request to the merge queue Aug 22, 2024
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Aug 22, 2024
@W95Psp W95Psp added this pull request to the merge queue Aug 23, 2024
Merged via the queue into main with commit 66b7683 Aug 23, 2024
13 checks passed
@W95Psp W95Psp deleted the loop-invariants branch August 23, 2024 06:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

Annotations for loop invariants
3 participants