about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFelix S. Klock II <pnkfelix@pnkfx.org>2024-12-03 14:29:27 +0000
committerCelina G. Val <celinval@amazon.com>2025-02-03 13:55:15 -0800
commitb279ff9dcfadcdb6976097d58044d151af81cf51 (patch)
tree2cf243d4eae0b32ff95ce2416c08910cc0cbc667
parentae7eff0be5c4abae63c06851af14cfdf7fec3981 (diff)
downloadrust-b279ff9dcfadcdb6976097d58044d151af81cf51.tar.gz
rust-b279ff9dcfadcdb6976097d58044d151af81cf51.zip
demonstrate how to capture state at precondition time and feed into postcondition predicate.
-rw-r--r--tests/ui/contracts/contract-captures-via-closure-copy.rs25
-rw-r--r--tests/ui/contracts/contract-captures-via-closure-noncopy.rs22
-rw-r--r--tests/ui/contracts/contract-captures-via-closure-noncopy.stderr27
3 files changed, 74 insertions, 0 deletions
diff --git a/tests/ui/contracts/contract-captures-via-closure-copy.rs b/tests/ui/contracts/contract-captures-via-closure-copy.rs
new file mode 100644
index 00000000000..742895ab0ad
--- /dev/null
+++ b/tests/ui/contracts/contract-captures-via-closure-copy.rs
@@ -0,0 +1,25 @@
+//@ run-fail
+//@ compile-flags: -Zcontract-checks=yes
+
+#![feature(rustc_contracts)]
+
+struct Baz {
+    baz: i32
+}
+
+#[track_caller]
+#[core::contracts::requires(x.baz > 0)]
+#[core::contracts::ensures({let old = x.baz; move |ret:&Baz| ret.baz == old*2 })]
+// Relevant thing is this:  ^^^^^^^^^^^^^^^
+// because we are capturing state that is Copy
+fn doubler(x: Baz) -> Baz {
+    Baz { baz: x.baz + 10 }
+}
+
+fn main() {
+    assert_eq!(doubler(Baz { baz: 10 }).baz, 20);
+    assert_eq!(doubler(Baz { baz: 100 }).baz, 200);
+    // This is a *run-fail* test because it is still exercising the
+    // contract machinery, specifically because this second invocation
+    // of `doubler` shows how the code does not meet its contract.
+}
diff --git a/tests/ui/contracts/contract-captures-via-closure-noncopy.rs b/tests/ui/contracts/contract-captures-via-closure-noncopy.rs
new file mode 100644
index 00000000000..8d7f2fd200e
--- /dev/null
+++ b/tests/ui/contracts/contract-captures-via-closure-noncopy.rs
@@ -0,0 +1,22 @@
+//@ compile-flags: -Zcontract-checks=yes
+
+#![feature(rustc_contracts)]
+
+struct Baz {
+    baz: i32
+}
+
+#[track_caller]
+#[core::contracts::requires(x.baz > 0)]
+#[core::contracts::ensures({let old = x; move |ret:&Baz| ret.baz == old.baz*2 })]
+// Relevant thing is this:  ^^^^^^^^^^^
+// because we are capturing state that is non-Copy.
+//~^^^ ERROR trait bound `Baz: std::marker::Copy` is not satisfied
+fn doubler(x: Baz) -> Baz {
+    Baz { baz: x.baz + 10 }
+}
+
+fn main() {
+    assert_eq!(doubler(Baz { baz: 10 }).baz, 20);
+    assert_eq!(doubler(Baz { baz: 100 }).baz, 200);
+}
diff --git a/tests/ui/contracts/contract-captures-via-closure-noncopy.stderr b/tests/ui/contracts/contract-captures-via-closure-noncopy.stderr
new file mode 100644
index 00000000000..b53809827f9
--- /dev/null
+++ b/tests/ui/contracts/contract-captures-via-closure-noncopy.stderr
@@ -0,0 +1,27 @@
+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}`
+  --> $DIR/contract-captures-via-closure-noncopy.rs:11:1
+   |
+LL | #[core::contracts::ensures({let old = x; move |ret:&Baz| ret.baz == old.baz*2 })]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------------------------------------^^^^
+   | |                                        |
+   | |                                        within this `{closure@$DIR/contract-captures-via-closure-noncopy.rs:11:42: 11:57}`
+   | |                                        this tail expression is of type `{closure@contract-captures-via-closure-noncopy.rs:11:42}`
+   | unsatisfied trait bound
+   |
+   = help: within `{closure@$DIR/contract-captures-via-closure-noncopy.rs:11:42: 11:57}`, the trait `std::marker::Copy` is not implemented for `Baz`
+note: required because it's used within this closure
+  --> $DIR/contract-captures-via-closure-noncopy.rs:11:42
+   |
+LL | #[core::contracts::ensures({let old = x; move |ret:&Baz| ret.baz == old.baz*2 })]
+   |                                          ^^^^^^^^^^^^^^^
+note: required by a bound in `build_check_ensures`
+  --> $SRC_DIR/core/src/contracts.rs:LL:COL
+help: consider annotating `Baz` with `#[derive(Copy)]`
+   |
+LL + #[derive(Copy)]
+LL | struct Baz {
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.