@@ -488,3 +488,138 @@ test_verify_one_file! {
488
488
}
489
489
} => Ok ( ( ) )
490
490
}
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