-
Notifications
You must be signed in to change notification settings - Fork 93
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a
#[derive(Invariant)]
macro (#3250)
This PR adds a `#[derive(Invariant)]` macro for structs which allows users to automatically derive the `Invariant` implementations for any struct. The derived implementation determines the invariant for the struct as the conjunction of invariants of its fields. In other words, the invariant is derived as `true && self.field1.is_safe() && self.field2.is_safe() && ..`. For example, for the struct ```rs #[derive(kani::Invariant)] struct Point<X, Y> { x: X, y: Y, } ``` we derive the `Invariant` implementation as ```rs impl<X: kani::Invariant, Y: kani::Invariant> kani::Invariant for Point<X, Y> { fn is_safe(&self) -> bool { true && self.x.is_safe() && self.y.is_safe() } } ``` Related #3095
- Loading branch information
1 parent
7dad847
commit 5c7cd63
Showing
12 changed files
with
244 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
37 changes: 37 additions & 0 deletions
37
tests/expected/derive-invariant/empty_struct/empty_struct.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// Copyright Kani Contributors | ||
// SPDX-License-Identifier: Apache-2.0 OR MIT | ||
|
||
//! Check that Kani can automatically derive `Invariant` for empty structs. | ||
|
||
extern crate kani; | ||
use kani::Invariant; | ||
|
||
#[derive(kani::Arbitrary)] | ||
#[derive(kani::Invariant)] | ||
struct Void; | ||
|
||
#[derive(kani::Arbitrary)] | ||
#[derive(kani::Invariant)] | ||
struct Void2(()); | ||
|
||
#[derive(kani::Arbitrary)] | ||
#[derive(kani::Invariant)] | ||
struct VoidOfVoid(Void, Void2); | ||
|
||
#[kani::proof] | ||
fn check_empty_struct_invariant_1() { | ||
let void1: Void = kani::any(); | ||
assert!(void1.is_safe()); | ||
} | ||
|
||
#[kani::proof] | ||
fn check_empty_struct_invariant_2() { | ||
let void2: Void2 = kani::any(); | ||
assert!(void2.is_safe()); | ||
} | ||
|
||
#[kani::proof] | ||
fn check_empty_struct_invariant_3() { | ||
let void3: VoidOfVoid = kani::any(); | ||
assert!(void3.is_safe()); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
- Status: SUCCESS\ | ||
- Description: "assertion failed: void1.is_safe()" | ||
|
||
- Status: SUCCESS\ | ||
- Description: "assertion failed: void2.is_safe()" | ||
|
||
- Status: SUCCESS\ | ||
- Description: "assertion failed: void3.is_safe()" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
- Status: SUCCESS\ | ||
- Description: "assertion failed: point.is_safe()" |
20 changes: 20 additions & 0 deletions
20
tests/expected/derive-invariant/generic_struct/generic_struct.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// Copyright Kani Contributors | ||
// SPDX-License-Identifier: Apache-2.0 OR MIT | ||
|
||
//! Check that Kani can automatically derive `Invariant` for structs with generics. | ||
|
||
extern crate kani; | ||
use kani::Invariant; | ||
|
||
#[derive(kani::Arbitrary)] | ||
#[derive(kani::Invariant)] | ||
struct Point<X, Y> { | ||
x: X, | ||
y: Y, | ||
} | ||
|
||
#[kani::proof] | ||
fn check_generic_struct_invariant() { | ||
let point: Point<i32, i8> = kani::any(); | ||
assert!(point.is_safe()); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
- Status: FAILURE\ | ||
- Description: "assertion failed: wrapper.is_safe()" | ||
|
||
Verification failed for - check_invariant_fail |
33 changes: 33 additions & 0 deletions
33
tests/expected/derive-invariant/invariant_fail/invariant_fail.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
// Copyright Kani Contributors | ||
// SPDX-License-Identifier: Apache-2.0 OR MIT | ||
|
||
//! Check that a verification failure is triggered when the derived `Invariant` | ||
//! method is checked but not satisfied. | ||
|
||
extern crate kani; | ||
use kani::Invariant; | ||
// Note: This represents an incorrect usage of `Arbitrary` and `Invariant`. | ||
// | ||
// The `Arbitrary` implementation should respect the type invariant, | ||
// but Kani does not enforce this in any way at the moment. | ||
// <https://github.com/model-checking/kani/issues/3265> | ||
#[derive(kani::Arbitrary)] | ||
struct NotNegative(i32); | ||
|
||
impl kani::Invariant for NotNegative { | ||
fn is_safe(&self) -> bool { | ||
self.0 >= 0 | ||
} | ||
} | ||
|
||
#[derive(kani::Arbitrary)] | ||
#[derive(kani::Invariant)] | ||
struct NotNegativeWrapper { | ||
x: NotNegative, | ||
} | ||
|
||
#[kani::proof] | ||
fn check_invariant_fail() { | ||
let wrapper: NotNegativeWrapper = kani::any(); | ||
assert!(wrapper.is_safe()); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
- Status: SUCCESS\ | ||
- Description: "assertion failed: point.is_safe()" |
20 changes: 20 additions & 0 deletions
20
tests/expected/derive-invariant/named_struct/named_struct.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// Copyright Kani Contributors | ||
// SPDX-License-Identifier: Apache-2.0 OR MIT | ||
|
||
//! Check that Kani can automatically derive `Invariant` for structs with named fields. | ||
|
||
extern crate kani; | ||
use kani::Invariant; | ||
|
||
#[derive(kani::Arbitrary)] | ||
#[derive(kani::Invariant)] | ||
struct Point { | ||
x: i32, | ||
y: i32, | ||
} | ||
|
||
#[kani::proof] | ||
fn check_generic_struct_invariant() { | ||
let point: Point = kani::any(); | ||
assert!(point.is_safe()); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
- Status: SUCCESS\ | ||
- Description: "assertion failed: point.is_safe()" |
17 changes: 17 additions & 0 deletions
17
tests/expected/derive-invariant/unnamed_struct/unnamed_struct.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// Copyright Kani Contributors | ||
// SPDX-License-Identifier: Apache-2.0 OR MIT | ||
|
||
//! Check that Kani can automatically derive `Invariant` for structs with unnamed fields. | ||
|
||
extern crate kani; | ||
use kani::Invariant; | ||
|
||
#[derive(kani::Arbitrary)] | ||
#[derive(kani::Invariant)] | ||
struct Point(i32, i32); | ||
|
||
#[kani::proof] | ||
fn check_generic_struct_invariant() { | ||
let point: Point = kani::any(); | ||
assert!(point.is_safe()); | ||
} |