Skip to content

Commit 43cb956

Browse files
bors[bot]Aurel300
andauthored
Merge #1123
1123: Snapshot equality r=Aurel300 a=Aurel300 Pulling this out of #980. `@vakaras` Co-authored-by: Aurel Bílý <[email protected]>
2 parents 6cd20c1 + 83c89ab commit 43cb956

File tree

6 files changed

+72
-8
lines changed

6 files changed

+72
-8
lines changed

prusti-contracts/src/lib.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,12 +343,33 @@ pub fn old<T>(arg: T) -> T {
343343
arg
344344
}
345345

346+
/// Universal quantifier.
347+
///
348+
/// This is a Prusti-internal representation of the `forall` syntax.
346349
pub fn forall<T, F>(_trigger_set: T, _closure: F) -> bool {
347350
true
348351
}
349352

353+
/// Existential quantifier.
354+
///
355+
/// This is a Prusti-internal representation of the `exists` syntax.
350356
pub fn exists<T, F>(_trigger_set: T, _closure: F) -> bool {
351357
true
352358
}
353359

360+
/// Creates an owned copy of a reference. This should only be used from within
361+
/// ghost code, as it circumvents the borrow checker.
362+
pub fn snap<T>(_x: &T) -> T {
363+
unimplemented!()
364+
}
365+
366+
/// Snapshot, "logical", or "mathematical" equality. Compares the in-memory
367+
/// representation of two instances of the same type, even if there is no
368+
/// `PartialEq` nor `Copy` implementation. The in-memory representation is
369+
/// constructed recursively: references are followed, unsafe pointers and cells
370+
/// are not. Importantly, addresses are not taken into consideration.
371+
pub fn snapshot_equality<T>(_l: T, _r: T) -> bool {
372+
true
373+
}
374+
354375
pub use private::*;

prusti-specs/src/specifications/preparser.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -797,7 +797,7 @@ impl PrustiBinaryOp {
797797
}
798798
Self::Or => quote_spanned! { span => #lhs || #rhs },
799799
Self::And => quote_spanned! { span => #lhs && #rhs },
800-
Self::SnapEq => quote_spanned! { span => snapshot_equality(#lhs, #rhs) },
800+
Self::SnapEq => quote_spanned! { span => snapshot_equality(&#lhs, &#rhs) },
801801
}
802802
}
803803
}
@@ -894,16 +894,15 @@ mod tests {
894894
);
895895
assert_eq!(
896896
parse_prusti("exists(|x: i32| a === b)".parse().unwrap()).unwrap().to_string(),
897-
"exists (() , # [prusti :: spec_only] | x : i32 | -> bool { ((snapshot_equality (a , b)) : bool) })",
897+
"exists (() , # [prusti :: spec_only] | x : i32 | -> bool { ((snapshot_equality (& a , & b)) : bool) })",
898898
);
899899
assert_eq!(
900900
parse_prusti("forall(|x: i32| a ==> b, triggers = [(c,), (d, e)])".parse().unwrap()).unwrap().to_string(),
901901
"forall (((# [prusti :: spec_only] | x : i32 | (c) ,) , (# [prusti :: spec_only] | x : i32 | (d) , # [prusti :: spec_only] | x : i32 | (e) ,) ,) , # [prusti :: spec_only] | x : i32 | -> bool { (((! (a) || (b))) : bool) })",
902902
);
903-
let expr: syn::Expr = syn::parse2("assert!(a === b ==> b)".parse().unwrap()).unwrap();
904903
assert_eq!(
905-
parse_prusti(quote! { #expr }).unwrap().to_string(),
906-
"assert ! ((! (snapshot_equality (a , b)) || (b)))",
904+
parse_prusti("assert!(a === b ==> b)".parse().unwrap()).unwrap().to_string(),
905+
"assert ! ((! (snapshot_equality (& a , & b)) || (b)))",
907906
);
908907
}
909908

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
use prusti_contracts::*;
2+
3+
#[requires(a === b)]
4+
fn foo<T>(a: T, b: T) {}
5+
6+
struct X { a: i32 }
7+
8+
fn test1() {
9+
foo(4, 5); //~ ERROR precondition might not hold
10+
}
11+
12+
fn test2() {
13+
foo(false, true); //~ ERROR precondition might not hold
14+
}
15+
16+
fn test3() {
17+
foo((1, 1), (1, 2)); //~ ERROR precondition might not hold
18+
}
19+
20+
fn test4() {
21+
foo(X { a: 2 }, X { a: 1 }); //~ ERROR precondition might not hold
22+
}
23+
24+
#[trusted]
25+
fn main() {}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
use prusti_contracts::*;
2+
3+
#[requires(a === b)]
4+
fn foo<T>(a: T, b: T) {}
5+
6+
struct X { a: i32 }
7+
8+
fn main() {
9+
foo(5, 5);
10+
foo(true, true);
11+
foo((1, 2), (1, 2));
12+
foo(X { a: 1 }, X { a: 1 });
13+
}

prusti-viper/src/encoder/mir/pure/pure_functions/interpreter.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -566,11 +566,12 @@ impl<'p, 'v: 'p, 'tcx: 'v> BackwardMirInterpreter<'tcx>
566566

567567
// Prusti-specific syntax
568568
// TODO: check we are in a spec function
569-
"prusti_contracts::implication"
570-
| "prusti_contracts::exists"
569+
"prusti_contracts::exists"
571570
| "prusti_contracts::forall"
572571
| "prusti_contracts::specification_entailment"
573-
| "prusti_contracts::call_description" => {
572+
| "prusti_contracts::call_description"
573+
| "prusti_contracts::snap"
574+
| "prusti_contracts::snapshot_equality" => {
574575
let expr = self.encoder.encode_prusti_operation(
575576
full_func_proc_name,
576577
span,

prusti-viper/src/encoder/mir/pure/specifications/interface.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,11 @@ impl<'v, 'tcx: 'v> SpecificationEncoderInterface<'tcx> for crate::encoder::Encod
247247
parent_def_id,
248248
substs,
249249
),
250+
"prusti_contracts::snap" => Ok(vir_poly::Expr::snap_app(encoded_args[0].clone())),
251+
"prusti_contracts::snapshot_equality" => Ok(vir_poly::Expr::eq_cmp(
252+
vir_poly::Expr::snap_app(encoded_args[0].clone()),
253+
vir_poly::Expr::snap_app(encoded_args[1].clone()),
254+
)),
250255
_ => unimplemented!(),
251256
}
252257
}

0 commit comments

Comments
 (0)