Skip to content

Commit 6f0c0b5

Browse files
authored
Function Contracts: Closure Type Inference (rust-lang#3307)
The rust type inference for closures doesn't work in the particular use case we are using it for ensures clauses. By creating a helper function, we change the path the rust type inference takes and lets the type of the closure be identified properly. This means type annotations are no longer required within ensures clauses. Resolves rust-lang#3304 By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.
1 parent 0994887 commit 6f0c0b5

File tree

6 files changed

+41
-1
lines changed

6 files changed

+41
-1
lines changed

library/kani/src/internal.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,10 @@ pub fn untracked_deref<T>(_: &T) -> T {
9090
#[doc(hidden)]
9191
#[rustc_diagnostic_item = "KaniInitContracts"]
9292
pub fn init_contracts() {}
93+
94+
/// This should only be used within contracts. The intent is to
95+
/// perform type inference on a closure's argument
96+
#[doc(hidden)]
97+
pub fn apply_closure<T, U: Fn(&T) -> bool>(f: U, x: &T) -> bool {
98+
f(x)
99+
}

library/kani_macros/src/sysroot/contracts/shared.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ pub fn build_ensures(data: &ExprClosure) -> (TokenStream2, Expr) {
176176
.fold(quote!(), |collect, (ident, expr)| quote!(let #ident = #expr; #collect));
177177

178178
let result: Ident = Ident::new(INTERNAL_RESULT_IDENT, Span::call_site());
179-
(remembers_stmts, Expr::Verbatim(quote!((#expr)(&#result))))
179+
(remembers_stmts, Expr::Verbatim(quote!(kani::internal::apply_closure(#expr, &#result))))
180180
}
181181

182182
trait OldTrigger {
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
assertion\
2+
- Status: SUCCESS\
3+
- Description: "|result| (*result == x) | (*result == y)"\
4+
in function max
5+
6+
VERIFICATION:- SUCCESSFUL
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright Kani Contributors
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
// kani-flags: -Zfunction-contracts
4+
5+
#[kani::ensures(|result| (*result == x) | (*result == y))]
6+
fn max(x: u32, y: u32) -> u32 {
7+
if x > y { x } else { y }
8+
}
9+
10+
#[kani::proof_for_contract(max)]
11+
fn max_harness() {
12+
let _ = Box::new(9_usize);
13+
max(7, 6);
14+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
cannot assign to `*_x`, as `Fn` closures cannot mutate their captured variables
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright Kani Contributors
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
// kani-flags: -Zfunction-contracts
4+
5+
#[kani::ensures(|_| {*_x += 1; true})]
6+
fn unit(_x: &mut u32) {}
7+
8+
#[kani::proof_for_contract(id)]
9+
fn harness() {
10+
let mut x = kani::any();
11+
unit(&mut x);
12+
}

0 commit comments

Comments
 (0)