@@ -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+ }
0 commit comments