Skip to content

Commit

Permalink
Merge #1123
Browse files Browse the repository at this point in the history
1123: Snapshot equality r=Aurel300 a=Aurel300

Pulling this out of #980. `@vakaras` 

Co-authored-by: Aurel Bílý <[email protected]>
  • Loading branch information
bors[bot] and Aurel300 authored Aug 8, 2022
2 parents 6cd20c1 + 83c89ab commit 43cb956
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 8 deletions.
21 changes: 21 additions & 0 deletions prusti-contracts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,12 +343,33 @@ pub fn old<T>(arg: T) -> T {
arg
}

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

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

/// Creates an owned copy of a reference. This should only be used from within
/// ghost code, as it circumvents the borrow checker.
pub fn snap<T>(_x: &T) -> T {
unimplemented!()
}

/// Snapshot, "logical", or "mathematical" equality. Compares the in-memory
/// representation of two instances of the same type, even if there is no
/// `PartialEq` nor `Copy` implementation. The in-memory representation is
/// constructed recursively: references are followed, unsafe pointers and cells
/// are not. Importantly, addresses are not taken into consideration.
pub fn snapshot_equality<T>(_l: T, _r: T) -> bool {
true
}

pub use private::*;
9 changes: 4 additions & 5 deletions prusti-specs/src/specifications/preparser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -797,7 +797,7 @@ impl PrustiBinaryOp {
}
Self::Or => quote_spanned! { span => #lhs || #rhs },
Self::And => quote_spanned! { span => #lhs && #rhs },
Self::SnapEq => quote_spanned! { span => snapshot_equality(#lhs, #rhs) },
Self::SnapEq => quote_spanned! { span => snapshot_equality(&#lhs, &#rhs) },
}
}
}
Expand Down Expand Up @@ -894,16 +894,15 @@ mod tests {
);
assert_eq!(
parse_prusti("exists(|x: i32| a === b)".parse().unwrap()).unwrap().to_string(),
"exists (() , # [prusti :: spec_only] | x : i32 | -> bool { ((snapshot_equality (a , b)) : bool) })",
"exists (() , # [prusti :: spec_only] | x : i32 | -> bool { ((snapshot_equality (& a , & b)) : bool) })",
);
assert_eq!(
parse_prusti("forall(|x: i32| a ==> b, triggers = [(c,), (d, e)])".parse().unwrap()).unwrap().to_string(),
"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) })",
);
let expr: syn::Expr = syn::parse2("assert!(a === b ==> b)".parse().unwrap()).unwrap();
assert_eq!(
parse_prusti(quote! { #expr }).unwrap().to_string(),
"assert ! ((! (snapshot_equality (a , b)) || (b)))",
parse_prusti("assert!(a === b ==> b)".parse().unwrap()).unwrap().to_string(),
"assert ! ((! (snapshot_equality (& a , & b)) || (b)))",
);
}

Expand Down
25 changes: 25 additions & 0 deletions prusti-tests/tests/verify_overflow/fail/generic/snap-eq.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use prusti_contracts::*;

#[requires(a === b)]
fn foo<T>(a: T, b: T) {}

struct X { a: i32 }

fn test1() {
foo(4, 5); //~ ERROR precondition might not hold
}

fn test2() {
foo(false, true); //~ ERROR precondition might not hold
}

fn test3() {
foo((1, 1), (1, 2)); //~ ERROR precondition might not hold
}

fn test4() {
foo(X { a: 2 }, X { a: 1 }); //~ ERROR precondition might not hold
}

#[trusted]
fn main() {}
13 changes: 13 additions & 0 deletions prusti-tests/tests/verify_overflow/pass/generic/snap-eq.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use prusti_contracts::*;

#[requires(a === b)]
fn foo<T>(a: T, b: T) {}

struct X { a: i32 }

fn main() {
foo(5, 5);
foo(true, true);
foo((1, 2), (1, 2));
foo(X { a: 1 }, X { a: 1 });
}
Original file line number Diff line number Diff line change
Expand Up @@ -566,11 +566,12 @@ impl<'p, 'v: 'p, 'tcx: 'v> BackwardMirInterpreter<'tcx>

// Prusti-specific syntax
// TODO: check we are in a spec function
"prusti_contracts::implication"
| "prusti_contracts::exists"
"prusti_contracts::exists"
| "prusti_contracts::forall"
| "prusti_contracts::specification_entailment"
| "prusti_contracts::call_description" => {
| "prusti_contracts::call_description"
| "prusti_contracts::snap"
| "prusti_contracts::snapshot_equality" => {
let expr = self.encoder.encode_prusti_operation(
full_func_proc_name,
span,
Expand Down
5 changes: 5 additions & 0 deletions prusti-viper/src/encoder/mir/pure/specifications/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,11 @@ impl<'v, 'tcx: 'v> SpecificationEncoderInterface<'tcx> for crate::encoder::Encod
parent_def_id,
substs,
),
"prusti_contracts::snap" => Ok(vir_poly::Expr::snap_app(encoded_args[0].clone())),
"prusti_contracts::snapshot_equality" => Ok(vir_poly::Expr::eq_cmp(
vir_poly::Expr::snap_app(encoded_args[0].clone()),
vir_poly::Expr::snap_app(encoded_args[1].clone()),
)),
_ => unimplemented!(),
}
}
Expand Down

0 comments on commit 43cb956

Please sign in to comment.