Skip to content

Commit 3cde68e

Browse files
committed
Add tests for operators;
1 parent 3c043af commit 3cde68e

File tree

2 files changed

+136
-1
lines changed

2 files changed

+136
-1
lines changed

source/rust_verify_test/tests/external_traits.rs

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,3 +488,138 @@ test_verify_one_file! {
488488
}
489489
} => Ok(())
490490
}
491+
492+
test_verify_one_file! {
493+
#[test] test_operator_overload verus_code! {
494+
use vstd::prelude::*;
495+
use vstd::std_specs::ops::*;
496+
use vstd::std_specs::cmp::*;
497+
498+
fn check_sub<Out, T: core::ops::Sub<Output = Out> + core::cmp::PartialOrd>(x: T, y: T) -> (ret: Option<Out>)
499+
requires
500+
vstd::std_specs::cmp::spec_gt(&x, &y) ==> spec_sub_requires(x, y)
501+
ensures
502+
ret.is_some() == vstd::std_specs::cmp::spec_gt(&x, &y),
503+
ret.is_some() ==> spec_sub_ensures(x, y, ret.unwrap()),
504+
{
505+
if x > y {
506+
assert(spec_gt(&x, &y));
507+
Some(x - y)
508+
} else {
509+
None
510+
}
511+
}
512+
513+
fn check_sub_u8(x: u8, y: u8)
514+
{
515+
let out = check_sub(x, y);
516+
assert(out.is_some() ==> (x >= y));
517+
}
518+
519+
#[derive(PartialEq)]
520+
struct A(pub usize);
521+
522+
impl SpecSubOp<A> for A {
523+
type Output = usize;
524+
open spec fn spec_sub_requires(lhs: A, rhs: A) -> bool {
525+
lhs.0 >= 20 && rhs.0 < 10
526+
}
527+
528+
open spec fn spec_sub_ensures(lhs: A, rhs: A, ret: usize) -> bool {
529+
ret == lhs.0 - rhs.0 - 10
530+
}
531+
}
532+
impl core::ops::Sub<A> for A {
533+
type Output = usize;
534+
fn sub(self, rhs: A) -> usize {
535+
assert(self.0 >= 20 && rhs.0 <= 10);
536+
self.0 - rhs.0 - 10
537+
}
538+
}
539+
540+
impl SpecPartialOrdOp<A> for A {
541+
open spec fn spec_partial_cmp(&self, rhs: &A) -> Option<core::cmp::Ordering> {
542+
if self.0 > 30 && rhs.0 < 9 {
543+
Some(core::cmp::Ordering::Greater)
544+
} else {
545+
None
546+
}
547+
}
548+
}
549+
550+
impl core::cmp::PartialOrd<A> for A {
551+
fn partial_cmp(&self, rhs: &A) -> Option<core::cmp::Ordering>{
552+
// Why we need this? It is not triggered automatically?
553+
proof!{vstd::std_specs::cmp::axiom_partial_cmp(self, rhs);}
554+
if self.0 > 30 && rhs.0 < 9 {
555+
Some(core::cmp::Ordering::Greater)
556+
} else {
557+
None
558+
}
559+
}
560+
}
561+
562+
fn check_sub_special()
563+
{
564+
let a1 = A(30);
565+
let a2 = A(9);
566+
if a1 > a2 {
567+
assert(a1.0 > 30);
568+
}
569+
let res = a1 - a2;
570+
assert(res == 11);
571+
572+
}
573+
574+
} => Ok(())
575+
}
576+
577+
test_verify_one_file! {
578+
#[test] test_call_operator_trait_method verus_code! {
579+
use core::ops::Sub;
580+
use vstd::prelude::*;
581+
use vstd::std_specs::ops::*;
582+
struct A;
583+
impl SpecSubOp<A> for A {
584+
type Output = A;
585+
open spec fn spec_sub_requires(lhs: A, other: A) -> bool {
586+
true
587+
}
588+
open spec fn spec_sub_ensures(lhs: A, other: A, ret: A) -> bool {
589+
true
590+
}
591+
}
592+
impl Sub for A {
593+
type Output = A;
594+
fn sub(self, other: A) -> (ret: A)
595+
{
596+
proof{
597+
broadcast use axiom_sub;
598+
}
599+
self
600+
}
601+
}
602+
// If it is a non-primitive type, it would work.
603+
fn test(x1: A, x2: A) {
604+
let ord2 = x1.sub(x2);
605+
}
606+
} => Ok(())
607+
}
608+
609+
test_verify_one_file! {
610+
#[test] test_operator_overload_failed_precondition verus_code! {
611+
use vstd::prelude::*;
612+
use vstd::std_specs::ops::*;
613+
use vstd::std_specs::cmp::*;
614+
fn check_add<Out, T: core::ops::Sub<Output = Out> + core::cmp::PartialOrd>(x: T, y: T) -> (ret: Option<Out>)
615+
ensures
616+
vstd::std_specs::cmp::spec_ge(&x, &y) ==> ret.is_some() && spec_sub_ensures(x, y, ret.unwrap()),
617+
{
618+
if x >= y {
619+
Some(x - y) // FAILS
620+
} else {
621+
None
622+
}
623+
}
624+
} => Err(e) => assert_one_fails(e)
625+
}

source/vstd/std_specs/ops.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ macro_rules! def_bin_ops_spec {
6868
fn $fun(self, rhs: Rhs) -> (ret: Self::Output)
6969
where Self: Sized
7070
requires $spec_requires(self, rhs),
71-
ensures $spec_ensures(self, rhs, ret)
71+
ensures $spec_ensures(self, rhs, ret) // Please Impl SpecXXOp before exec operator trait.
7272
;
7373
}
7474

0 commit comments

Comments
 (0)