Skip to content

Commit

Permalink
add support of abort when in spec
Browse files Browse the repository at this point in the history
  • Loading branch information
rahxephon89 committed Oct 11, 2024
1 parent 1c42c29 commit 6142f77
Show file tree
Hide file tree
Showing 8 changed files with 188 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ impl<'a> ExpRewriterFunctions for SpecConverter<'a> {
.into_exp()
},
// Deal with removing various occurrences of Abort and spec blocks
Call(id, Abort, _) | SpecBlock(id, ..) => {
SpecBlock(id, ..) => {
// Replace direct call by unit
Call(*id, Tuple, vec![]).into_exp()
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ module 0x42::move_function_in_spec {
}
}
spec fun $type_of<T>(): TypeInfo {
Tuple()
Abort(1)
}
} // end 0x42::move_function_in_spec

Expand Down
21 changes: 21 additions & 0 deletions third_party/move/move-prover/boogie-backend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,27 @@ pub fn add_prelude(
sh_instances = vec![];
bv_instances = vec![];
}

let mut all_types = mono_info
.all_types
.iter()
.filter(|ty| ty.can_be_type_argument())
.map(|ty| TypeInfo::new(env, options, ty, false))
.collect::<BTreeSet<_>>()
.into_iter()
.collect_vec();
let mut bv_all_types = mono_info
.all_types
.iter()
.filter(|ty| ty.can_be_type_argument())
.map(|ty| TypeInfo::new(env, options, ty, true))
.filter(|ty_info| !all_types.contains(ty_info))
.collect::<BTreeSet<_>>()
.into_iter()
.collect_vec();
all_types.append(&mut bv_all_types);
context.insert("uninterpreted_instances", &all_types);

context.insert("sh_instances", &sh_instances);
context.insert("bv_instances", &bv_instances);
let mut vec_instances = mono_info
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,18 @@ options provided to the prover.
{% include "custom-natives" %}
{%- endif %}


// Uninterpreted function for all types

{% for instance in uninterpreted_instances %}

{%- set S = "'" ~ instance.suffix ~ "'" -%}
{%- set T = instance.name -%}

function $Uninterpreted_value_of_{{S}}(): {{T}};

{% endfor %}

// ============================================================================================
// Primitive Types

Expand Down
39 changes: 30 additions & 9 deletions third_party/move/move-prover/boogie-backend/src/spec_translator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -724,13 +724,18 @@ impl<'env> SpecTranslator<'env> {
// Single-element sequence is just a wrapped value.
self.translate_exp(exp_vec.first().expect("list has an element"));
},
ExpData::Return(..)
| ExpData::Sequence(..)
| ExpData::Loop(..)
| ExpData::Assign(..)
| ExpData::Mutate(..)
| ExpData::SpecBlock(..)
| ExpData::LoopCont(..) => panic!("imperative expressions not supported"),
ExpData::Return(id, ..)
| ExpData::Sequence(id, ..)
| ExpData::Loop(id, ..)
| ExpData::Assign(id, ..)
| ExpData::Mutate(id, ..)
| ExpData::SpecBlock(id, ..)
| ExpData::LoopCont(id, ..) => {
self.env.error(
&self.env.get_node_loc(*id),
"imperative expressions not supported in specs",
);
},

Check warning on line 738 in third_party/move/move-prover/boogie-backend/src/spec_translator.rs

View check run for this annotation

Codecov / codecov/patch

third_party/move/move-prover/boogie-backend/src/spec_translator.rs#L727-L738

Added lines #L727 - L738 were not covered by tests
}
}

