Skip to content

Commit 4c11fa0

Browse files
paaassscccaaalllPascal Hollenstein
authored andcommitted
added loop_invariant (which is true at start and end of loop)
renamed LoopSpecification enum for bodyinvariant! from Invariant to BodyInvariant
1 parent 8d72822 commit 4c11fa0

File tree

7 files changed

+44
-4
lines changed

7 files changed

+44
-4
lines changed

prusti-contracts/prusti-contracts-proc-macros/src/lib.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ pub fn body_invariant(_tokens: TokenStream) -> TokenStream {
5858
TokenStream::new()
5959
}
6060

61+
#[cfg(not(feature = "prusti"))]
62+
#[proc_macro]
63+
pub fn loop_invariant(_tokens: TokenStream) -> TokenStream {
64+
TokenStream::new()
65+
}
66+
6167
#[cfg(not(feature = "prusti"))]
6268
#[proc_macro]
6369
pub fn prusti_assert(_tokens: TokenStream) -> TokenStream {
@@ -189,6 +195,12 @@ pub fn body_invariant(tokens: TokenStream) -> TokenStream {
189195
prusti_specs::body_invariant(tokens.into()).into()
190196
}
191197

198+
#[cfg(feature = "prusti")]
199+
#[proc_macro]
200+
pub fn loop_invariant(tokens: TokenStream) -> TokenStream {
201+
prusti_specs::loop_invariant_expr(tokens.into()).into()
202+
}
203+
192204
#[cfg(feature = "prusti")]
193205
#[proc_macro]
194206
pub fn prusti_assert(tokens: TokenStream) -> TokenStream {

prusti-contracts/prusti-contracts/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ pub use prusti_contracts_proc_macros::invariant;
2727
/// A macro for writing a loop body invariant.
2828
pub use prusti_contracts_proc_macros::body_invariant;
2929

30+
/// A macro to annotate loop invariants (Holds at start and end of the loop)
31+
pub use prusti_contracts_proc_macros::loop_invariant;
32+
3033
/// A macro for writing assertions using the full prusti specifications
3134
pub use prusti_contracts_proc_macros::prusti_assert;
3235

prusti-contracts/prusti-specs/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,10 @@ pub fn body_variant(tokens: TokenStream) -> TokenStream {
420420
}
421421

422422
pub fn body_invariant(tokens: TokenStream) -> TokenStream {
423+
generate_expression_closure(&AstRewriter::process_body_invariant, tokens)
424+
}
425+
426+
pub fn loop_invariant_expr(tokens: TokenStream) -> TokenStream {
423427
generate_expression_closure(&AstRewriter::process_loop_invariant, tokens)
424428
}
425429

prusti-contracts/prusti-specs/src/rewriter.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,14 +240,23 @@ impl AstRewriter {
240240
}
241241

242242
/// Parse a loop invariant into a Rust expression
243-
pub fn process_loop_invariant(
243+
pub fn process_body_invariant(
244244
&mut self,
245245
spec_id: SpecificationId,
246246
tokens: TokenStream,
247247
) -> syn::Result<TokenStream> {
248248
self.process_prusti_expression(quote! {loop_body_invariant_spec}, spec_id, tokens)
249249
}
250250

251+
/// Parse a proper loop invariant into a Rust expression
252+
pub fn process_loop_invariant(
253+
&mut self,
254+
spec_id: SpecificationId,
255+
tokens: TokenStream,
256+
) -> syn::Result<TokenStream> {
257+
self.process_prusti_expression(quote! {loop_invariant_spec}, spec_id, tokens)
258+
}
259+
251260
/// Parse a prusti assertion into a Rust expression
252261
pub fn process_prusti_assertion(
253262
&mut self,

prusti-encoder/src/encoders/impure/loop.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ impl<'vir, 'enc, E: TaskEncoder> ImpureEncVisitor<'vir, 'enc, E> {
312312
{
313313
let is_loop_invariant = spec::with_type_spec(|def_spec| {
314314
if let Some(loop_spec) = def_spec.get_loop_spec(cl_def_id) {
315-
assert!(!matches!(loop_spec, prusti_interface::specs::typed::LoopSpecification::Invariant(_)), "body_invariant! currently not supported");
315+
assert!(!matches!(loop_spec, prusti_interface::specs::typed::LoopSpecification::BodyInvariant(_)), "body_invariant! currently not supported");
316316
matches!(loop_spec, prusti_interface::specs::typed::LoopSpecification::LoopInvariant(_))
317317
} else {
318318
false

prusti-interface/src/specs/mod.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ pub struct SpecCollector<'a, 'tcx> {
8181
/// Map from functions/loops/types to their specifications.
8282
procedure_specs: FxHashMap<LocalDefId, ProcedureSpecRefs>,
8383
loop_specs: Vec<LocalDefId>,
84+
loop_invariants: Vec<LocalDefId>,
8485
loop_variants: Vec<LocalDefId>,
8586
type_specs: FxHashMap<LocalDefId, TypeSpecRefs>,
8687
prusti_assertions: Vec<LocalDefId>,
@@ -98,6 +99,7 @@ impl<'a, 'tcx> SpecCollector<'a, 'tcx> {
9899
spec_functions: FxHashMap::default(),
99100
procedure_specs: FxHashMap::default(),
100101
loop_specs: vec![],
102+
loop_invariants: vec![],
101103
loop_variants: vec![],
102104
type_specs: FxHashMap::default(),
103105
prusti_assertions: vec![],
@@ -220,7 +222,13 @@ impl<'a, 'tcx> SpecCollector<'a, 'tcx> {
220222
for local_id in self.loop_specs.iter() {
221223
def_spec.loop_specs.insert(
222224
local_id.to_def_id(),
223-
typed::LoopSpecification::Invariant(*local_id),
225+
typed::LoopSpecification::BodyInvariant(*local_id),
226+
);
227+
}
228+
for local_id in self.loop_invariants.iter() {
229+
def_spec.loop_specs.insert(
230+
local_id.to_def_id(),
231+
typed::LoopSpecification::LoopInvariant(*local_id),
224232
);
225233
}
226234
for local_id in self.loop_variants.iter() {
@@ -487,6 +495,9 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for SpecCollector<'a, 'tcx> {
487495
if has_prusti_attr(attrs, "loop_body_invariant_spec") {
488496
self.loop_specs.push(local_id);
489497
}
498+
if has_prusti_attr(attrs, "loop_invariant_spec") {
499+
self.loop_invariants.push(local_id);
500+
}
490501
if has_prusti_attr(attrs, "loop_body_variant_spec") {
491502
self.loop_variants.push(local_id);
492503
}

prusti-interface/src/specs/typed.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,8 @@ impl ProcedureSpecificationKind {
264264

265265
#[derive(Debug, Clone)]
266266
pub enum LoopSpecification {
267-
Invariant(LocalDefId),
267+
BodyInvariant(LocalDefId), // body_invariant!() - true at call site in loop body
268+
LoopInvariant(LocalDefId), // invariant!() - true at loop head/start and end of iteration
268269
Variant(LocalDefId),
269270
}
270271

0 commit comments

Comments
 (0)