#![feature(rustc_private)]
#[macro_use]
mod common;
use common::*;
test_verify_one_file! {
#[test] test1 verus_code! {
#[verifier(inline)]
spec fn fi(x: int, y: int) -> int {
x + 2 * y
}
spec fn f1(x: int, y: int) -> int {
x + 2 * y
}
#[verifier(inline)]
spec fn f2(x: int, y: int) -> int {
f1(x, y)
}
#[verifier(inline)]
spec fn f3(a: int, b: int) -> int {
f1(a, b)
}
#[verifier(inline)]
spec fn f4(a: int, b: int) -> int {
let za = a + 1;
let zb = b + 1;
f1(za - 1, zb - 1)
}
#[verifier(inline)]
spec fn fg(a: A, b: B) -> (B, A) {
(b, a)
}
uninterp spec fn fx(x: int) -> bool;
#[verifier(inline)]
spec fn fy(x: int) -> bool {
fx(x)
}
uninterp spec fn fpx(x: A) -> bool;
#[verifier(inline)]
spec fn fpy(x: A) -> bool {
fpx(x)
}
proof fn test()
requires
forall|i: int| fy(i),
forall|i: u8| fpy(i),
{
assert(fi(33, 44) == 121);
assert(f1(33, 44) == 121);
assert(f2(33, 44) == 121);
assert(f3(33, 44) == 121);
assert({let za = 44; f4(33, za) == 121});
assert(fg(10u8, true) == (true, 10u8));
assert(fx(7));
assert(fy(6));
assert(fpx(7u8));
assert(fpy(6u8));
}
} => Ok(())
}
test_verify_one_file! {
#[test] test_private_fails verus_code! {
#[verifier(inline)]
pub closed spec fn f(x: int, y: int) -> int {
x + 2 * y
}
} => Err(err) => assert_vir_error_msg(err, "`inline` is only allowed for private or `open spec` functions")
}
test_verify_one_file! {
#[test] test_nonspec_fails verus_code! {
#[verifier(inline)]
proof fn f() {
}
} => Err(err) => assert_vir_error_msg(err, "`inline` is only allowed for `spec` functions")
}
test_verify_one_file! {
#[test] test_rec_fails1 verus_code! {
#[verifier(inline)]
spec fn f(n: nat) -> nat
decreases n
{
0
}
} => Err(err) => assert_vir_error_msg(err, "`inline` functions cannot be recursive")
}
test_verify_one_file! {
#[test] test_rec_fails2 verus_code! {
#[verifier(inline)]
spec fn f(n: nat) -> nat
{
if n == 0 {
0
} else {
f((n - 1) as nat)
}
}
} => Err(err) => assert_vir_error_msg(err, "recursive function must have a `decreases` clause")
}
test_verify_one_file! {
#[test] test_no_body_fails verus_code! {
#[verifier(inline)]
spec fn f(n: nat) -> nat;
} => Err(err) => assert_vir_error_msg(err, "`inline` functions must have a body")
}
test_verify_one_file! {
#[test] test_spec_fn verus_code! {
#[verifier(inline)]
spec fn f1(i: int, j: int) -> bool {
i <= j
}
#[verifier(inline)]
spec fn f2(i: int, j: int) -> bool {
let x = i;
let y = j;
x < y
}
#[verifier(opaque)]
spec fn f3(i: int, j: int) -> bool {
f1(j, i)
}
fn test_spec_fn(a: int, b: int) {
hide(f2);
assume(f2(a, b));
proof {
reveal(f2);
}
assert(f1(a, b));
proof {
reveal(f3);
}
assert(f3(b, a));
assert(f3(a, b)); // FAILS
}
} => Err(err) => assert_one_fails(err)
}
test_verify_one_file! {
#[test] test_ensures_type_inference verus_code! {
struct Foo {
pub b: bool,
}
#[verifier(inline)]
spec fn get_b(foo: Foo) -> bool {
foo.b
}
fn test1() -> (b: Foo)
ensures get_b(b)
{
Foo { b: true }
}
} => Ok(())
}
test_verify_one_file! {
#[test] inline_poly verus_code! {
use vstd::prelude::*;
#[verifier::inline]
spec fn all_contains(s1: Set) -> bool {
forall|a: A| s1.contains(a)
}
proof fn failing_proof(s: Set) {
assert(all_contains(s)); // FAILS
}
} => Err(err) => assert_one_fails(err)
}
test_verify_one_file! {
#[test] inline_poly_assoc_type verus_code! {
// https://github.com/verus-lang/verus/issues/1303
use vstd::prelude::*;
pub type SpecBytes = Seq;
pub type Bytes<'a> = &'a [u8];
pub enum SpecMsg {
M0(SpecBytes),
}
pub enum Msg<'a> {
M0(Bytes<'a>),
}
impl View for Msg<'_> {
type V = SpecMsg;
open spec fn view(&self) -> Self::V {
match self {
Msg::M0(m) => SpecMsg::M0(m@),
}
}
}
} => Ok(())
}
test_verify_one_file! {
#[test] default_impl_issue1407 verus_code! {
trait Tr {
#[verifier::inline]
spec fn foo(&self) -> bool { true }
}
struct X { }
impl Tr for X {
spec fn foo(&self) -> bool { false }
}
#[verifier::inline]
spec fn foo_wrapper_inlined(t: &T) -> bool {
t.foo()
}
proof fn test4() {
let x = X { };
assert(foo_wrapper_inlined(&x)); // FAILS
}
proof fn test5(t: &T) {
assert(foo_wrapper_inlined(t)); // FAILS
}
} => Err(err) => assert_fails(err, 2)
}