Expand Down Expand Up @@ -991,15 +996,31 @@ impl<'env> SpecTranslator<'env> {
self.translate_call(node_id, oper, &[args[args.len() - 1].clone()]);
emit!(self.writer, &")".repeat(count));
},
Operation::Abort => {
let exp_bv_flag = global_state.get_node_num_oper(node_id) == Bitwise;
emit!(
self.writer,
&format!(
"$Uninterpreted_value_of_'{}'()",
boogie_type_suffix_bv(self.env, &self.get_node_type(node_id), exp_bv_flag)
)
);
},
Operation::MoveFunction(_, _)
| Operation::BorrowGlobal(_)
| Operation::Borrow(..)
| Operation::Deref
| Operation::MoveTo
| Operation::MoveFrom
| Operation::Abort
| Operation::Old => {
panic!("operation unexpected: {}", oper.display(self.env, node_id))
self.env.error(
&self.env.get_node_loc(node_id),
&format!(
"operation {} is not supported \
in the current context",
oper.display(self.env, node_id)
),
);

Check warning on line 1023 in third_party/move/move-prover/boogie-backend/src/spec_translator.rs

View check run for this annotation

Codecov / codecov/patch

third_party/move/move-prover/boogie-backend/src/spec_translator.rs#L1016-L1023

Added lines #L1016 - L1023 were not covered by tests
},
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
module 0x42::TestAbortInFunction {

fun aborts_with(x: u64, y: u64): u64 {
if (x == 1) {
abort 2
} else if (y == 2) {
abort 3
} else {
x
}
}
spec aborts_with {
aborts_if x == 1 with 2;
aborts_if y == 2 with 3;
ensures result == x;
}

fun call_aborts_with(): u64 {
aborts_with(2, 3)
}

spec call_aborts_with {
ensures result == aborts_with(2, 3);
}

fun abort_generic<Element: copy + drop>(x: Element, y: Element): Element {
if (x == y) {
abort 0
} else {
x
}
}

fun call_aborts_generic(): u64 {
abort_generic(2, 3)
}

spec call_aborts_generic {
ensures result == abort_generic(2, 3);
}

struct S<Element: copy + drop> has copy, drop {
value: Element
}

fun abort_generic_struct<Element: copy + drop>(x: S<Element>, y: S<Element>): S<Element> {
if (x == y) {
abort 0
} else {
x
}
}

fun spec_abort_generic_struct<Element: copy + drop>(x: S<Element>, y: S<Element>): S<Element> {
if (x == y) {
abort 0
} else {
x
}
}

fun call_abort_generic_struct<Element: copy + drop>(x: Element, y: Element): Element {
let sx = S {
value: x
};
let sy = S {
value: y
};
abort_generic_struct(sx, sy).value
}

spec call_abort_generic_struct {
aborts_if x == y;
ensures result == call_abort_generic_struct(x, y);
}

struct T has copy, drop {
v: u64
}

spec T {
pragma bv=b"0";
}

fun call_abort_generic_struct_concrete(x: u64, y: u64, test_assert1: bool): T {
let sx = S {
value: T {
v: x
}
};
let sy = S {
value: T {
v: y
}
};
assert!(test_assert1, 0);
abort_generic_struct(sx, sy).value
}

spec call_abort_generic_struct_concrete {
aborts_if x == y;
aborts_if !test_assert1;
ensures result == call_abort_generic_struct_concrete(x, y, test_assert1);
ensures result == spec_call_abort_generic_struct_concrete(x, y);
}

spec fun spec_call_abort_generic_struct_concrete(x: u64, y: u64): T {
let sx = S {
value: T {
v: x
}
};
let sy = S {
value: T {
v: y
}
};
spec_abort_generic_struct(sx, sy).value
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ error: induction case of the loop invariant does not hold
= at tests/sources/functional/loops_with_memory_ops.move:80: nested_loop2
= at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2
= b = <redacted>
= at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2
= a = <redacted>
= at tests/sources/functional/loops_with_memory_ops.move:85: nested_loop2
= i = <redacted>
Expand Down Expand Up @@ -104,8 +105,8 @@ error: unknown assertion failed
= at tests/sources/functional/loops_with_memory_ops.move:80: nested_loop2
= at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2
= b = <redacted>
= a = <redacted>
= at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2
= a = <redacted>
= at tests/sources/functional/loops_with_memory_ops.move:85: nested_loop2
= i = <redacted>
= at tests/sources/functional/loops_with_memory_ops.move:86: nested_loop2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ error: induction case of the loop invariant does not hold
= at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2
= a = <redacted>
= b = <redacted>
= at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2
= at tests/sources/functional/loops_with_memory_ops.move:85: nested_loop2
= <redacted> = <redacted>
= i = <redacted>
Expand Down Expand Up @@ -100,9 +99,6 @@ error: unknown assertion failed
= at tests/sources/functional/loops_with_memory_ops.move:75: nested_loop2
= at tests/sources/functional/loops_with_memory_ops.move:80: nested_loop2
= at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2
= a = <redacted>
= at tests/sources/functional/loops_with_memory_ops.move:81: nested_loop2
= b = <redacted>
= at tests/sources/functional/loops_with_memory_ops.move:85: nested_loop2
= <redacted> = <redacted>
= i = <redacted>
Expand Down

0 comments on commit 6142f77

Please sign in to comment.