Skip to content
/ rust Public
forked from rust-lang/rust

Commit b279ff9

Browse files
pnkfelixcelinval
authored andcommitted
demonstrate how to capture state at precondition time and feed into postcondition predicate.
1 parent ae7eff0 commit b279ff9

3 files changed

+74
-0
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//@ run-fail
2+
//@ compile-flags: -Zcontract-checks=yes
3+
4+
#![feature(rustc_contracts)]
5+
6+
struct Baz {
7+
baz: i32
8+
}
9+
10+
#[track_caller]
11+
#[core::contracts::requires(x.baz > 0)]
12+
#[core::contracts::ensures({let old = x.baz; move |ret:&Baz| ret.baz == old*2 })]
13+
// Relevant thing is this: ^^^^^^^^^^^^^^^
14+
// because we are capturing state that is Copy
15+
fn doubler(x: Baz) -> Baz {
16+
Baz { baz: x.baz + 10 }
17+
}
18+
19+
fn main() {
20+
assert_eq!(doubler(Baz { baz: 10 }).baz, 20);
21+
assert_eq!(doubler(Baz { baz: 100 }).baz, 200);
22+
// This is a *run-fail* test because it is still exercising the
23+
// contract machinery, specifically because this second invocation
24+
// of `doubler` shows how the code does not meet its contract.
25+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//@ compile-flags: -Zcontract-checks=yes
2+
3+
#![feature(rustc_contracts)]
4+
5+
struct Baz {
6+
baz: i32
7+
}
8+
9+
#[track_caller]
10+
#[core::contracts::requires(x.baz > 0)]
11+
#[core::contracts::ensures({let old = x; move |ret:&Baz| ret.baz == old.baz*2 })]
12+
// Relevant thing is this: ^^^^^^^^^^^
13+
// because we are capturing state that is non-Copy.
14+
//~^^^ ERROR trait bound `Baz: std::marker::Copy` is not satisfied
15+
fn doubler(x: Baz) -> Baz {
16+
Baz { baz: x.baz + 10 }
17+
}
18+
19+
fn main() {
20+
assert_eq!(doubler(Baz { baz: 10 }).baz, 20);
21+
assert_eq!(doubler(Baz { baz: 100 }).baz, 200);
22+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0277]: the trait bound `Baz: std::marker::Copy` is not satisfied in `{closure@$DIR/contract-captures-via-closure-noncopy.rs:11:42: 11:57}`
2+
--> $DIR/contract-captures-via-closure-noncopy.rs:11:1
3+
|
4+
LL | #[core::contracts::ensures({let old = x; move |ret:&Baz| ret.baz == old.baz*2 })]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------------------------------------^^^^
6+
| | |
7+
| | within this `{closure@$DIR/contract-captures-via-closure-noncopy.rs:11:42: 11:57}`
8+
| | this tail expression is of type `{[email protected]:11:42}`
9+
| unsatisfied trait bound
10+
|
11+
= help: within `{closure@$DIR/contract-captures-via-closure-noncopy.rs:11:42: 11:57}`, the trait `std::marker::Copy` is not implemented for `Baz`
12+
note: required because it's used within this closure
13+
--> $DIR/contract-captures-via-closure-noncopy.rs:11:42
14+
|
15+
LL | #[core::contracts::ensures({let old = x; move |ret:&Baz| ret.baz == old.baz*2 })]
16+
| ^^^^^^^^^^^^^^^
17+
note: required by a bound in `build_check_ensures`
18+
--> $SRC_DIR/core/src/contracts.rs:LL:COL
19+
help: consider annotating `Baz` with `#[derive(Copy)]`
20+
|
21+
LL + #[derive(Copy)]
22+
LL | struct Baz {
23+
|
24+
25+
error: aborting due to 1 previous error
26+
27+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)