Skip to content

Commit b6a3829

Browse files
committed
Replace old in invariant expressions
1 parent 8a3efcf commit b6a3829

File tree

3 files changed

+73
-11
lines changed

3 files changed

+73
-11
lines changed

src/lib.rs

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,9 @@ fn verify_method(m: &Method, cx: &mut slang_ui::Context, solver: &mut Solver<Z3B
376376

377377
let dsa = ivl_to_dsa(&ivl, &mut HashMap::new())?;
378378

379+
380+
//println!("Method {} IVL {:#?}", m.name.to_string(), ivl.to_string());
381+
379382
// Calculate obligation and error message (if obligation is not
380383
// verified)
381384
let wp_list = wp_set(&dsa, vec![])?;
@@ -854,7 +857,7 @@ fn return_to_ivl(expr: Option<&Expr>, span: &Span, method_context: &MethodContex
854857

855858
fn loop_to_ivl(invariants: &Vec<Expr>, variant: &Option<Expr>, cases: &Cases, method_context: &MethodContext) -> Result<IVLCmd, Error> {
856859
let mut result = IVLCmd::assert(&Expr::new_typed(ExprKind::Bool(true), Type::Bool), "Please don't fail!");
857-
860+
858861
match variant {
859862
Some(variant_expr) => {
860863
let mut variant_entry_assertion = IVLCmd::assert(&Expr::op(variant_expr, Op::Ge, &Expr::num(0)), "Loop variant might not be non-negative on entry");
@@ -867,10 +870,11 @@ fn loop_to_ivl(invariants: &Vec<Expr>, variant: &Option<Expr>, cases: &Cases, me
867870
let mut loop_invariants_assertions: Vec<(Expr, Expr)> = Vec::new();
868871
for invariant in invariants {
869872
let expr_without_broke = replace_broke_in_expression(invariant, false);
873+
let expr_without_old = replace_old_in_expression(&expr_without_broke, &method_context.global_variables_old_values);
870874
result = result.seq(&IVLCmd::assert(
871-
&expr_without_broke,
875+
&expr_without_old,
872876
&format!("Loop invariant {} might not hold on entry", invariant.to_string())));
873-
loop_invariants_assertions.push((invariant.clone(), expr_without_broke.clone()));
877+
loop_invariants_assertions.push((invariant.clone(), expr_without_old.clone()));
874878
}
875879

876880
for case in cases.cases.clone() {
@@ -882,7 +886,8 @@ fn loop_to_ivl(invariants: &Vec<Expr>, variant: &Option<Expr>, cases: &Cases, me
882886

883887
for invariant in invariants {
884888
let expr_without_broke = replace_broke_in_expression(invariant, false);
885-
result = result.seq(&IVLCmd::assume(&expr_without_broke))
889+
let expr_without_old = replace_old_in_expression(&expr_without_broke, &method_context.global_variables_old_values);
890+
result = result.seq(&IVLCmd::assume(&expr_without_old))
886891
}
887892

888893
let variant_assertion = match variant {
@@ -910,7 +915,7 @@ fn loop_to_ivl(invariants: &Vec<Expr>, variant: &Option<Expr>, cases: &Cases, me
910915
}
911916
new_cases.push(Case {
912917
condition: case.condition.clone(),
913-
cmd:
918+
cmd:
914919
case.cmd
915920
.seq(&loop_invariants_assertions_commands)
916921
.seq(&Cmd::assert(&local_variant_assertion, &format!("Loop variant might not be decreased in case {}", case.condition.clone().to_string())))
@@ -941,7 +946,7 @@ fn loop_to_ivl(invariants: &Vec<Expr>, variant: &Option<Expr>, cases: &Cases, me
941946
}
942947

943948
}
944-
949+
945950

946951
result = result.seq(&body_translation);
947952

@@ -963,9 +968,9 @@ fn find_break_paths(command: &Cmd, context: IVLCmd, method_context: &MethodConte
963968
for case in body.cases.clone() {
964969
let ivl_for_condition = IVLCmd::assume(&case.condition);
965970
let paths_for_case = find_break_paths(
966-
&case.cmd,
967-
match_context.seq(&ivl_for_condition),
968-
method_context,
971+
&case.cmd,
972+
match_context.seq(&ivl_for_condition),
973+
method_context,
969974
loop_context)?;
970975
paths.extend(paths_for_case);
971976
match_context = match_context.seq(&IVLCmd::assume(&Expr::prefix(&case.condition, PrefixOp::Not)));
@@ -1261,14 +1266,14 @@ fn replace_in_expression(original_expression: &Expr, identifier: &Name, replace_
12611266
ExprKind::Ident(name) if name.0 == identifier.ident.0 => replace_with_identifier.clone(),
12621267
ExprKind::Prefix(op, expr) => Expr::new_typed(
12631268
ExprKind::Prefix(
1264-
*op,
1269+
*op,
12651270
Box::new(replace_in_expression(expr, identifier, replace_with_identifier))
12661271
),
12671272
original_expression.ty.clone()),
12681273
ExprKind::Infix(lhs, op, rhs) => Expr::new_typed(
12691274
ExprKind::Infix(
12701275
Box::new(replace_in_expression(lhs, identifier, replace_with_identifier)),
1271-
*op,
1276+
*op,
12721277
Box::new(replace_in_expression(rhs, identifier, replace_with_identifier))
12731278
),
12741279
original_expression.ty.clone()),

tests/global-loop-old-bad.slang

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
global i: Int
2+
3+
method sum(n: Int)
4+
modifies i
5+
requires n >= 0
6+
ensures i == old(i) + n
7+
{
8+
var j: Int := 0;
9+
assert j <= n;
10+
loop
11+
invariant j >= 0 && j <= n
12+
// @CheckError
13+
invariant i == old(i) + j
14+
{
15+
j < n =>
16+
i := i;
17+
j := j + 1
18+
}
19+
20+
}
21+
22+
23+
method c()
24+
modifies i
25+
{
26+
i := 0;
27+
sum(5);
28+
assert i == 5
29+
}

tests/global-loop-old-good.slang

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
global i: Int
2+
3+
method sum(n: Int)
4+
modifies i
5+
requires n >= 0
6+
ensures i == old(i) + n
7+
{
8+
var j: Int := 0;
9+
assert j <= n;
10+
loop
11+
invariant j >= 0 && j <= n
12+
invariant i == old(i) + j
13+
{
14+
j < n =>
15+
i := i + 1;
16+
j := j + 1
17+
}
18+
19+
}
20+
21+
22+
method c()
23+
modifies i
24+
{
25+
i := 0;
26+
sum(5);
27+
assert i == 5
28+
}

0 commit comments

Comments
 (0)