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

Need to refer to $self_ instead of $self in ensures #1276

Open
maximebuyse opened this issue Jan 29, 2025 · 4 comments
Open

Need to refer to $self_ instead of $self in ensures #1276

maximebuyse opened this issue Jan 29, 2025 · 4 comments
Labels
lib Lib-related issue (e.g. annotations lib)

Comments

@maximebuyse
Copy link
Contributor

trait Test {
    fn f(&self) -> u8;
}

#[hax_lib::attributes]
impl Test for u8 {
    #[hax_lib::ensures(|result| fstar!("${self_} = $result"))]
    fn f(&self) -> u8 {*self}
}

Open this code snippet in the playground

As in the example above, when using fstar! inside an ensures for a method inside a trait implementation, we need to refer to self as $self_ instead of $self which is confusing. Note that this seems not to work at all for a non-trait impl.

@maximebuyse maximebuyse added the lib Lib-related issue (e.g. annotations lib) label Jan 29, 2025
@maximebuyse
Copy link
Contributor Author

struct Test(u8);

#[hax_lib::attributes]
impl Test {
    #[hax_lib::ensures(|result| fstar!("${self_}._0 = $result"))]
    fn f(&self) -> u8 {self.0}
}

Open this code snippet in the playground

Here is a reproducer for an inherent impl, where things seem to be just broken.

@maximebuyse
Copy link
Contributor Author

struct Test(u8);

#[hax_lib::attributes]
impl Test {
#[hax_lib::ensures(|result| fstar!("${self_}._0 = $result"))]
fn f(&self) -> u8 {self.0}
}

Open this code snippet in the playground

Here is a reproducer for an inherent impl, where things seem to be just broken.

Workaround:

struct Test(u8);

#[hax_lib::attributes]
impl Test {
    #[hax_lib::ensures(|result| fstar!("let ${self_} = self in ${self_.0} = $result"))]
    fn f(&self) -> u8 {self.0}
}

Open this code snippet in the playground

@karthikbhargavan
Copy link
Contributor

We hit this again in Bertie. It would be great to prioritize this.

@karthikbhargavan
Copy link
Contributor

Note that this is not just an fstar! problem. The same problem appears if we use self in Rust.

See:
https://hax-playground.cryspen.com/#fstar/2b75d755e8/gist=4d2d91104991ada9589bf72bee056ab0

struct Test(pub u8);

#[hax_lib::attributes]
impl Test {
    #[hax_lib::ensures(|result| self.0 == result)]
    fn f(&self) -> u8 {self.0}
}

W95Psp added a commit that referenced this issue Mar 11, 2025
Consider the following piece of code:
```rust
struct S(pub  u8);

impl S {
    #[hax_lib::requires(self.0 == 0)]
    fn f(&self) {}
}
```

The `requires` annotation produces a standalone function that looks like the following:

```rust
fn requires(self_: S) -> bool {
    self_.0 == 0
}
```

Here, we can't use `self`: this is a reserved keyword in Rust, and we are not in a `impl` context.
Thus, the macro renames `self` into `self_`.
The bug described in #1276 comes from this renaming not being reverted in the engine.

With this commit, when the F* backend inteprets
such clauses, if the function on which a clause
exists have a `self` as first argument, we now
substitute the first argument of the clause
function to replace it with the first argument of
the original function.
In the example above, we replace `self_` with `self`.
W95Psp added a commit that referenced this issue Mar 11, 2025
Consider the following piece of code:
```rust
struct S(pub  u8);

impl S {
    #[hax_lib::requires(self.0 == 0)]
    fn f(&self) {}
}
```

The `requires` annotation produces a standalone function that looks like the following:

```rust
fn requires(self_: S) -> bool {
    self_.0 == 0
}
```

Here, we can't use `self`: this is a reserved keyword in Rust, and we are not in a `impl` context.
Thus, the macro renames `self` into `self_`.
The bug described in #1276 comes from this renaming not being reverted in the engine.

With this commit, when the F* backend inteprets
such clauses, if the function on which a clause
exists have a `self` as first argument, we now
substitute the first argument of the clause
function to replace it with the first argument of
the original function.
In the example above, we replace `self_` with `self`.

This PR also improves the macro to always pick a fresh name, not always `self_`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
lib Lib-related issue (e.g. annotations lib)
Projects
None yet
Development

No branches or pull requests

2 participants