From 3e8cfef5408f1d2c5d88ed7fa4a853dc257e5610 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Tue, 22 Nov 2022 06:11:27 +0100 Subject: [PATCH 01/64] recognize and reject extern specs which define bodies for their methods --- .../src/extern_spec_rewriter/impls.rs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs index b15f96bffee..5659a7b7ed9 100644 --- a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs +++ b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs @@ -92,6 +92,13 @@ fn rewrite_plain_impl(impl_item: &mut syn::ItemImpl, new_ty: Box) -> )); } syn::ImplItem::Method(method) => { + if !is_stub(&method.block) { + return Err(syn::Error::new( + method.span(), + "Unexpected method body. (Extern specs only define specifications.)", + )); + } + let (rewritten_method, spec_items) = generate_extern_spec_method_stub( method, item_ty, @@ -124,6 +131,19 @@ fn rewrite_plain_impl(impl_item: &mut syn::ItemImpl, new_ty: Box) -> Ok(()) } +/// Recognizes method stubs, e.g. `fn foo();`. +/// +/// The absence of a body is represented in a roundabout way: +/// They have a body comprising a single verbatim item containing a single semicolon token. +fn is_stub(block: &syn::Block) -> bool { + if block.stmts.len() != 1 { return false; } + if let syn::Stmt::Item(syn::Item::Verbatim(tokens)) = &block.stmts[0] { + return tokens.to_string() == ";"; + } else { + return false; + } +} + fn rewrite_trait_impl( impl_item: syn::ItemImpl, new_ty: Box, From 6e4fcdb907f2ecd1ca67aecbb35fe026f1cd6066 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Wed, 23 Nov 2022 06:10:35 +0100 Subject: [PATCH 02/64] support multiple constraints in ghost constraints --- .../prusti-specs/src/ghost_constraints/mod.rs | 17 ++++------ .../src/specifications/preparser.rs | 33 +++++++++++-------- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/prusti-contracts/prusti-specs/src/ghost_constraints/mod.rs b/prusti-contracts/prusti-specs/src/ghost_constraints/mod.rs index d7b8145d4c8..ef3e72cee44 100644 --- a/prusti-contracts/prusti-specs/src/ghost_constraints/mod.rs +++ b/prusti-contracts/prusti-specs/src/ghost_constraints/mod.rs @@ -47,18 +47,15 @@ pub fn generate(attr: TokenStream, item: &untyped::AnyFnItem) -> GeneratedResult } fn generate_where_clause_for_spec( - trait_bounds: &syn::PredicateType, + trait_bounds: &Vec, existing_where_clause: Option<&syn::WhereClause>, ) -> syn::WhereClause { - let span = trait_bounds.span(); - if let Some(mut where_clause) = existing_where_clause.cloned() { - where_clause.predicates.push(parse_quote_spanned! {span=> - #trait_bounds - }); - where_clause - } else { + let mut where_clause = existing_where_clause.cloned().unwrap_or_else(|| syn::parse_quote!(where)); + where_clause.predicates.extend(trait_bounds.iter().map(|bound| -> syn::WherePredicate { + let span = bound.span(); parse_quote_spanned! {span=> - where #trait_bounds + #bound } - } + })); + where_clause } diff --git a/prusti-contracts/prusti-specs/src/specifications/preparser.rs b/prusti-contracts/prusti-specs/src/specifications/preparser.rs index df45fbad30a..c6503b1140b 100644 --- a/prusti-contracts/prusti-specs/src/specifications/preparser.rs +++ b/prusti-contracts/prusti-specs/src/specifications/preparser.rs @@ -493,33 +493,40 @@ impl PrustiTokenStream { #[derive(Debug)] pub struct GhostConstraint { - pub trait_bounds: syn::PredicateType, - pub comma: syn::token::Comma, + pub trait_bounds: Vec, pub specs: Vec>, } impl Parse for GhostConstraint { fn parse(input: ParseStream) -> syn::Result { Ok(GhostConstraint { - trait_bounds: parse_trait_bounds(input)?, - comma: input.parse().map_err(with_ghost_constraint_example)?, - specs: PrustiTokenStream::new(input.parse().expect("Failed to parse GhostConstraint")) + trait_bounds: parse_trait_bounds(input).map_err(with_ghost_constraint_example)?, + specs: PrustiTokenStream::new(input.parse().unwrap()) .parse_rest(|pts| pts.pop_group_of_nested_specs(input.span()))?, }) } } -fn parse_trait_bounds(input: ParseStream) -> syn::Result { +fn parse_trait_bounds(input: ParseStream) -> syn::Result> { use syn::WherePredicate::*; - let where_predicate: syn::WherePredicate = input.parse().map_err(with_ghost_constraint_example)?; - match where_predicate { - Type(type_bound) => { - validate_trait_bounds(&type_bound)?; - Ok(type_bound) + + let mut bounds: Vec = Vec::new(); + loop { + if input.peek(syn::token::Bracket) { + break; + } + let predicate = input.parse::()?; + match predicate { + Type(type_bound) => { + validate_trait_bounds(&type_bound)?; + bounds.push(type_bound); + } + Lifetime(lifetime_bound) => disallowed_lifetime_error(lifetime_bound.span())?, + Eq(eq_bound) => err(eq_bound.span(), "equality predicates are not supported in trait bounds")?, } - Lifetime(lifetime_bound) => disallowed_lifetime_error(lifetime_bound.span()), - Eq(eq_bound) => err(eq_bound.span(), "equality predicates are not supported in trait bounds"), + input.parse::()?; } + Ok(bounds) } fn disallowed_lifetime_error(span: Span) -> syn::Result { From 352baa8620628889dc0c70b4696ef0d9a703cd5e Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Mon, 28 Nov 2022 07:25:33 +0100 Subject: [PATCH 03/64] correctly support purity ghost constraints turns out the previous implementation was flawed in that it made the function pure whether or not the constraint held --- .../prusti-specs/src/ghost_constraints/mod.rs | 4 +-- prusti-contracts/prusti-specs/src/lib.rs | 23 +++++++++++------ prusti-contracts/prusti-specs/src/rewriter.rs | 24 ++++++++++++++++++ .../prusti-specs/src/specifications/common.rs | 1 + prusti-interface/src/specs/mod.rs | 25 +++++++++++++------ prusti-interface/src/specs/typed.rs | 16 ++++++++++++ .../encoder/mir/specifications/constraints.rs | 14 ++++++++--- 7 files changed, 86 insertions(+), 21 deletions(-) diff --git a/prusti-contracts/prusti-specs/src/ghost_constraints/mod.rs b/prusti-contracts/prusti-specs/src/ghost_constraints/mod.rs index ef3e72cee44..7e18cbd40b7 100644 --- a/prusti-contracts/prusti-specs/src/ghost_constraints/mod.rs +++ b/prusti-contracts/prusti-specs/src/ghost_constraints/mod.rs @@ -1,5 +1,5 @@ use crate::{ - generate_for_ensures, generate_for_requires, do_generate_for_pure, parse_ghost_constraint, untyped, GeneratedResult, + generate_for_ensures, generate_for_requires, generate_for_pure_ghost_constraint, parse_ghost_constraint, untyped, GeneratedResult, NestedSpec, }; use proc_macro2::TokenStream; @@ -18,7 +18,7 @@ pub fn generate(attr: TokenStream, item: &untyped::AnyFnItem) -> GeneratedResult let (mut generated_items, generated_attrs) = match nested_spec { NestedSpec::Ensures(tokens) => generate_for_ensures(tokens, item)?, NestedSpec::Requires(tokens) => generate_for_requires(tokens, item)?, - NestedSpec::Pure => do_generate_for_pure(item)?, + NestedSpec::Pure => generate_for_pure_ghost_constraint(item)?, }; for generated_item in generated_items.iter_mut() { diff --git a/prusti-contracts/prusti-specs/src/lib.rs b/prusti-contracts/prusti-specs/src/lib.rs index e2387b80582..18daa3f81b0 100644 --- a/prusti-contracts/prusti-specs/src/lib.rs +++ b/prusti-contracts/prusti-specs/src/lib.rs @@ -277,14 +277,6 @@ fn generate_for_pure(attr: TokenStream, item: &untyped::AnyFnItem) -> GeneratedR )); } - do_generate_for_pure(item) -} - -/// Generate spec items and attributes to typecheck and later retrieve "pure" annotations. -/// -/// This the actual generating logic called by `generate_for_pure` after checking that the body is empty. -/// It's exposed separately for use in ghost constraints. -fn do_generate_for_pure(item: &untyped::AnyFnItem) -> GeneratedResult { Ok(( vec![], vec![parse_quote_spanned! {item.span()=> @@ -293,6 +285,21 @@ fn do_generate_for_pure(item: &untyped::AnyFnItem) -> GeneratedResult { )) } +/// Generate spec items and attributes to typecheck and later retrieve "pure" annotations, but encoded as a referenced separate function that ghost constraints can apply trait bounds to. +fn generate_for_pure_ghost_constraint(item: &untyped::AnyFnItem) -> GeneratedResult { + let mut rewriter = rewriter::AstRewriter::new(); + let spec_id = rewriter.generate_spec_id(); + let spec_id_str = spec_id.to_string(); + let spec_item = rewriter.process_pure_ghost_constraint(spec_id, item)?; + + Ok(( + vec![spec_item], + vec![parse_quote_spanned! {item.span()=> + #[prusti::pure_spec_id_ref = #spec_id_str] + }], + )) +} + /// Generate spec items and attributes to typecheck and later retrieve "trusted" annotations. fn generate_for_trusted(attr: TokenStream, item: &untyped::AnyFnItem) -> GeneratedResult { if !attr.is_empty() { diff --git a/prusti-contracts/prusti-specs/src/rewriter.rs b/prusti-contracts/prusti-specs/src/rewriter.rs index e1dced3a032..2153ebfb8c4 100644 --- a/prusti-contracts/prusti-specs/src/rewriter.rs +++ b/prusti-contracts/prusti-specs/src/rewriter.rs @@ -164,6 +164,30 @@ impl AstRewriter { ) } + pub fn process_pure_ghost_constraint( + &mut self, + spec_id: SpecificationId, + item: &untyped::AnyFnItem, + ) -> syn::Result { + let item_span = item.span(); + let item_name = syn::Ident::new( + &format!("prusti_pure_ghost_item_{}", item.sig().ident), + item_span, + ); + + let spec_id_str = spec_id.to_string(); + let mut spec_item: syn::ItemFn = parse_quote_spanned! {item_span=> + #[allow(unused_must_use, unused_parens, unused_variables, dead_code)] + #[prusti::spec_only] + #[prusti::spec_id = #spec_id_str] + fn #item_name() {} // we only care about this for evaluating + }; + + spec_item.sig.generics = item.sig().generics.clone(); + spec_item.sig.inputs = item.sig().inputs.clone(); + Ok(syn::Item::Fn(spec_item)) + } + /// Parse a pledge with lhs into a Rust expression pub fn process_assert_pledge( &mut self, diff --git a/prusti-contracts/prusti-specs/src/specifications/common.rs b/prusti-contracts/prusti-specs/src/specifications/common.rs index 31b94930f79..096b439e2a8 100644 --- a/prusti-contracts/prusti-specs/src/specifications/common.rs +++ b/prusti-contracts/prusti-specs/src/specifications/common.rs @@ -56,6 +56,7 @@ pub struct SpecificationId(Uuid); pub enum SpecIdRef { Precondition(SpecificationId), Postcondition(SpecificationId), + Purity(SpecificationId), Pledge { lhs: Option, rhs: SpecificationId, diff --git a/prusti-interface/src/specs/mod.rs b/prusti-interface/src/specs/mod.rs index f959a2566a9..428351214d3 100644 --- a/prusti-interface/src/specs/mod.rs +++ b/prusti-interface/src/specs/mod.rs @@ -120,7 +120,11 @@ impl<'a, 'tcx> SpecCollector<'a, 'tcx> { for (local_id, refs) in self.procedure_specs.iter() { let mut spec = SpecGraph::new(ProcedureSpecification::empty(local_id.to_def_id())); - let mut kind = refs.into(); + // We do not want to create an empty kind. + // This would lead to refinement inheritance if there is a trait involved. + // Instead, we require the user to explicitly make annotations. + spec.set_kind(refs.into()); + let mut kind_override = None; for spec_id_ref in &refs.spec_id_refs { match spec_id_ref { @@ -133,6 +137,9 @@ impl<'a, 'tcx> SpecCollector<'a, 'tcx> { self.env, ); } + SpecIdRef::Purity(spec_id) => { + spec.add_purity(*self.spec_functions.get(spec_id).unwrap(), self.env); + } SpecIdRef::Pledge { lhs, rhs } => { spec.add_pledge(typed::Pledge { reference: None, // FIXME: Currently only `result` is supported. @@ -143,9 +150,9 @@ impl<'a, 'tcx> SpecCollector<'a, 'tcx> { }); } SpecIdRef::Predicate(spec_id) => { - kind = ProcedureSpecificationKind::Predicate(Some( + kind_override = Some(ProcedureSpecificationKind::Predicate(Some( self.spec_functions.get(spec_id).unwrap().to_def_id(), - )); + ))); } SpecIdRef::Terminates(spec_id) => { spec.set_terminates(*self.spec_functions.get(spec_id).unwrap()); @@ -155,10 +162,9 @@ impl<'a, 'tcx> SpecCollector<'a, 'tcx> { spec.set_trusted(refs.trusted); - // We do not want to create an empty kind. - // This would lead to refinement inheritance if there is a trait involved. - // Instead, we require the user to explicitly make annotations. - spec.set_kind(kind); + if let Some(kind) = kind_override { + spec.set_kind(kind); + } if !spec.specs_with_constraints.is_empty() && !prusti_common::config::enable_ghost_constraints() @@ -325,6 +331,11 @@ fn get_procedure_spec_ids(def_id: DefId, attrs: &[ast::Attribute]) -> Option>, pub trusted: SpecificationItem, pub terminates: SpecificationItem>, + pub purity: SpecificationItem>, // for ghost constraints } impl ProcedureSpecification { @@ -217,6 +218,7 @@ impl ProcedureSpecification { pledges: SpecificationItem::Empty, trusted: SpecificationItem::Inherent(false), terminates: SpecificationItem::Inherent(None), + purity: SpecificationItem::Inherent(None), } } } @@ -436,6 +438,19 @@ impl SpecGraph { } } + pub fn add_purity<'tcx>(&mut self, purity: LocalDefId, env: &Environment<'tcx>) { + match self.get_constraint(purity, env) { + None => unreachable!("separate purity defs are only used for ghost constraints"), + Some(constraint) => { + let constrained_spec = self.get_constrained_spec_mut(constraint); + constrained_spec.kind = + SpecificationItem::Inherent(ProcedureSpecificationKind::Pure); + // need to store this as well, since without pres or posts we couldn't find any def id with the trait bounds + constrained_spec.purity.set(Some(purity.to_def_id())); + } + } + } + /// Attaches the `pledge` to the base spec and all constrained specs. pub fn add_pledge(&mut self, pledge: Pledge) { self.base_spec.pledges.push(pledge.clone()); @@ -752,6 +767,7 @@ impl Refinable for ProcedureSpecification { kind: self.kind.refine(&other.kind), trusted: self.trusted.refine(&other.trusted), terminates: self.terminates.refine(&other.terminates), + purity: self.purity.refine(&other.purity), // ASK: include purity in refinement? only used for ghost constraints so doesn't really apply } } } diff --git a/prusti-viper/src/encoder/mir/specifications/constraints.rs b/prusti-viper/src/encoder/mir/specifications/constraints.rs index d3da4823b5d..1aa69277b03 100644 --- a/prusti-viper/src/encoder/mir/specifications/constraints.rs +++ b/prusti-viper/src/encoder/mir/specifications/constraints.rs @@ -58,7 +58,7 @@ impl<'spec, 'env: 'spec, 'tcx: 'env> ConstraintResolver<'spec, 'env, 'tcx> } let context = match query { - SpecQuery::GetProcKind(_, _) | SpecQuery::FetchSpan(_) => { + SpecQuery::FetchSpan(_) => { trace!("No need to resolve obligations for cause {:?}", query); return Ok(&self.base_spec); } @@ -74,7 +74,8 @@ impl<'spec, 'env: 'spec, 'tcx: 'env> ConstraintResolver<'spec, 'env, 'tcx> // Obligations are resolved for function definition encodings to account // for ghost constraints on traits (behavioral subtyping rules will be checked // against the resolved spec). - SpecQuery::FunctionDefEncoding(proc_def_id, substs) => ConstraintSolvingContext { + SpecQuery::FunctionDefEncoding(proc_def_id, substs) + | SpecQuery::GetProcKind(proc_def_id, substs) => ConstraintSolvingContext { proc_def_id: *proc_def_id, substs, caller_proc_def_id: None, @@ -131,7 +132,7 @@ fn constraint_fulfilled<'spec, 'env: 'spec, 'tcx: 'env>( } } -pub mod trait_bounds { +mod trait_bounds { use super::*; use prusti_interface::{utils::has_trait_bounds_ghost_constraint, PrustiError}; use rustc_hash::FxHashMap; @@ -231,7 +232,12 @@ pub mod trait_bounds { .expect_empty_or_inherent() .cloned() .unwrap_or_default(); - for spec_id in pres.iter().chain(posts.iter()) { + let purity = spec + .purity + .expect_empty_or_inherent() + .cloned() + .unwrap_or_default(); + for spec_id in pres.iter().chain(posts.iter()).chain(purity.iter()) { let param_env = env.tcx().param_env(spec_id); let spec_span = env.query.get_def_span(spec_id); let attrs = env.query.get_attributes(*spec_id); From 10613bef6ff9fd61ed1598c81e4b558b73441c1d Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Mon, 28 Nov 2022 07:54:11 +0100 Subject: [PATCH 04/64] require at least one bound for ghost constraints --- .../prusti-specs/src/specifications/preparser.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/prusti-contracts/prusti-specs/src/specifications/preparser.rs b/prusti-contracts/prusti-specs/src/specifications/preparser.rs index c6503b1140b..0a4ed402743 100644 --- a/prusti-contracts/prusti-specs/src/specifications/preparser.rs +++ b/prusti-contracts/prusti-specs/src/specifications/preparser.rs @@ -512,9 +512,6 @@ fn parse_trait_bounds(input: ParseStream) -> syn::Result let mut bounds: Vec = Vec::new(); loop { - if input.peek(syn::token::Bracket) { - break; - } let predicate = input.parse::()?; match predicate { Type(type_bound) => { @@ -525,6 +522,9 @@ fn parse_trait_bounds(input: ParseStream) -> syn::Result Eq(eq_bound) => err(eq_bound.span(), "equality predicates are not supported in trait bounds")?, } input.parse::()?; + if input.peek(syn::token::Bracket) { + break; + } } Ok(bounds) } From ab1f1099bf960f3e118c58381071c631d6f11be2 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Mon, 28 Nov 2022 07:59:14 +0100 Subject: [PATCH 05/64] report example structure only when it makes sense --- .../prusti-specs/src/specifications/preparser.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/prusti-contracts/prusti-specs/src/specifications/preparser.rs b/prusti-contracts/prusti-specs/src/specifications/preparser.rs index 0a4ed402743..56fb5ac1744 100644 --- a/prusti-contracts/prusti-specs/src/specifications/preparser.rs +++ b/prusti-contracts/prusti-specs/src/specifications/preparser.rs @@ -500,7 +500,7 @@ pub struct GhostConstraint { impl Parse for GhostConstraint { fn parse(input: ParseStream) -> syn::Result { Ok(GhostConstraint { - trait_bounds: parse_trait_bounds(input).map_err(with_ghost_constraint_example)?, + trait_bounds: parse_trait_bounds(input)?, specs: PrustiTokenStream::new(input.parse().unwrap()) .parse_rest(|pts| pts.pop_group_of_nested_specs(input.span()))?, }) @@ -512,7 +512,7 @@ fn parse_trait_bounds(input: ParseStream) -> syn::Result let mut bounds: Vec = Vec::new(); loop { - let predicate = input.parse::()?; + let predicate = input.parse::().map_err(with_ghost_constraint_example)?; match predicate { Type(type_bound) => { validate_trait_bounds(&type_bound)?; @@ -521,7 +521,7 @@ fn parse_trait_bounds(input: ParseStream) -> syn::Result Lifetime(lifetime_bound) => disallowed_lifetime_error(lifetime_bound.span())?, Eq(eq_bound) => err(eq_bound.span(), "equality predicates are not supported in trait bounds")?, } - input.parse::()?; + input.parse::().map_err(with_ghost_constraint_example)?; if input.peek(syn::token::Bracket) { break; } From b5e3776e3506ac961909afb6d7299c8ca2950822 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Mon, 28 Nov 2022 07:59:30 +0100 Subject: [PATCH 06/64] add compiletests for ghost constraint purity --- .../tests/verify/fail/ghost-constraints/purity.rs | 14 ++++++++++++++ .../tests/verify/pass/ghost-constraints/purity.rs | 11 +++++++++++ 2 files changed, 25 insertions(+) create mode 100644 prusti-tests/tests/verify/fail/ghost-constraints/purity.rs create mode 100644 prusti-tests/tests/verify/pass/ghost-constraints/purity.rs diff --git a/prusti-tests/tests/verify/fail/ghost-constraints/purity.rs b/prusti-tests/tests/verify/fail/ghost-constraints/purity.rs new file mode 100644 index 00000000000..b7b262bda52 --- /dev/null +++ b/prusti-tests/tests/verify/fail/ghost-constraints/purity.rs @@ -0,0 +1,14 @@ +// compile-flags: -Penable_ghost_constraints=true + +use prusti_contracts::*; + +#[ghost_constraint(T: Copy, [pure])] +#[trusted] +fn test(_t: T) -> bool { true } + +#[derive(Clone, PartialEq, Eq)] +struct Copyrighted; // not Copy + +fn main() { + prusti_assert!(test(Copyrighted) == test(Copyrighted)); //~ ERROR: [Prusti: invalid specification] use of impure function "test" in pure code is not allowed +} diff --git a/prusti-tests/tests/verify/pass/ghost-constraints/purity.rs b/prusti-tests/tests/verify/pass/ghost-constraints/purity.rs new file mode 100644 index 00000000000..2de4b07e018 --- /dev/null +++ b/prusti-tests/tests/verify/pass/ghost-constraints/purity.rs @@ -0,0 +1,11 @@ +// compile-flags: -Penable_ghost_constraints=true + +use prusti_contracts::*; + +#[ghost_constraint(T: Copy, [pure])] +#[trusted] +fn test(_t: T) -> bool { true } + +fn main() { + assert!(test(5) == test(5)); +} From 18ac66972722d3092bbcbec9b9f3f39f2021da76 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Mon, 28 Nov 2022 08:04:30 +0100 Subject: [PATCH 07/64] auto-format prusti-specs crate --- prusti-contracts/prusti-specs/src/common.rs | 85 +-- .../src/extern_spec_rewriter/common.rs | 123 ++-- .../src/extern_spec_rewriter/impls.rs | 31 +- .../src/extern_spec_rewriter/traits.rs | 53 +- .../prusti-specs/src/ghost_constraints/mod.rs | 22 +- prusti-contracts/prusti-specs/src/lib.rs | 171 +++--- .../prusti-specs/src/parse_closure_macro.rs | 4 +- .../prusti-specs/src/predicate.rs | 6 +- prusti-contracts/prusti-specs/src/rewriter.rs | 14 +- .../prusti-specs/src/span_overrider.rs | 8 +- .../prusti-specs/src/spec_attribute_kind.rs | 4 +- .../prusti-specs/src/specifications/common.rs | 33 +- .../prusti-specs/src/specifications/mod.rs | 4 +- .../src/specifications/preparser.rs | 529 ++++++++++-------- .../src/specifications/untyped.rs | 16 +- .../prusti-specs/src/type_model/mod.rs | 13 +- .../src/user_provided_type_params.rs | 2 +- x.py | 2 +- 18 files changed, 620 insertions(+), 500 deletions(-) diff --git a/prusti-contracts/prusti-specs/src/common.rs b/prusti-contracts/prusti-specs/src/common.rs index 3a4e1513715..91ef613b99f 100644 --- a/prusti-contracts/prusti-specs/src/common.rs +++ b/prusti-contracts/prusti-specs/src/common.rs @@ -1,20 +1,20 @@ //! Common code for spec-rewriting -use std::borrow::BorrowMut; -use std::collections::HashMap; use proc_macro2::Ident; -use syn::{GenericParam, parse_quote, TypeParam}; -use syn::punctuated::Punctuated; -use syn::spanned::Spanned; -use uuid::Uuid; -pub(crate) use syn_extensions::*; -pub(crate) use self_type_rewriter::*; pub(crate) use receiver_rewriter::*; +pub(crate) use self_type_rewriter::*; +use std::{borrow::BorrowMut, collections::HashMap}; +use syn::{parse_quote, punctuated::Punctuated, spanned::Spanned, GenericParam, TypeParam}; +pub(crate) use syn_extensions::*; +use uuid::Uuid; /// Module which provides various extension traits for syn types. /// These allow for writing of generic code over these types. mod syn_extensions { - use syn::{Attribute, Generics, ImplItemMacro, ImplItemMethod, ItemFn, ItemImpl, ItemStruct, ItemTrait, Macro, Signature, TraitItemMacro, TraitItemMethod}; + use syn::{ + Attribute, Generics, ImplItemMacro, ImplItemMethod, ItemFn, ItemImpl, ItemStruct, + ItemTrait, Macro, Signature, TraitItemMacro, TraitItemMethod, + }; /// Trait which signals that the corresponding syn item contains generics pub(crate) trait HasGenerics { @@ -26,28 +26,36 @@ mod syn_extensions { fn generics(&self) -> &Generics { self } - fn generics_mut(&mut self) -> &mut Generics { self } + fn generics_mut(&mut self) -> &mut Generics { + self + } } impl HasGenerics for ItemTrait { fn generics(&self) -> &Generics { &self.generics } - fn generics_mut(&mut self) -> &mut Generics { &mut self.generics } + fn generics_mut(&mut self) -> &mut Generics { + &mut self.generics + } } impl HasGenerics for ItemStruct { fn generics(&self) -> &Generics { &self.generics } - fn generics_mut(&mut self) -> &mut Generics { &mut self.generics } + fn generics_mut(&mut self) -> &mut Generics { + &mut self.generics + } } impl HasGenerics for ItemImpl { fn generics(&self) -> &syn::Generics { &self.generics } - fn generics_mut(&mut self) -> &mut Generics { &mut self.generics } + fn generics_mut(&mut self) -> &mut Generics { + &mut self.generics + } } /// Abstraction over everything that has a [syn::Signature] @@ -129,7 +137,7 @@ mod syn_extensions { &self.attrs } } - + impl HasAttributes for ItemFn { fn attrs(&self) -> &Vec { &self.attrs @@ -241,9 +249,10 @@ mod self_type_rewriter { mod receiver_rewriter { use proc_macro2::{Ident, TokenStream, TokenTree}; use quote::{quote, quote_spanned}; - use syn::{FnArg, ImplItemMethod, ItemFn, Macro, parse_quote_spanned, Type}; - use syn::spanned::Spanned; - use syn::visit_mut::VisitMut; + use syn::{ + parse_quote_spanned, spanned::Spanned, visit_mut::VisitMut, FnArg, ImplItemMethod, ItemFn, + Macro, Type, + }; /// Rewrites the receiver of a method-like item. /// This can be used to convert impl methods to free-standing functions. @@ -267,14 +276,14 @@ mod receiver_rewriter { impl RewritableReceiver for ImplItemMethod { fn rewrite_receiver(&mut self, new_ty: &Type) { - let mut rewriter = Rewriter {new_ty}; + let mut rewriter = Rewriter { new_ty }; rewriter.rewrite_impl_item_method(self); } } impl RewritableReceiver for ItemFn { fn rewrite_receiver(&mut self, new_ty: &Type) { - let mut rewriter = Rewriter {new_ty}; + let mut rewriter = Rewriter { new_ty }; rewriter.rewrite_item_fn(self); } } @@ -296,13 +305,15 @@ mod receiver_rewriter { let tokens_span = tokens.span(); let rewritten = TokenStream::from_iter(tokens.into_iter().map(|token| match token { TokenTree::Group(group) => { - let new_group = - proc_macro2::Group::new(group.delimiter(), Self::rewrite_tokens(group.stream())); + let new_group = proc_macro2::Group::new( + group.delimiter(), + Self::rewrite_tokens(group.stream()), + ); TokenTree::Group(new_group) } TokenTree::Ident(ident) if ident == "self" => { TokenTree::Ident(proc_macro2::Ident::new("_self", ident.span())) - }, + } other => other, })); parse_quote_spanned! {tokens_span=> @@ -316,17 +327,15 @@ mod receiver_rewriter { if let FnArg::Receiver(receiver) = fn_arg { let span = receiver.span(); let and = match &receiver.reference { - Some((_, Some(lifetime))) => - quote_spanned!{span => &#lifetime}, - Some((_, None)) => - quote_spanned!{span => &}, - None => quote! {} + Some((_, Some(lifetime))) => quote_spanned! {span => &#lifetime}, + Some((_, None)) => quote_spanned! {span => &}, + None => quote! {}, }; let mutability = &receiver.mutability; let new_ty = self.new_ty; let new_fn_arg: FnArg = parse_quote_spanned! {span=> - _self : #and #mutability #new_ty - }; + _self : #and #mutability #new_ty + }; *fn_arg = new_fn_arg; } else { syn::visit_mut::visit_fn_arg_mut(self, fn_arg); @@ -380,9 +389,12 @@ pub(crate) fn merge_generics(target: &mut T, source: &T) { if let GenericParam::Type(type_param_source) = param_source { // We can remove the target type param here, because the source will not have the // same type param with the same identifiers - let maybe_type_param_source = existing_target_type_params.remove(&type_param_source.ident); + let maybe_type_param_source = + existing_target_type_params.remove(&type_param_source.ident); if let Some(type_param_target) = maybe_type_param_source { - type_param_target.bounds.extend(type_param_source.bounds.clone()); + type_param_target + .bounds + .extend(type_param_source.bounds.clone()); } else { new_generic_params.push(GenericParam::Type(type_param_source.clone())); } @@ -398,8 +410,13 @@ pub(crate) fn merge_generics(target: &mut T, source: &T) { } // Merge the where clause - match (generics_target.where_clause.as_mut(), generics_source.where_clause.as_ref()) { - (Some(target_where), Some(source_where)) => target_where.predicates.extend(source_where.predicates.clone()), + match ( + generics_target.where_clause.as_mut(), + generics_source.where_clause.as_ref(), + ) { + (Some(target_where), Some(source_where)) => target_where + .predicates + .extend(source_where.predicates.clone()), (None, Some(source_where)) => generics_target.where_clause = Some(source_where.clone()), _ => (), } @@ -487,8 +504,8 @@ mod tests { use super::*; mod merge_generics { - use syn::parse_quote; use crate::merge_generics; + use syn::parse_quote; macro_rules! test_merge { ([$($source:tt)+] into [$($target:tt)+] gives [$($expected:tt)+]) => { diff --git a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/common.rs b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/common.rs index 697e67f49c0..9fcd308e662 100644 --- a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/common.rs +++ b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/common.rs @@ -1,28 +1,31 @@ -use crate::{ExternSpecKind, extract_prusti_attributes, generate_spec_and_assertions, RewritableReceiver, SelfTypeRewriter}; +use crate::{ + common::{HasAttributes, HasSignature}, + extract_prusti_attributes, generate_spec_and_assertions, + span_overrider::SpanOverrider, + untyped::AnyFnItem, + ExternSpecKind, RewritableReceiver, SelfTypeRewriter, +}; use quote::{quote, ToTokens}; -use syn::{Expr, FnArg, GenericParam, GenericArgument, parse_quote_spanned, Pat, PatType, Token}; -use syn::punctuated::Punctuated; -use syn::spanned::Spanned; -use crate::common::{HasAttributes, HasSignature}; -use crate::span_overrider::SpanOverrider; -use crate::untyped::AnyFnItem; -use syn::visit::Visit; -use syn::visit_mut::VisitMut; +use syn::{ + parse_quote_spanned, punctuated::Punctuated, spanned::Spanned, visit::Visit, + visit_mut::VisitMut, Expr, FnArg, GenericArgument, GenericParam, Pat, PatType, Token, +}; /// Counts the number of elided lifetimes in receivers and types. /// For details see the function `with_explicit_lifetimes`. struct ElidedLifetimeCounter { - num_elided_lifetimes: u32 + num_elided_lifetimes: u32, } - impl ElidedLifetimeCounter { fn new() -> ElidedLifetimeCounter { - ElidedLifetimeCounter { num_elided_lifetimes: 0 } + ElidedLifetimeCounter { + num_elided_lifetimes: 0, + } } } -impl <'ast> syn::visit::Visit<'ast> for ElidedLifetimeCounter { +impl<'ast> syn::visit::Visit<'ast> for ElidedLifetimeCounter { fn visit_receiver(&mut self, receiver: &syn::Receiver) { if let Some((_, None)) = receiver.reference { self.num_elided_lifetimes += 1; @@ -36,7 +39,6 @@ impl <'ast> syn::visit::Visit<'ast> for ElidedLifetimeCounter { } } - fn has_multiple_elided_lifetimes(inputs: &Punctuated) -> bool { let mut visitor = ElidedLifetimeCounter::new(); for input in inputs { @@ -60,31 +62,34 @@ fn returns_reference_with_elided_lifetime(return_type: &syn::ReturnType) -> bool /// annotations. The explicit lifetime annotations correspond to what Rust would assign /// for the elided lifetimes in the original signature. fn with_explicit_lifetimes(sig: &syn::Signature) -> Option { - // This struct is responsible for inserting an explicit lifetime for elided // lifetimes in the receiver and output type. struct SelfLifetimeInserter {} impl syn::visit_mut::VisitMut for SelfLifetimeInserter { fn visit_type_reference_mut(&mut self, reference: &mut syn::TypeReference) { - reference.lifetime = parse_quote_spanned!{reference.span() => 'prusti_self_lifetime }; + reference.lifetime = parse_quote_spanned! {reference.span() => 'prusti_self_lifetime }; } fn visit_receiver_mut(&mut self, receiver: &mut syn::Receiver) { - receiver.reference.as_mut().unwrap().1 = parse_quote_spanned!{receiver.span() => 'prusti_self_lifetime }; + receiver.reference.as_mut().unwrap().1 = + parse_quote_spanned! {receiver.span() => 'prusti_self_lifetime }; } } - if !returns_reference_with_elided_lifetime(&sig.output) || - !has_multiple_elided_lifetimes(&sig.inputs) + if !returns_reference_with_elided_lifetime(&sig.output) + || !has_multiple_elided_lifetimes(&sig.inputs) { return None; } let mut new_sig = sig.clone(); - let mut inserter = SelfLifetimeInserter{}; + let mut inserter = SelfLifetimeInserter {}; // Insert explicit lifetime parameter to method signature - new_sig.generics.params.insert(0, parse_quote_spanned!{new_sig.generics.params.span() => 'prusti_self_lifetime }); + new_sig.generics.params.insert( + 0, + parse_quote_spanned! {new_sig.generics.params.span() => 'prusti_self_lifetime }, + ); // Assign the explicit lifetime to the reference to self if let Some(syn::FnArg::Receiver(r)) = new_sig.inputs.first_mut() { @@ -133,13 +138,13 @@ pub(crate) fn generate_extern_spec_method_stub parse_quote_spanned! {method_sig_span=> <#self_type> :: #method_ident - } + }, }; // Build the method stub let stub_method: syn::ImplItemMethod = generate_extern_spec_function_stub(method, &method_path, extern_spec_kind); - + // Eagerly extract and process specifications let mut stub_method = AnyFnItem::ImplMethod(stub_method); let prusti_attributes = extract_prusti_attributes(&mut stub_method); @@ -155,7 +160,10 @@ pub(crate) fn generate_extern_spec_method_stub( +pub(crate) fn generate_extern_spec_function_stub< + Input: HasSignature + HasAttributes + Spanned, + Output: syn::parse::Parse, +>( function: &Input, fn_path: &syn::ExprPath, extern_spec_kind: ExternSpecKind, @@ -187,7 +198,7 @@ pub(crate) fn generate_extern_spec_function_stub #[trusted] #[prusti::extern_spec = #extern_spec_kind_string] @@ -216,20 +227,17 @@ impl MethodParamsAsCallArguments for H { impl MethodParamsAsCallArguments for Punctuated { fn params_as_call_args(&self) -> Punctuated { - Punctuated::from_iter( - self.iter() - .map(|param| -> Expr { - let span = param.span(); - match param { - FnArg::Typed(PatType { pat: box Pat::Ident(ident), .. }) => - parse_quote_spanned! {span=>#ident }, - FnArg::Receiver(_) => - parse_quote_spanned! {span=>self}, - _ => - unimplemented!(), - } - }) - ) + Punctuated::from_iter(self.iter().map(|param| -> Expr { + let span = param.span(); + match param { + FnArg::Typed(PatType { + pat: box Pat::Ident(ident), + .. + }) => parse_quote_spanned! {span=>#ident }, + FnArg::Receiver(_) => parse_quote_spanned! {span=>self}, + _ => unimplemented!(), + } + })) } } @@ -246,20 +254,18 @@ impl GenericParamsAsCallArguments for H { impl GenericParamsAsCallArguments for Punctuated { fn generic_params_as_call_args(&self) -> Punctuated { use syn::*; - Punctuated::from_iter( - self.iter() - .flat_map(|param| -> Option { - let span = param.span(); - match param { - GenericParam::Type(TypeParam { ident, .. }) => - Some(parse_quote_spanned! {span=>#ident }), - GenericParam::Lifetime(_) => - None, - GenericParam::Const(ConstParam { ident, .. }) => - Some(parse_quote_spanned! {span=>#ident }), - } - }) - ) + Punctuated::from_iter(self.iter().flat_map(|param| -> Option { + let span = param.span(); + match param { + GenericParam::Type(TypeParam { ident, .. }) => { + Some(parse_quote_spanned! {span=>#ident }) + } + GenericParam::Lifetime(_) => None, + GenericParam::Const(ConstParam { ident, .. }) => { + Some(parse_quote_spanned! {span=>#ident }) + } + } + })) } } @@ -279,7 +285,10 @@ impl GenericParamsAsCallArguments for Punctuated { /// } /// ``` pub fn add_phantom_data_for_generic_params(item_struct: &mut syn::ItemStruct) { - let fields = item_struct.generics.params.iter() + let fields = item_struct + .generics + .params + .iter() .flat_map(|param| match param { syn::GenericParam::Type(tp) => { let ident = tp.ident.clone(); @@ -306,7 +315,9 @@ pub fn rewrite_generics(gens: &syn::Generics) -> syn::AngleBracketedGenericArgum .map(|gp| { let ts = match gp { syn::GenericParam::Type(syn::TypeParam { ident, .. }) - | syn::GenericParam::Const(syn::ConstParam { ident, .. }) => ident.into_token_stream(), + | syn::GenericParam::Const(syn::ConstParam { ident, .. }) => { + ident.into_token_stream() + } syn::GenericParam::Lifetime(ld) => ld.lifetime.into_token_stream(), }; syn::parse2::(ts).unwrap() diff --git a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs index 5659a7b7ed9..042e0be63fa 100644 --- a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs +++ b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs @@ -1,10 +1,10 @@ -use crate::SPECS_VERSION; -use crate::{ExternSpecKind, is_predicate_macro, specifications::common::generate_struct_name}; +use super::common::*; +use crate::{ + is_predicate_macro, specifications::common::generate_struct_name, ExternSpecKind, SPECS_VERSION, +}; use proc_macro2::TokenStream; use quote::quote_spanned; -use syn::parse_quote_spanned; -use syn::spanned::Spanned; -use super::common::*; +use syn::{parse_quote_spanned, spanned::Spanned}; pub fn rewrite_extern_spec(item_impl: &syn::ItemImpl) -> syn::Result { let rewritten = rewrite_extern_spec_internal(item_impl)?; @@ -33,7 +33,7 @@ fn rewrite_extern_spec_internal(item_impl: &syn::ItemImpl) -> syn::Result) -> "Unexpected method body. (Extern specs only define specifications.)", )); } - + let (rewritten_method, spec_items) = generate_extern_spec_method_stub( method, item_ty, @@ -108,11 +108,11 @@ fn rewrite_plain_impl(impl_item: &mut syn::ItemImpl, new_ty: Box) -> rewritten_items.extend(spec_items.into_iter().map(syn::ImplItem::Method)); rewritten_items.push(syn::ImplItem::Method(rewritten_method)); - }, + } syn::ImplItem::Macro(makro) if is_predicate_macro(makro) => { return Err(syn::Error::new( makro.span(), - "Can not declare abstract predicate in external spec" + "Can not declare abstract predicate in external spec", )); } _ => { @@ -132,11 +132,13 @@ fn rewrite_plain_impl(impl_item: &mut syn::ItemImpl, new_ty: Box) -> } /// Recognizes method stubs, e.g. `fn foo();`. -/// +/// /// The absence of a body is represented in a roundabout way: /// They have a body comprising a single verbatim item containing a single semicolon token. fn is_stub(block: &syn::Block) -> bool { - if block.stmts.len() != 1 { return false; } + if block.stmts.len() != 1 { + return false; + } if let syn::Stmt::Item(syn::Item::Verbatim(tokens)) = &block.stmts[0] { return tokens.to_string() == ";"; } else { @@ -157,7 +159,8 @@ fn rewrite_trait_impl( new_impl.items.clear(); let item_trait_path = impl_item.trait_.as_ref().unwrap().1.clone(); - let item_trait_typath: syn::TypePath = parse_quote_spanned! {item_trait_path.span()=> #item_trait_path }; + let item_trait_typath: syn::TypePath = + parse_quote_spanned! {item_trait_path.span()=> #item_trait_path }; // TODO: reduce duplication with rewrite_plain_impl for item in impl_item.items.into_iter() { @@ -176,7 +179,9 @@ fn rewrite_trait_impl( ExternSpecKind::TraitImpl, )?; - new_impl.items.extend(spec_items.into_iter().map(syn::ImplItem::Method)); + new_impl + .items + .extend(spec_items.into_iter().map(syn::ImplItem::Method)); new_impl.items.push(syn::ImplItem::Method(rewritten_method)); } _ => { diff --git a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs index 15dc31c6b3f..820345f0509 100644 --- a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs +++ b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs @@ -1,11 +1,12 @@ //! Encoding of external specs for traits -use crate::{ExternSpecKind, is_predicate_macro, parse_quote_spanned}; -use crate::specifications::common::generate_struct_name_for_trait; +use super::common::*; +use crate::{ + is_predicate_macro, parse_quote_spanned, + specifications::common::generate_struct_name_for_trait, ExternSpecKind, +}; use proc_macro2::TokenStream; use quote::{quote_spanned, ToTokens}; -use syn::parse_quote; -use syn::spanned::Spanned; -use super::common::*; +use syn::{parse_quote, spanned::Spanned}; /// Generates a struct for a `syn::ItemTrait` which is used for checking /// compilation of external specs on traits. @@ -49,15 +50,19 @@ fn generate_new_struct(item_trait: &syn::ItemTrait) -> syn::Result syn::Result GeneratedStruct<'a> { let (method, spec_fns) = self.generate_method_stub(trait_method)?; struct_impl.items.push(syn::ImplItem::Method(method)); - struct_impl.items.extend(spec_fns.into_iter().map(syn::ImplItem::Method)); - }, + struct_impl + .items + .extend(spec_fns.into_iter().map(syn::ImplItem::Method)); + } syn::TraitItem::Macro(makro) if is_predicate_macro(makro) => { return Err(syn::Error::new( makro.span(), - "Can not declare abstract predicate in external spec" + "Can not declare abstract predicate in external spec", )); } _ => unimplemented!("Unimplemented trait item for extern spec"), @@ -163,14 +173,22 @@ impl<'a> GeneratedStruct<'a> { Ok(struct_impl) } - fn generate_method_stub(&self, trait_method: &syn::TraitItemMethod) -> syn::Result<(syn::ImplItemMethod, Vec)> { + fn generate_method_stub( + &self, + trait_method: &syn::TraitItemMethod, + ) -> syn::Result<(syn::ImplItemMethod, Vec)> { let self_type_ident = &self.self_type_ident; let self_type_path: syn::TypePath = parse_quote_spanned! {self_type_ident.span()=> #self_type_ident }; let self_type = syn::Type::Path(self_type_path); - generate_extern_spec_method_stub(trait_method, &self_type, Some(&self.self_type_trait), ExternSpecKind::Trait) + generate_extern_spec_method_stub( + trait_method, + &self_type, + Some(&self.self_type_trait), + ExternSpecKind::Trait, + ) } } @@ -203,7 +221,7 @@ impl ProvidedTypeParam { match path.segments[0].ident.to_string().as_str() { "generic" => Some(ProvidedTypeParam::GenericType(clone_without_attrs())), "concrete" => Some(ProvidedTypeParam::ConcreteType(clone_without_attrs())), - _ => None + _ => None, } } } @@ -211,7 +229,8 @@ impl ProvidedTypeParam { impl ToTokens for ProvidedTypeParam { fn to_tokens(&self, tokens: &mut TokenStream) { match &self { - ProvidedTypeParam::ConcreteType(ty_param) | ProvidedTypeParam::GenericType(ty_param) => ty_param.to_tokens(tokens), + ProvidedTypeParam::ConcreteType(ty_param) + | ProvidedTypeParam::GenericType(ty_param) => ty_param.to_tokens(tokens), } } } diff --git a/prusti-contracts/prusti-specs/src/ghost_constraints/mod.rs b/prusti-contracts/prusti-specs/src/ghost_constraints/mod.rs index 7e18cbd40b7..7ee32d47693 100644 --- a/prusti-contracts/prusti-specs/src/ghost_constraints/mod.rs +++ b/prusti-contracts/prusti-specs/src/ghost_constraints/mod.rs @@ -1,6 +1,6 @@ use crate::{ - generate_for_ensures, generate_for_requires, generate_for_pure_ghost_constraint, parse_ghost_constraint, untyped, GeneratedResult, - NestedSpec, + generate_for_ensures, generate_for_pure_ghost_constraint, generate_for_requires, + parse_ghost_constraint, untyped, GeneratedResult, NestedSpec, }; use proc_macro2::TokenStream; use syn::{parse_quote_spanned, spanned::Spanned}; @@ -50,12 +50,16 @@ fn generate_where_clause_for_spec( trait_bounds: &Vec, existing_where_clause: Option<&syn::WhereClause>, ) -> syn::WhereClause { - let mut where_clause = existing_where_clause.cloned().unwrap_or_else(|| syn::parse_quote!(where)); - where_clause.predicates.extend(trait_bounds.iter().map(|bound| -> syn::WherePredicate { - let span = bound.span(); - parse_quote_spanned! {span=> - #bound - } - })); + let mut where_clause = existing_where_clause + .cloned() + .unwrap_or_else(|| syn::parse_quote!(where)); + where_clause + .predicates + .extend(trait_bounds.iter().map(|bound| -> syn::WherePredicate { + let span = bound.span(); + parse_quote_spanned! {span=> + #bound + } + })); where_clause } diff --git a/prusti-contracts/prusti-specs/src/lib.rs b/prusti-contracts/prusti-specs/src/lib.rs index 18daa3f81b0..9119876ee1f 100644 --- a/prusti-contracts/prusti-specs/src/lib.rs +++ b/prusti-contracts/prusti-specs/src/lib.rs @@ -23,7 +23,6 @@ mod type_model; mod user_provided_type_params; mod print_counterexample; - use proc_macro2::{Span, TokenStream, TokenTree}; use quote::{quote, quote_spanned, ToTokens}; use rewriter::AstRewriter; @@ -57,8 +56,10 @@ fn extract_prusti_attributes( let mut prusti_attributes = Vec::new(); let mut regular_attributes = Vec::new(); for attr in item.attrs_mut().drain(0..) { - if attr.path.segments.len() == 1 || (attr.path.segments.len() == 2 && attr.path.segments[0].ident == "prusti_contracts") { - let idx = attr.path.segments.len()-1; + if attr.path.segments.len() == 1 + || (attr.path.segments.len() == 2 && attr.path.segments[0].ident == "prusti_contracts") + { + let idx = attr.path.segments.len() - 1; if let Ok(attr_kind) = attr.path.segments[idx].ident.to_string().try_into() { let tokens = match attr_kind { SpecAttributeKind::Requires @@ -84,7 +85,9 @@ fn extract_prusti_attributes( } SpecAttributeKind::Invariant => unreachable!("type invariant on function"), SpecAttributeKind::Model => unreachable!("model on function"), - SpecAttributeKind::PrintCounterexample => unreachable!("print_counterexample on function"), + SpecAttributeKind::PrintCounterexample => { + unreachable!("print_counterexample on function") + } }; prusti_attributes.push((attr_kind, tokens)); } else { @@ -291,7 +294,7 @@ fn generate_for_pure_ghost_constraint(item: &untyped::AnyFnItem) -> GeneratedRes let spec_id = rewriter.generate_spec_id(); let spec_id_str = spec_id.to_string(); let spec_item = rewriter.process_pure_ghost_constraint(spec_id, item)?; - + Ok(( vec![spec_item], vec![parse_quote_spanned! {item.span()=> @@ -350,41 +353,29 @@ fn generate_for_trusted_for_types(attr: TokenStream, item: &syn::DeriveInput) -> .params .iter() .map(|generic_param| match generic_param { - syn::GenericParam::Type(param) => { - syn::GenericParam::Type( - syn::TypeParam { - attrs: Vec::new(), - bounds: syn::punctuated::Punctuated::new(), - colon_token: None, - default: None, - eq_token: None, - ident: param.ident.clone(), - } - ) - }, - syn::GenericParam::Lifetime(param) => { - syn::GenericParam::Lifetime( - syn::LifetimeDef { - attrs: Vec::new(), - bounds: syn::punctuated::Punctuated::new(), - colon_token: None, - lifetime: param.lifetime.clone(), - } - ) - }, - syn::GenericParam::Const(param) => { - syn::GenericParam::Const( - syn::ConstParam { - attrs: Vec::new(), - colon_token: param.colon_token, - const_token: param.const_token, - default: None, - eq_token: None, - ident: param.ident.clone(), - ty: param.ty.clone(), - } - ) - } + syn::GenericParam::Type(param) => syn::GenericParam::Type(syn::TypeParam { + attrs: Vec::new(), + bounds: syn::punctuated::Punctuated::new(), + colon_token: None, + default: None, + eq_token: None, + ident: param.ident.clone(), + }), + syn::GenericParam::Lifetime(param) => syn::GenericParam::Lifetime(syn::LifetimeDef { + attrs: Vec::new(), + bounds: syn::punctuated::Punctuated::new(), + colon_token: None, + lifetime: param.lifetime.clone(), + }), + syn::GenericParam::Const(param) => syn::GenericParam::Const(syn::ConstParam { + attrs: Vec::new(), + colon_token: param.colon_token, + const_token: param.const_token, + default: None, + eq_token: None, + ident: param.ident.clone(), + ty: param.ty.clone(), + }), }) .collect::>(); // TODO: similarly to extern_specs, don't generate an actual impl @@ -394,10 +385,7 @@ fn generate_for_trusted_for_types(attr: TokenStream, item: &syn::DeriveInput) -> } }; - Ok(( - vec![syn::Item::Impl(item_impl)], - vec![], - )) + Ok((vec![syn::Item::Impl(item_impl)], vec![])) } pub fn body_variant(tokens: TokenStream) -> TokenStream { @@ -645,41 +633,31 @@ pub fn trusted(attr: TokenStream, tokens: TokenStream) -> TokenStream { .params .iter() .map(|generic_param| match generic_param { - syn::GenericParam::Type(param) => { - syn::GenericParam::Type( - syn::TypeParam { - attrs: Vec::new(), - bounds: syn::punctuated::Punctuated::new(), - colon_token: None, - default: None, - eq_token: None, - ident: param.ident.clone(), - } - ) - }, + syn::GenericParam::Type(param) => syn::GenericParam::Type(syn::TypeParam { + attrs: Vec::new(), + bounds: syn::punctuated::Punctuated::new(), + colon_token: None, + default: None, + eq_token: None, + ident: param.ident.clone(), + }), syn::GenericParam::Lifetime(param) => { - syn::GenericParam::Lifetime( - syn::LifetimeDef { - attrs: Vec::new(), - bounds: syn::punctuated::Punctuated::new(), - colon_token: None, - lifetime: param.lifetime.clone(), - } - ) - }, - syn::GenericParam::Const(param) => { - syn::GenericParam::Const( - syn::ConstParam { - attrs: Vec::new(), - colon_token: param.colon_token, - const_token: param.const_token, - default: None, - eq_token: None, - ident: param.ident.clone(), - ty: param.ty.clone(), - } - ) + syn::GenericParam::Lifetime(syn::LifetimeDef { + attrs: Vec::new(), + bounds: syn::punctuated::Punctuated::new(), + colon_token: None, + lifetime: param.lifetime.clone(), + }) } + syn::GenericParam::Const(param) => syn::GenericParam::Const(syn::ConstParam { + attrs: Vec::new(), + colon_token: param.colon_token, + const_token: param.const_token, + default: None, + eq_token: None, + ident: param.ident.clone(), + ty: param.ty.clone(), + }), }) .collect::>(); // TODO: similarly to extern_specs, don't generate an actual impl @@ -786,9 +764,10 @@ pub fn rewrite_prusti_attributes_for_types( // Collect the remaining Prusti attributes, removing them from `item`. prusti_attributes.extend(extract_prusti_attributes_for_types(&mut item)); - if prusti_attributes.len() > 1 && prusti_attributes - .iter() - .any(|(ak, _)| ak == &SpecAttributeKind::Trusted) + if prusti_attributes.len() > 1 + && prusti_attributes + .iter() + .any(|(ak, _)| ak == &SpecAttributeKind::Trusted) { return syn::Error::new( item.span(), @@ -800,8 +779,9 @@ pub fn rewrite_prusti_attributes_for_types( // we order the attributes to ensure a model attribute is processed first prusti_attributes.sort_by(|(ak1, _), (ak2, _)| ak1.cmp(ak2)); - let (generated_spec_items, generated_attributes) = - handle_result!(generate_spec_and_assertions_for_types(prusti_attributes, &mut item)); + let (generated_spec_items, generated_attributes) = handle_result!( + generate_spec_and_assertions_for_types(prusti_attributes, &mut item) + ); quote_spanned! {item.span()=> #(#generated_attributes)* @@ -810,7 +790,6 @@ pub fn rewrite_prusti_attributes_for_types( } } - fn extract_prusti_attributes_for_types( item: &mut syn::DeriveInput, ) -> Vec<(SpecAttributeKind, TokenStream)> { @@ -829,8 +808,7 @@ fn extract_prusti_attributes_for_types( SpecAttributeKind::Invariant => unreachable!("invariant on type"), SpecAttributeKind::Predicate => unreachable!("predicate on type"), SpecAttributeKind::Terminates => unreachable!("terminates on type"), - SpecAttributeKind::Trusted | - SpecAttributeKind::Model => { + SpecAttributeKind::Trusted | SpecAttributeKind::Model => { assert!(attr.tokens.is_empty(), "Unexpected shape of an attribute."); attr.tokens } @@ -876,7 +854,9 @@ fn generate_spec_and_assertions_for_types( SpecAttributeKind::Terminates => unreachable!(), SpecAttributeKind::Trusted => generate_for_trusted_for_types(attr_tokens, item), SpecAttributeKind::Model => generate_for_model(attr_tokens, item), - SpecAttributeKind::PrintCounterexample => generate_for_print_counterexample(attr_tokens, item), + SpecAttributeKind::PrintCounterexample => { + generate_for_print_counterexample(attr_tokens, item) + } }; let (new_items, new_attributes) = rewriting_result?; generated_items.extend(new_items); @@ -890,7 +870,7 @@ fn generate_spec_and_assertions_for_types( fn generate_for_model(attr: TokenStream, item: &mut syn::DeriveInput) -> GeneratedResult { match syn::Item::from(item.clone()) { syn::Item::Struct(item_struct) => { - match type_model::rewrite(item_struct){ + match type_model::rewrite(item_struct) { Ok(result) => { match result.first() { Some(syn::Item::Struct(new_item)) => { @@ -899,7 +879,7 @@ fn generate_for_model(attr: TokenStream, item: &mut syn::DeriveInput) -> Generat } _ => unreachable!(), } - }, + } Err(err) => Err(err), } } @@ -910,30 +890,31 @@ fn generate_for_model(attr: TokenStream, item: &mut syn::DeriveInput) -> Generat } } - /// Generate spec items and attributes to typecheck and later retrieve "print_counterexample" annotations. -fn generate_for_print_counterexample(attr: TokenStream, item: &mut syn::DeriveInput) -> GeneratedResult { +fn generate_for_print_counterexample( + attr: TokenStream, + item: &mut syn::DeriveInput, +) -> GeneratedResult { match syn::Item::from(item.clone()) { syn::Item::Struct(item_struct) => { - match print_counterexample::rewrite_struct(attr, item_struct){ + match print_counterexample::rewrite_struct(attr, item_struct) { Ok(result) => Ok((result, vec![])), Err(err) => Err(err), } } syn::Item::Enum(item_enum) => { - match print_counterexample::rewrite_enum(attr, item_enum){ + match print_counterexample::rewrite_enum(attr, item_enum) { Ok(result) => { match result.first() { Some(syn::Item::Enum(new_item)) => { *item = syn::DeriveInput::from(new_item.clone()); //print_counterexample removes all attributes inside the enum Ok((vec![result[1].clone()], vec![])) - }, + } _ => unreachable!(), } - }, + } Err(err) => Err(err), } - } _ => Err(syn::Error::new( attr.span(), diff --git a/prusti-contracts/prusti-specs/src/parse_closure_macro.rs b/prusti-contracts/prusti-specs/src/parse_closure_macro.rs index 365a4fdfdcc..34d0a12d1b0 100644 --- a/prusti-contracts/prusti-specs/src/parse_closure_macro.rs +++ b/prusti-contracts/prusti-specs/src/parse_closure_macro.rs @@ -3,7 +3,7 @@ use syn::parse::{Parse, ParseStream}; pub(crate) struct ClosureWithSpec { pub pres: Vec, pub posts: Vec, - pub cl: syn::ExprClosure + pub cl: syn::ExprClosure, } impl Parse for ClosureWithSpec { @@ -21,7 +21,7 @@ impl Parse for ClosureWithSpec { match id.to_string().as_ref() { "requires" => pres.push(syn::parse2(attr.tokens.clone())), "ensures" => posts.push(syn::parse2(attr.tokens.clone())), - _ => return false + _ => return false, } true } else { diff --git a/prusti-contracts/prusti-specs/src/predicate.rs b/prusti-contracts/prusti-specs/src/predicate.rs index 3fe390e2d5a..8b2f152b05c 100644 --- a/prusti-contracts/prusti-specs/src/predicate.rs +++ b/prusti-contracts/prusti-specs/src/predicate.rs @@ -1,10 +1,12 @@ //! Predicate parsing -use crate::{rewriter, SpecificationId, SPECS_VERSION}; +use crate::{ + common::{HasMacro, HasSignature}, + rewriter, SpecificationId, SPECS_VERSION, +}; use proc_macro2::{Span, TokenStream}; use quote::ToTokens; use syn::{parse::Parse, parse_quote_spanned, spanned::Spanned}; -use crate::common::{HasMacro, HasSignature}; #[derive(Debug)] pub struct PredicateWithBody { diff --git a/prusti-contracts/prusti-specs/src/rewriter.rs b/prusti-contracts/prusti-specs/src/rewriter.rs index 2153ebfb8c4..483717ea223 100644 --- a/prusti-contracts/prusti-specs/src/rewriter.rs +++ b/prusti-contracts/prusti-specs/src/rewriter.rs @@ -113,9 +113,15 @@ impl AstRewriter { // terminator in MIR has a span set to the one character just after // the identifier let (return_type, return_modifier) = if spec_type == SpecItemType::Termination { - (quote_spanned! {item_span => Int}, quote_spanned! {item_span => Int::new(0) + }) + ( + quote_spanned! {item_span => Int}, + quote_spanned! {item_span => Int::new(0) + }, + ) } else { - (quote_spanned! {item_span => bool}, quote_spanned! {item_span => !!}) + ( + quote_spanned! {item_span => bool}, + quote_spanned! {item_span => !!}, + ) }; let mut spec_item: syn::ItemFn = parse_quote_spanned! {item_span=> #[allow(unused_must_use, unused_parens, unused_variables, dead_code)] @@ -174,13 +180,13 @@ impl AstRewriter { &format!("prusti_pure_ghost_item_{}", item.sig().ident), item_span, ); - + let spec_id_str = spec_id.to_string(); let mut spec_item: syn::ItemFn = parse_quote_spanned! {item_span=> #[allow(unused_must_use, unused_parens, unused_variables, dead_code)] #[prusti::spec_only] #[prusti::spec_id = #spec_id_str] - fn #item_name() {} // we only care about this for evaluating + fn #item_name() {} // we only care about this for evaluating }; spec_item.sig.generics = item.sig().generics.clone(); diff --git a/prusti-contracts/prusti-specs/src/span_overrider.rs b/prusti-contracts/prusti-specs/src/span_overrider.rs index a517a64ad45..12039ca523d 100644 --- a/prusti-contracts/prusti-specs/src/span_overrider.rs +++ b/prusti-contracts/prusti-specs/src/span_overrider.rs @@ -2,18 +2,16 @@ use proc_macro2::Span; /// Override all span information pub struct SpanOverrider { - span: Span + span: Span, } impl SpanOverrider { pub fn new(span: Span) -> Self { - SpanOverrider { - span - } + SpanOverrider { span } } } -impl syn::visit_mut::VisitMut for SpanOverrider { +impl syn::visit_mut::VisitMut for SpanOverrider { fn visit_span_mut(&mut self, span: &mut Span) { *span = self.span; } diff --git a/prusti-contracts/prusti-specs/src/spec_attribute_kind.rs b/prusti-contracts/prusti-specs/src/spec_attribute_kind.rs index c77bb53ee42..67c7c3d8012 100644 --- a/prusti-contracts/prusti-specs/src/spec_attribute_kind.rs +++ b/prusti-contracts/prusti-specs/src/spec_attribute_kind.rs @@ -3,8 +3,8 @@ use std::convert::TryFrom; /// This type identifies one of the procedural macro attributes of Prusti #[derive(PartialEq, Eq, Copy, Clone, Debug, PartialOrd, Ord)] pub enum SpecAttributeKind { - /// All type specifications that alter its type must be processed before - /// PrintCounterexample. Currently this only applies to Model. + /// All type specifications that alter its type must be processed before + /// PrintCounterexample. Currently this only applies to Model. Model = 0, Requires = 1, Ensures = 2, diff --git a/prusti-contracts/prusti-specs/src/specifications/common.rs b/prusti-contracts/prusti-specs/src/specifications/common.rs index 096b439e2a8..7e10a4161c7 100644 --- a/prusti-contracts/prusti-specs/src/specifications/common.rs +++ b/prusti-contracts/prusti-specs/src/specifications/common.rs @@ -3,8 +3,10 @@ //! Please see the `parser.rs` file for more information about //! specifications. -use std::convert::TryFrom; -use std::fmt::{Display, Debug}; +use std::{ + convert::TryFrom, + fmt::{Debug, Display}, +}; use uuid::Uuid; #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -45,7 +47,17 @@ impl<'a> TryFrom<&'a str> for SpecType { } #[derive( - Debug, Default, PartialEq, Eq, Hash, Clone, Copy, serde::Serialize, serde::Deserialize, PartialOrd, Ord, + Debug, + Default, + PartialEq, + Eq, + Hash, + Clone, + Copy, + serde::Serialize, + serde::Deserialize, + PartialOrd, + Ord, )] /// A unique ID of the specification element such as entire precondition /// or postcondition. @@ -117,16 +129,17 @@ pub(crate) fn generate_mod_name(ident: &syn::Ident) -> String { fn generate_name_for_type(ty: &syn::Type) -> Option { match ty { - syn::Type::Path(ty_path) => { - Some(String::from_iter(ty_path.path.segments.iter() - .map(|seg| seg.ident.to_string()))) - }, + syn::Type::Path(ty_path) => Some(String::from_iter( + ty_path + .path + .segments + .iter() + .map(|seg| seg.ident.to_string()), + )), syn::Type::Slice(ty_slice) => { let ty = &*ty_slice.elem; Some(format!("Slice{}", generate_name_for_type(ty)?.as_str())) - }, - _ => { - None } + _ => None, } } diff --git a/prusti-contracts/prusti-specs/src/specifications/mod.rs b/prusti-contracts/prusti-specs/src/specifications/mod.rs index a669cb22200..07e766175bd 100644 --- a/prusti-contracts/prusti-specs/src/specifications/mod.rs +++ b/prusti-contracts/prusti-specs/src/specifications/mod.rs @@ -2,7 +2,7 @@ /// assertion ::= prusti_expr ; /// pledge ::= pledge_lhs, ",", prusti_expr ; /// pledge_lhs ::= [ ? actual rust expression ?, "=>" ], prusti_expr ; -/// +/// /// prusti_expr ::= conjunction, [ "==>", prusti_expr ] ; /// conjunction ::= entailment, { "&&", entailment } ; /// entailment ::= primary | ? actual rust expression ?, [ "|=", [ "|", ? args as parsed by syn2 ?, "|" ], "[", [ ( requires | ensures ), { ",", ( requires | ensures ) } ], "]" ] ; @@ -11,7 +11,7 @@ /// ; /// requires ::= "requires", "(", prusti_expr, ")" ; /// ensures ::= "ensures", "(", prusti_expr, ")" ; -/// +/// /// This grammar doesn't yet handle the unintuitive precedence difference between `&&` and `||` operators. pub mod common; diff --git a/prusti-contracts/prusti-specs/src/specifications/preparser.rs b/prusti-contracts/prusti-specs/src/specifications/preparser.rs index 56fb5ac1744..b39a0fc0ad6 100644 --- a/prusti-contracts/prusti-specs/src/specifications/preparser.rs +++ b/prusti-contracts/prusti-specs/src/specifications/preparser.rs @@ -1,17 +1,18 @@ /// The preparser processes Prusti syntax into Rust syntax. - -use proc_macro2::{Span, TokenStream, TokenTree, Delimiter}; +use proc_macro2::{Delimiter, Span, TokenStream, TokenTree}; +use proc_macro2::{Punct, Spacing::*}; +use quote::{quote, quote_spanned, ToTokens}; use std::collections::VecDeque; -use quote::{ToTokens, quote, quote_spanned}; -use proc_macro2::Punct; -use proc_macro2::Spacing::*; -use syn::{parse::{Parse, ParseStream}, spanned::Spanned}; +use syn::{ + parse::{Parse, ParseStream}, + spanned::Spanned, +}; /// The representation of an argument to a quantifier (for example `a: i32`) #[derive(Debug, Clone)] pub struct Arg { pub name: syn::Ident, - pub typ: syn::Type + pub typ: syn::Type, } pub fn parse_prusti(tokens: TokenStream) -> syn::Result { @@ -28,7 +29,10 @@ pub fn parse_prusti_pledge(tokens: TokenStream) -> syn::Result { let (reference, rhs) = PrustiTokenStream::new(tokens).parse_pledge()?; if let Some(reference) = reference { if reference.to_string() != "result" { - return err(reference.span(), "reference of after_expiry must be \"result\""); + return err( + reference.span(), + "reference of after_expiry must be \"result\"", + ); } } syn::parse2::(rhs.clone())?; @@ -42,7 +46,10 @@ pub fn parse_prusti_assert_pledge(tokens: TokenStream) -> syn::Result<(TokenStre let (reference, lhs, rhs) = PrustiTokenStream::new(tokens).parse_assert_pledge()?; if let Some(reference) = reference { if reference.to_string() != "result" { - return err(reference.span(), "reference of assert_on_expiry must be \"result\""); + return err( + reference.span(), + "reference of assert_on_expiry must be \"result\"", + ); } } syn::parse2::(lhs.clone())?; @@ -159,7 +166,10 @@ impl PrustiTokenStream { (token, _, _) => PrustiToken::Token(token.clone()), }); } - Self { tokens, source_span } + Self { + tokens, + source_span, + } } fn is_empty(&self) -> bool { @@ -189,24 +199,23 @@ impl PrustiTokenStream { /// Processes a Prusti token stream back into Rust syntax. /// Prusti-specific syntax is not allowed and will raise an error. fn parse_rust_only(self) -> syn::Result { - Ok(TokenStream::from_iter(self.tokens - .into_iter() - .map(|token| match token { - PrustiToken::Group(_, _, box stream) => stream.parse_rust_only(), - PrustiToken::Token(tree) => Ok(tree.to_token_stream()), - PrustiToken::BinOp(span, PrustiBinaryOp::Rust(op)) => Ok(op.to_tokens(span)), - _ => err(token.span(), "unexpected Prusti syntax"), - }) - .collect::, _>>()? - .into_iter())) + Ok(TokenStream::from_iter( + self.tokens + .into_iter() + .map(|token| match token { + PrustiToken::Group(_, _, box stream) => stream.parse_rust_only(), + PrustiToken::Token(tree) => Ok(tree.to_token_stream()), + PrustiToken::BinOp(span, PrustiBinaryOp::Rust(op)) => Ok(op.to_tokens(span)), + _ => err(token.span(), "unexpected Prusti syntax"), + }) + .collect::, _>>()? + .into_iter(), + )) } /// Processes a Prusti token stream for a pledge, in the form `a => b` or /// just `b`. - fn parse_pledge(self) -> syn::Result<( - Option, - TokenStream - )> { + fn parse_pledge(self) -> syn::Result<(Option, TokenStream)> { let mut pledge_ops = self.split(PrustiBinaryOp::Rust(RustOp::Arrow), false); if pledge_ops.len() == 1 { Ok((None, pledge_ops[0].expr_bp(0)?)) @@ -219,11 +228,7 @@ impl PrustiTokenStream { /// Processes a Prusti token stream for an assert pledge, in the form `a => /// b, c` or `b, c`. - fn parse_assert_pledge(self) -> syn::Result<( - Option, - TokenStream, - TokenStream - )> { + fn parse_assert_pledge(self) -> syn::Result<(Option, TokenStream, TokenStream)> { let mut pledge_ops = self.split(PrustiBinaryOp::Rust(RustOp::Arrow), false); let (reference, body) = match (pledge_ops.pop(), pledge_ops.pop(), pledge_ops.pop()) { (Some(body), None, _) => (None, body), @@ -232,7 +237,11 @@ impl PrustiTokenStream { }; let mut body_parts = body.split(PrustiBinaryOp::Rust(RustOp::Comma), false); if body_parts.len() == 2 { - Ok((reference, body_parts[0].expr_bp(0)?, body_parts[1].expr_bp(0)?)) + Ok(( + reference, + body_parts[0].expr_bp(0)?, + body_parts[1].expr_bp(0)?, + )) } else { err(Span::call_site(), "missing assertion") } @@ -245,22 +254,22 @@ impl PrustiTokenStream { fn expr_bp(&mut self, min_bp: u8) -> syn::Result { let mut lhs = match self.tokens.pop_front() { Some(PrustiToken::Group(span, delimiter, box stream)) => { - let mut group = proc_macro2::Group::new( - delimiter, - stream.parse()?, - ); + let mut group = proc_macro2::Group::new(delimiter, stream.parse()?); group.set_span(span); TokenTree::Group(group).to_token_stream() } Some(PrustiToken::Outer(span)) => { - let _stream = self.pop_group(Delimiter::Parenthesis) + let _stream = self + .pop_group(Delimiter::Parenthesis) .ok_or_else(|| error(span, "expected parenthesized expression after outer"))?; todo!() } Some(PrustiToken::Quantifier(span, kind)) => { - let mut stream = self.pop_group(Delimiter::Parenthesis) - .ok_or_else(|| error(span, "expected parenthesized expression after quantifier"))?; - let args = stream.pop_closure_args() + let mut stream = self.pop_group(Delimiter::Parenthesis).ok_or_else(|| { + error(span, "expected parenthesized expression after quantifier") + })?; + let args = stream + .pop_closure_args() .ok_or_else(|| error(span, "expected quantifier body"))?; { @@ -273,7 +282,12 @@ impl PrustiTokenStream { for pat in parsed_cl.inputs { match pat { syn::Pat::Type(_) => {} - _ => return err(pat.span(), "quantifier arguments must have explicit types"), + _ => { + return err( + pat.span(), + "quantifier arguments must have explicit types", + ) + } } } }; @@ -287,16 +301,14 @@ impl PrustiTokenStream { kind.translate(span, triggers, args, body) } - Some(PrustiToken::SpecEnt(span, _)) - | Some(PrustiToken::CallDesc(span, _)) => - return err(span, "unexpected operator"), + Some(PrustiToken::SpecEnt(span, _)) | Some(PrustiToken::CallDesc(span, _)) => { + return err(span, "unexpected operator") + } // some Rust binary operators can appear on their own, e.g. `(..)` - Some(PrustiToken::BinOp(span, PrustiBinaryOp::Rust(op))) => - op.to_tokens(span), + Some(PrustiToken::BinOp(span, PrustiBinaryOp::Rust(op))) => op.to_tokens(span), - Some(PrustiToken::BinOp(span, _)) => - return err(span, "unexpected binary operator"), + Some(PrustiToken::BinOp(span, _)) => return err(span, "unexpected binary operator"), Some(PrustiToken::Token(token)) => token.to_token_stream(), None => return Ok(TokenStream::new()), }; @@ -307,10 +319,7 @@ impl PrustiTokenStream { // precedence operators (e.g. plus) are connected into atoms // as far as our parser is concerned. Some(PrustiToken::Group(span, delimiter, box stream)) => { - let mut group = proc_macro2::Group::new( - *delimiter, - stream.clone().parse()?, - ); + let mut group = proc_macro2::Group::new(*delimiter, stream.clone().parse()?); group.set_span(*span); lhs.extend(TokenTree::Group(group).to_token_stream()); self.tokens.pop_front(); @@ -326,15 +335,15 @@ impl PrustiTokenStream { let span = *span; let once = *once; self.tokens.pop_front(); - let args = self.pop_closure_args() + let args = self + .pop_closure_args() .ok_or_else(|| error(span, "expected closure arguments"))?; let nested_closure_specs = self.pop_group_of_nested_specs(span)?; lhs = translate_spec_ent( span, once, lhs, - args - .split(PrustiBinaryOp::Rust(RustOp::Comma), true) + args.split(PrustiBinaryOp::Rust(RustOp::Comma), true) .into_iter() .map(|stream| stream.parse()) .collect::, _>>()?, @@ -346,10 +355,10 @@ impl PrustiTokenStream { Some(PrustiToken::CallDesc(..)) => todo!("call desc"), Some(PrustiToken::BinOp(span, op)) => (*span, *op), - Some(PrustiToken::Outer(span)) => - return err(*span, "unexpected outer"), - Some(PrustiToken::Quantifier(span, _)) => - return err(*span, "unexpected quantifier"), + Some(PrustiToken::Outer(span)) => return err(*span, "unexpected outer"), + Some(PrustiToken::Quantifier(span, _)) => { + return err(*span, "unexpected quantifier") + } None => break, }; @@ -370,8 +379,7 @@ impl PrustiTokenStream { fn pop_group(&mut self, delimiter: Delimiter) -> Option { match self.tokens.pop_front() { - Some(PrustiToken::Group(_, del, box stream)) if del == delimiter - => Some(stream), + Some(PrustiToken::Group(_, del, box stream)) if del == delimiter => Some(stream), _ => None, } } @@ -380,8 +388,14 @@ impl PrustiTokenStream { let mut tokens = VecDeque::new(); // special case: empty closure might be parsed as a logical or - if matches!(self.tokens.front(), Some(PrustiToken::BinOp(_, PrustiBinaryOp::Or))) { - return Some(Self { tokens, source_span: self.source_span }); + if matches!( + self.tokens.front(), + Some(PrustiToken::BinOp(_, PrustiBinaryOp::Or)) + ) { + return Some(Self { + tokens, + source_span: self.source_span, + }); } if !self.tokens.pop_front()?.is_closure_brace() { @@ -395,9 +409,12 @@ impl PrustiTokenStream { tokens.push_back(token); } - Some(Self { tokens, source_span: self.source_span }) + Some(Self { + tokens, + source_span: self.source_span, + }) } - + fn pop_parenthesized_group(&mut self) -> syn::Result { match self.tokens.pop_front() { Some(PrustiToken::Group(_span, Delimiter::Parenthesis, box group)) => { @@ -406,25 +423,33 @@ impl PrustiTokenStream { _ => Err(error(self.source_span, "expected parenthesized group")), } } - + fn pop_single_nested_spec(&mut self) -> syn::Result> { - let first = self.tokens.pop_front().ok_or_else(|| { - error(self.source_span, "expected nested spec") - })?; + let first = self + .tokens + .pop_front() + .ok_or_else(|| error(self.source_span, "expected nested spec"))?; if let PrustiToken::Token(TokenTree::Ident(spec_type)) = first { match spec_type.to_string().as_ref() { "requires" => Ok(NestedSpec::Requires(self.pop_parenthesized_group()?)), "ensures" => Ok(NestedSpec::Ensures(self.pop_parenthesized_group()?)), "pure" => Ok(NestedSpec::Pure), - other => err(self.source_span, format!("unexpected nested spec type: {}", other).as_ref()), + other => err( + self.source_span, + format!("unexpected nested spec type: {}", other).as_ref(), + ), } } else { err(self.source_span, "expected identifier") } } - fn pop_group_of_nested_specs(&mut self, span: Span) -> syn::Result>> { - let group_of_specs = self.pop_group(Delimiter::Bracket) + fn pop_group_of_nested_specs( + &mut self, + span: Span, + ) -> syn::Result>> { + let group_of_specs = self + .pop_group(Delimiter::Bracket) .ok_or_else(|| error(span, "expected nested specification in brackets"))?; let parsed = group_of_specs .split(PrustiBinaryOp::Rust(RustOp::Comma), true) @@ -435,19 +460,19 @@ impl PrustiTokenStream { Ok(parsed) } - fn split( - self, - split_on: PrustiBinaryOp, - allow_trailing: bool, - ) -> Vec { + fn split(self, split_on: PrustiBinaryOp, allow_trailing: bool) -> Vec { if self.tokens.is_empty() { return vec![]; } - let mut res = self.tokens + let mut res = self + .tokens .into_iter() .collect::>() .split(|token| matches!(token, PrustiToken::BinOp(_, t) if *t == split_on)) - .map(|group| Self { tokens: group.iter().cloned().collect(), source_span: self.source_span }) + .map(|group| Self { + tokens: group.iter().cloned().collect(), + source_span: self.source_span, + }) .collect::>(); if allow_trailing && res.len() > 1 && res[res.len() - 1].tokens.is_empty() { res.pop(); @@ -466,22 +491,24 @@ impl PrustiTokenStream { &self.tokens[len - 2], &self.tokens[len - 1], ] { - [ - PrustiToken::BinOp(_, PrustiBinaryOp::Rust(RustOp::Comma)), - PrustiToken::Token(TokenTree::Ident(ident)), - PrustiToken::BinOp(_, PrustiBinaryOp::Rust(RustOp::Assign)), - PrustiToken::Group(triggers_span, Delimiter::Bracket, box triggers), - ] if ident == "triggers" => { - let triggers = triggers.clone() + [PrustiToken::BinOp(_, PrustiBinaryOp::Rust(RustOp::Comma)), PrustiToken::Token(TokenTree::Ident(ident)), PrustiToken::BinOp(_, PrustiBinaryOp::Rust(RustOp::Assign)), PrustiToken::Group(triggers_span, Delimiter::Bracket, box triggers)] + if ident == "triggers" => + { + let triggers = triggers + .clone() .split(PrustiBinaryOp::Rust(RustOp::Comma), true) .into_iter() - .map(|mut stream| stream - .pop_group(Delimiter::Parenthesis) - .ok_or_else(|| error(*triggers_span, "trigger sets must be tuples of expressions"))? - .split(PrustiBinaryOp::Rust(RustOp::Comma), true) - .into_iter() - .map(|stream| stream.parse()) - .collect::, _>>()) + .map(|mut stream| { + stream + .pop_group(Delimiter::Parenthesis) + .ok_or_else(|| { + error(*triggers_span, "trigger sets must be tuples of expressions") + })? + .split(PrustiBinaryOp::Rust(RustOp::Comma), true) + .into_iter() + .map(|stream| stream.parse()) + .collect::, _>>() + }) .collect::, _>>(); self.tokens.truncate(len - 4); triggers @@ -509,19 +536,26 @@ impl Parse for GhostConstraint { fn parse_trait_bounds(input: ParseStream) -> syn::Result> { use syn::WherePredicate::*; - + let mut bounds: Vec = Vec::new(); loop { - let predicate = input.parse::().map_err(with_ghost_constraint_example)?; + let predicate = input + .parse::() + .map_err(with_ghost_constraint_example)?; match predicate { Type(type_bound) => { validate_trait_bounds(&type_bound)?; bounds.push(type_bound); } Lifetime(lifetime_bound) => disallowed_lifetime_error(lifetime_bound.span())?, - Eq(eq_bound) => err(eq_bound.span(), "equality predicates are not supported in trait bounds")?, + Eq(eq_bound) => err( + eq_bound.span(), + "equality predicates are not supported in trait bounds", + )?, } - input.parse::().map_err(with_ghost_constraint_example)?; + input + .parse::() + .map_err(with_ghost_constraint_example)?; if input.peek(syn::token::Bracket) { break; } @@ -530,7 +564,10 @@ fn parse_trait_bounds(input: ParseStream) -> syn::Result } fn disallowed_lifetime_error(span: Span) -> syn::Result { - err(span, "lifetimes are not allowed in ghost constraint trait bounds") + err( + span, + "lifetimes are not allowed in ghost constraint trait bounds", + ) } fn validate_trait_bounds(trait_bounds: &syn::PredicateType) -> syn::Result<()> { @@ -544,7 +581,7 @@ fn validate_trait_bounds(trait_bounds: &syn::PredicateType) -> syn::Result<()> { } syn::TypeParamBound::Trait(trait_bound) => { if let Some(lt) = &trait_bound.lifetimes { - return disallowed_lifetime_error(lt.span()) + return disallowed_lifetime_error(lt.span()); } } } @@ -609,27 +646,37 @@ fn translate_spec_ent( let generic_res = TokenTree::Ident(proc_macro2::Ident::new("GR", span)); let extract_args = (0..arg_count) - .map(|i| TokenTree::Ident(proc_macro2::Ident::new(&format!("__extract_arg{}", i), span))) + .map(|i| { + TokenTree::Ident(proc_macro2::Ident::new( + &format!("__extract_arg{}", i), + span, + )) + }) .collect::>(); - let extract_args_decl = extract_args.iter() + let extract_args_decl = extract_args + .iter() .zip(generics_args.iter()) - .map(|(ident, arg_type)| quote_spanned! { span => - #[prusti::spec_only] - fn #ident< - #(#generics_args),* , - #generic_res, - F: FnOnce( #(#generics_args),* ) -> #generic_res - >(_f: &F) -> #arg_type { unreachable!() } + .map(|(ident, arg_type)| { + quote_spanned! { span => + #[prusti::spec_only] + fn #ident< + #(#generics_args),* , + #generic_res, + F: FnOnce( #(#generics_args),* ) -> #generic_res + >(_f: &F) -> #arg_type { unreachable!() } + } }) .collect::>(); - let preconds = contract.iter() + let preconds = contract + .iter() .filter_map(|spec| match spec { NestedSpec::Requires(stream) => Some(stream.clone()), _ => None, }) .collect::>(); - let postconds = contract.into_iter() + let postconds = contract + .into_iter() .filter_map(|spec| match spec { NestedSpec::Ensures(stream) => Some(stream), _ => None, @@ -673,11 +720,13 @@ impl Quantifier { body: TokenStream, ) -> TokenStream { // TODO: refer to forall and exists with prusti_contracts:: prefix - let trigger_sets = triggers.into_iter() + let trigger_sets = triggers + .into_iter() .map(|set| { - let triggers = TokenStream::from_iter(set.into_iter() - .map(|trigger| quote_spanned! { trigger.span() => - #[prusti::spec_only] | #args | ( #trigger ), })); + let triggers = TokenStream::from_iter(set.into_iter().map(|trigger| { + quote_spanned! { trigger.span() => + #[prusti::spec_only] | #args | ( #trigger ), } + })); quote_spanned! { span => ( #triggers ) } }) //.map(|set| quote_spanned! { span => @@ -703,26 +752,16 @@ impl Quantifier { // // "==>" should still have the expected spacing of [Joint, Joint, Alone] // even though "==" and ">" are separate Rust operators. -fn operator2( - op: &str, - p1: &Punct, - p2: &Punct, -) -> bool { +fn operator2(op: &str, p1: &Punct, p2: &Punct) -> bool { let chars = op.chars().collect::>(); - [p1.as_char(), p2.as_char()] == chars[0..2] - && p1.spacing() == Joint - && p2.spacing() == Alone + [p1.as_char(), p2.as_char()] == chars[0..2] && p1.spacing() == Joint && p2.spacing() == Alone } -fn operator3( - op: &str, - p1: &Punct, - p2: &Punct, - p3: &Punct, -) -> bool { +fn operator3(op: &str, p1: &Punct, p2: &Punct, p3: &Punct) -> bool { let chars = op.chars().collect::>(); [p1.as_char(), p2.as_char(), p3.as_char()] == chars[0..3] - && p1.spacing() == Joint && p2.spacing() == Joint + && p1.spacing() == Joint + && p2.spacing() == Joint && p3.spacing() == Alone } @@ -744,69 +783,68 @@ impl PrustiToken { if p.as_char() == '|' && p.spacing() == proc_macro2::Spacing::Alone) } - fn parse_op2( - p1: &Punct, - p2: &Punct, - ) -> Option { + fn parse_op2(p1: &Punct, p2: &Punct) -> Option { let span = join_spans(p1.span(), p2.span()); - Some(Self::BinOp(span, if operator2("&&", p1, p2) { - PrustiBinaryOp::And - } else if operator2("||", p1, p2) { - PrustiBinaryOp::Or - } else if operator2("->", p1, p2) { - PrustiBinaryOp::Implies - } else if operator2("..", p1, p2) { - PrustiBinaryOp::Rust(RustOp::Range) - } else if operator2("+=", p1, p2) { - PrustiBinaryOp::Rust(RustOp::AddAssign) - } else if operator2("-=", p1, p2) { - PrustiBinaryOp::Rust(RustOp::SubtractAssign) - } else if operator2("*=", p1, p2) { - PrustiBinaryOp::Rust(RustOp::MultiplyAssign) - } else if operator2("/=", p1, p2) { - PrustiBinaryOp::Rust(RustOp::DivideAssign) - } else if operator2("%=", p1, p2) { - PrustiBinaryOp::Rust(RustOp::ModuloAssign) - } else if operator2("&=", p1, p2) { - PrustiBinaryOp::Rust(RustOp::BitAndAssign) - //} else if operator2("|=", p1, p2) { - // PrustiBinaryOp::Rust(RustOp::BitOrAssign) - } else if operator2("^=", p1, p2) { - PrustiBinaryOp::Rust(RustOp::BitXorAssign) - } else if operator2("=>", p1, p2) { - PrustiBinaryOp::Rust(RustOp::Arrow) - } else if operator2("|=", p1, p2) { - return Some(Self::SpecEnt(span, false)); - } else if operator2("~>", p1, p2) { - return Some(Self::CallDesc(span, false)); - } else { - return None; - })) + Some(Self::BinOp( + span, + if operator2("&&", p1, p2) { + PrustiBinaryOp::And + } else if operator2("||", p1, p2) { + PrustiBinaryOp::Or + } else if operator2("->", p1, p2) { + PrustiBinaryOp::Implies + } else if operator2("..", p1, p2) { + PrustiBinaryOp::Rust(RustOp::Range) + } else if operator2("+=", p1, p2) { + PrustiBinaryOp::Rust(RustOp::AddAssign) + } else if operator2("-=", p1, p2) { + PrustiBinaryOp::Rust(RustOp::SubtractAssign) + } else if operator2("*=", p1, p2) { + PrustiBinaryOp::Rust(RustOp::MultiplyAssign) + } else if operator2("/=", p1, p2) { + PrustiBinaryOp::Rust(RustOp::DivideAssign) + } else if operator2("%=", p1, p2) { + PrustiBinaryOp::Rust(RustOp::ModuloAssign) + } else if operator2("&=", p1, p2) { + PrustiBinaryOp::Rust(RustOp::BitAndAssign) + //} else if operator2("|=", p1, p2) { + // PrustiBinaryOp::Rust(RustOp::BitOrAssign) + } else if operator2("^=", p1, p2) { + PrustiBinaryOp::Rust(RustOp::BitXorAssign) + } else if operator2("=>", p1, p2) { + PrustiBinaryOp::Rust(RustOp::Arrow) + } else if operator2("|=", p1, p2) { + return Some(Self::SpecEnt(span, false)); + } else if operator2("~>", p1, p2) { + return Some(Self::CallDesc(span, false)); + } else { + return None; + }, + )) } - fn parse_op3( - p1: &Punct, - p2: &Punct, - p3: &Punct, - ) -> Option { + fn parse_op3(p1: &Punct, p2: &Punct, p3: &Punct) -> Option { let span = join_spans(join_spans(p1.span(), p2.span()), p3.span()); - Some(Self::BinOp(span, if operator3("==>", p1, p2, p3) { - PrustiBinaryOp::Implies - } else if operator3("===", p1, p2, p3) { - PrustiBinaryOp::SnapEq - } else if operator3("..=", p1, p2, p3) { - PrustiBinaryOp::Rust(RustOp::RangeInclusive) - } else if operator3("<<=", p1, p2, p3) { - PrustiBinaryOp::Rust(RustOp::LeftShiftAssign) - } else if operator3(">>=", p1, p2, p3) { - PrustiBinaryOp::Rust(RustOp::RightShiftAssign) - } else if operator3("|=!", p1, p2, p3) { - return Some(Self::SpecEnt(span, true)); - } else if operator3("~>!", p1, p2, p3) { - return Some(Self::CallDesc(span, true)); - } else { - return None; - })) + Some(Self::BinOp( + span, + if operator3("==>", p1, p2, p3) { + PrustiBinaryOp::Implies + } else if operator3("===", p1, p2, p3) { + PrustiBinaryOp::SnapEq + } else if operator3("..=", p1, p2, p3) { + PrustiBinaryOp::Rust(RustOp::RangeInclusive) + } else if operator3("<<=", p1, p2, p3) { + PrustiBinaryOp::Rust(RustOp::LeftShiftAssign) + } else if operator3(">>=", p1, p2, p3) { + PrustiBinaryOp::Rust(RustOp::RightShiftAssign) + } else if operator3("|=!", p1, p2, p3) { + return Some(Self::SpecEnt(span, true)); + } else if operator3("~>!", p1, p2, p3) { + return Some(Self::CallDesc(span, true)); + } else { + return None; + }, + )) } } @@ -831,12 +869,7 @@ impl PrustiBinaryOp { } } - fn translate( - &self, - span: Span, - lhs: TokenStream, - rhs: TokenStream, - ) -> TokenStream { + fn translate(&self, span: Span, lhs: TokenStream, rhs: TokenStream) -> TokenStream { match self { Self::Rust(op) => op.translate(span, lhs, rhs), // implication is desugared into this form to avoid evaluation @@ -876,20 +909,12 @@ enum RustOp { } impl RustOp { - fn translate( - &self, - span: Span, - lhs: TokenStream, - rhs: TokenStream, - ) -> TokenStream { + fn translate(&self, span: Span, lhs: TokenStream, rhs: TokenStream) -> TokenStream { let op = self.to_tokens(span); quote! { #lhs #op #rhs } } - fn to_tokens( - self, - span: Span, - ) -> TokenStream { + fn to_tokens(self, span: Span) -> TokenStream { match self { Self::RangeInclusive => quote_spanned! { span => ..= }, Self::LeftShiftAssign => quote_spanned! { span => <<= }, @@ -916,7 +941,10 @@ fn join_spans(s1: Span, s2: Span) -> Span { let is_proc_macro = std::panic::catch_unwind(|| s1.unwrap()).is_ok(); if is_proc_macro { // This works even when compiled with stable - s1.unwrap().join(s2.unwrap()).expect("Failed to join spans!").into() + s1.unwrap() + .join(s2.unwrap()) + .expect("Failed to join spans!") + .into() } else { // During tests we don't care so much about returning a default s1.join(s2).unwrap_or(s1) @@ -928,28 +956,32 @@ mod tests { use super::*; macro_rules! assert_error { - ( $result:expr, $expected:expr ) => { - { - let _res = $result; - assert!(_res.is_err()); - let _err = _res.unwrap_err(); - assert_eq!(_err.to_string(), $expected); - } - }; + ( $result:expr, $expected:expr ) => {{ + let _res = $result; + assert!(_res.is_err()); + let _err = _res.unwrap_err(); + assert_eq!(_err.to_string(), $expected); + }}; } #[test] fn test_preparser() { assert_eq!( - parse_prusti("a ==> b".parse().unwrap()).unwrap().to_string(), + parse_prusti("a ==> b".parse().unwrap()) + .unwrap() + .to_string(), "(! (a) || (b))", ); assert_eq!( - parse_prusti("a ==> b ==> c".parse().unwrap()).unwrap().to_string(), + parse_prusti("a ==> b ==> c".parse().unwrap()) + .unwrap() + .to_string(), "(! (a) || ((! (b) || (c))))", ); assert_eq!( - parse_prusti("(a ==> b && c) ==> d || e".parse().unwrap()).unwrap().to_string(), + parse_prusti("(a ==> b && c) ==> d || e".parse().unwrap()) + .unwrap() + .to_string(), "(! (((! (a) || (b && c)))) || (d || e))", ); assert_eq!( @@ -965,7 +997,9 @@ mod tests { "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) })", ); assert_eq!( - parse_prusti("assert!(a === b ==> b)".parse().unwrap()).unwrap().to_string(), + parse_prusti("assert!(a === b ==> b)".parse().unwrap()) + .unwrap() + .to_string(), "assert ! ((! (snapshot_equality (& a , & b)) || (b)))", ); } @@ -978,20 +1012,41 @@ mod tests { #[test] fn invalid_args() { let err_invalid_bounds = "expected one of: `for`, parentheses, `fn`, `unsafe`, `extern`, identifier, `::`, `<`, square brackets, `*`, `&`, `!`, `impl`, `_`, lifetime"; - assert_error!(parse_ghost_constraint(quote!{ [requires(false)] }), err_invalid_bounds); - assert_error!(parse_ghost_constraint(quote!{ }), format!("unexpected end of input, {}", err_invalid_bounds)); - assert_error!(parse_ghost_constraint(quote!{T: A }), "expected `,`"); - assert_error!(parse_ghost_constraint(quote!{T: A, [requires(false)], "nope" }), "unexpected extra tokens"); - assert_error!(parse_ghost_constraint(quote!{[requires(false)], T: A }), err_invalid_bounds); - assert_error!(parse_ghost_constraint(quote!{T: A, }), "expected nested specification in brackets"); - assert_error!(parse_ghost_constraint(quote!{T: A, {} }), "expected nested specification in brackets"); + assert_error!( + parse_ghost_constraint(quote! { [requires(false)] }), + err_invalid_bounds + ); + assert_error!( + parse_ghost_constraint(quote! {}), + format!("unexpected end of input, {}", err_invalid_bounds) + ); + assert_error!(parse_ghost_constraint(quote! {T: A }), "expected `,`"); + assert_error!( + parse_ghost_constraint(quote! {T: A, [requires(false)], "nope" }), + "unexpected extra tokens" + ); + assert_error!( + parse_ghost_constraint(quote! {[requires(false)], T: A }), + err_invalid_bounds + ); + assert_error!( + parse_ghost_constraint(quote! {T: A, }), + "expected nested specification in brackets" + ); + assert_error!( + parse_ghost_constraint(quote! {T: A, {} }), + "expected nested specification in brackets" + ); } #[test] fn multiple_bounds_multiple_specs() { - let constraint = parse_ghost_constraint(quote!{ T: A+B+Foo, [requires(true), ensures(false), pure]}).unwrap(); + let constraint = parse_ghost_constraint( + quote! { T: A+B+Foo, [requires(true), ensures(false), pure]}, + ) + .unwrap(); - assert_bounds_eq(constraint.trait_bounds, quote!{ T : A + B + Foo < i32 > }); + assert_bounds_eq(constraint.trait_bounds, quote! { T : A + B + Foo < i32 > }); match &constraint.specs[0] { NestedSpec::Requires(ts) => assert_eq!(ts.to_string(), "true"), _ => panic!(), @@ -1006,28 +1061,32 @@ mod tests { #[test] fn no_specs() { - let constraint = parse_ghost_constraint(quote!{ T: A, []}).unwrap(); - assert_bounds_eq(constraint.trait_bounds, quote!{ T : A }); + let constraint = parse_ghost_constraint(quote! { T: A, []}).unwrap(); + assert_bounds_eq(constraint.trait_bounds, quote! { T : A }); assert!(constraint.specs.is_empty()); } #[test] fn fully_qualified_trait_path() { - let constraint = parse_ghost_constraint(quote!{ T: path::to::A, [requires(true)]}).unwrap(); - assert_bounds_eq(constraint.trait_bounds, quote!{ T : path :: to :: A }); + let constraint = + parse_ghost_constraint(quote! { T: path::to::A, [requires(true)]}).unwrap(); + assert_bounds_eq(constraint.trait_bounds, quote! { T : path :: to :: A }); } - + #[test] fn tuple_generics() { // just check that parsing succeeds - assert!(parse_ghost_constraint(quote!{ T: Fn<(i32,), Output = i32>, []}).is_ok()); - assert!(parse_ghost_constraint(quote!{ T: Fn<(i32,)>, []}).is_ok()); - assert!(parse_ghost_constraint(quote!{ T: Fn<(i32, bool)>, []}).is_ok()); - assert!(parse_ghost_constraint(quote!{ T: Fn<(i32, bool,)>, []}).is_ok()); + assert!(parse_ghost_constraint(quote! { T: Fn<(i32,), Output = i32>, []}).is_ok()); + assert!(parse_ghost_constraint(quote! { T: Fn<(i32,)>, []}).is_ok()); + assert!(parse_ghost_constraint(quote! { T: Fn<(i32, bool)>, []}).is_ok()); + assert!(parse_ghost_constraint(quote! { T: Fn<(i32, bool,)>, []}).is_ok()); } - + fn assert_bounds_eq(parsed: syn::PredicateType, quote: TokenStream) { - assert_eq!(syn::WherePredicate::Type(parsed), syn::parse_quote!{ #quote }); + assert_eq!( + syn::WherePredicate::Type(parsed), + syn::parse_quote! { #quote } + ); } } } diff --git a/prusti-contracts/prusti-specs/src/specifications/untyped.rs b/prusti-contracts/prusti-specs/src/specifications/untyped.rs index 7ad57070b7a..0d434409f2e 100644 --- a/prusti-contracts/prusti-specs/src/specifications/untyped.rs +++ b/prusti-contracts/prusti-specs/src/specifications/untyped.rs @@ -1,10 +1,12 @@ -use proc_macro2::{TokenStream}; +use crate::common::HasSignature; +use proc_macro2::TokenStream; use quote::ToTokens; use syn::Signature; -use crate::common::HasSignature; -pub use super::common::{SpecType, SpecificationId}; -pub use super::preparser::Arg; +pub use super::{ + common::{SpecType, SpecificationId}, + preparser::Arg, +}; /// An abstraction over all kinds of function items. #[derive(Debug, PartialEq, Eq)] @@ -24,7 +26,7 @@ impl syn::parse::Parse for AnyFnItem { // We have an item Fn. input.advance_to(&fork); Ok(AnyFnItem::Fn(res)) - }, + } Err(_) => { // It is not a valid ItemFn. let item_method = input.parse()?; @@ -62,7 +64,7 @@ impl AnyFnItem { pub fn expect_impl_item(self) -> syn::ImplItemMethod { match self { AnyFnItem::ImplMethod(i) => i, - _ => unreachable!() + _ => unreachable!(), } } } @@ -93,4 +95,4 @@ impl ToTokens for AnyFnItem { AnyFnItem::ImplMethod(item) => item.to_tokens(tokens), } } -} \ No newline at end of file +} diff --git a/prusti-contracts/prusti-specs/src/type_model/mod.rs b/prusti-contracts/prusti-specs/src/type_model/mod.rs index 50a61eda086..5d59e04d404 100644 --- a/prusti-contracts/prusti-specs/src/type_model/mod.rs +++ b/prusti-contracts/prusti-specs/src/type_model/mod.rs @@ -19,7 +19,8 @@ use crate::{ common::add_phantom_data_for_generic_params, user_provided_type_params::{ UserAnnotatedTypeParam, UserAnnotatedTypeParamParser, UserAnnotatedTypeParamParserError, - }, SPECS_VERSION, + }, + SPECS_VERSION, }; use proc_macro2::{Ident, TokenStream}; use quote::ToTokens; @@ -30,9 +31,11 @@ use uuid::Uuid; pub fn rewrite(item_struct: syn::ItemStruct) -> syn::Result> { let res = rewrite_internal(item_struct); match res { - Ok(result) => { - Ok(vec![syn::Item::Struct(result.model_struct), syn::Item::Trait(result.to_model_trait), syn::Item::Impl(result.model_impl)]) - }, + Ok(result) => Ok(vec![ + syn::Item::Struct(result.model_struct), + syn::Item::Trait(result.to_model_trait), + syn::Item::Impl(result.model_impl), + ]), Err(err) => Err(err.into()), } } @@ -135,7 +138,7 @@ impl ToModelTrait { .collect(); let model_path = &model_struct.path; - + let to_model_trait_ident = &idents.to_model_trait_ident; let item = parse_quote_spanned! {item_struct.span()=> #[allow(non_camel_case_types)] diff --git a/prusti-contracts/prusti-specs/src/user_provided_type_params.rs b/prusti-contracts/prusti-specs/src/user_provided_type_params.rs index 0a76f568e67..2ec67ca7903 100644 --- a/prusti-contracts/prusti-specs/src/user_provided_type_params.rs +++ b/prusti-contracts/prusti-specs/src/user_provided_type_params.rs @@ -1,7 +1,7 @@ +use crate::common::HasGenerics; use proc_macro2::TokenStream; use quote::ToTokens; use syn::{spanned::Spanned, TypeParam}; -use crate::common::HasGenerics; #[derive(Debug)] pub(crate) enum UserAnnotatedTypeParam { diff --git a/x.py b/x.py index 8c439d3f98e..befd7c77ab5 100755 --- a/x.py +++ b/x.py @@ -41,7 +41,7 @@ #'prusti-common', 'prusti-contracts/prusti-contracts', 'prusti-contracts/prusti-contracts-proc-macros', - #'prusti-contracts/prusti-specs', + 'prusti-contracts/prusti-specs', 'prusti-contracts/prusti-std', 'prusti-contracts-build', 'prusti-interface', From 99a17bfed20931d02c3965ff5155a3c0f4150889 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Mon, 28 Nov 2022 15:46:56 +0100 Subject: [PATCH 08/64] unify handling of bodies in extern specs and check more places --- .../src/extern_spec_rewriter/common.rs | 27 +++++++++++++++++++ .../src/extern_spec_rewriter/impls.rs | 24 +++-------------- .../src/extern_spec_rewriter/mods.rs | 3 ++- .../src/extern_spec_rewriter/traits.rs | 5 +--- 4 files changed, 33 insertions(+), 26 deletions(-) diff --git a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/common.rs b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/common.rs index 9fcd308e662..d1a9e88b6ba 100644 --- a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/common.rs +++ b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/common.rs @@ -325,3 +325,30 @@ pub fn rewrite_generics(gens: &syn::Generics) -> syn::AngleBracketedGenericArgum .collect(); syn::parse_quote! { < #(#args),* > } } + +/// Checks that the given block is a stub (`;`), returning an error otherwise. +pub(super) fn check_is_stub(block: &syn::Block) -> Result<(), syn::Error> { + if is_stub(block) { + Ok(()) + } else { + Err(syn::Error::new( + block.span(), + "Unexpected method body. (Extern specs only define specifications.)", + )) + } +} + +/// Recognizes method stubs, e.g. `fn foo();`. +/// +/// The absence of a body is represented in a roundabout way: +/// They have a body comprising a single verbatim item containing a single semicolon token. +fn is_stub(block: &syn::Block) -> bool { + if block.stmts.len() != 1 { + return false; + } + if let syn::Stmt::Item(syn::Item::Verbatim(tokens)) = &block.stmts[0] { + return tokens.to_string() == ";"; + } else { + return false; + } +} diff --git a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs index 042e0be63fa..10d56cedf68 100644 --- a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs +++ b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs @@ -92,12 +92,7 @@ fn rewrite_plain_impl(impl_item: &mut syn::ItemImpl, new_ty: Box) -> )); } syn::ImplItem::Method(method) => { - if !is_stub(&method.block) { - return Err(syn::Error::new( - method.span(), - "Unexpected method body. (Extern specs only define specifications.)", - )); - } + check_is_stub(&method.block)?; let (rewritten_method, spec_items) = generate_extern_spec_method_stub( method, @@ -131,21 +126,6 @@ fn rewrite_plain_impl(impl_item: &mut syn::ItemImpl, new_ty: Box) -> Ok(()) } -/// Recognizes method stubs, e.g. `fn foo();`. -/// -/// The absence of a body is represented in a roundabout way: -/// They have a body comprising a single verbatim item containing a single semicolon token. -fn is_stub(block: &syn::Block) -> bool { - if block.stmts.len() != 1 { - return false; - } - if let syn::Stmt::Item(syn::Item::Verbatim(tokens)) = &block.stmts[0] { - return tokens.to_string() == ";"; - } else { - return false; - } -} - fn rewrite_trait_impl( impl_item: syn::ItemImpl, new_ty: Box, @@ -172,6 +152,8 @@ fn rewrite_trait_impl( )); } syn::ImplItem::Method(method) => { + check_is_stub(&method.block)?; + let (rewritten_method, spec_items) = generate_extern_spec_method_stub( &method, &item_ty, diff --git a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/mods.rs b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/mods.rs index dca2acaf78a..4e30a6acc20 100644 --- a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/mods.rs +++ b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/mods.rs @@ -5,7 +5,7 @@ //! Modules are rewritten so that their name does not clash with the module //! they are specifying. -use super::common::generate_extern_spec_function_stub; +use super::common::{generate_extern_spec_function_stub, check_is_stub}; use crate::{specifications::common::generate_mod_name, ExternSpecKind}; use proc_macro2::{Group, TokenStream, TokenTree}; use quote::{quote, ToTokens}; @@ -35,6 +35,7 @@ fn rewrite_mod(item_mod: &mut syn::ItemMod, path: &syn::Path) -> syn::Result<()> for item in item_mod.content.as_mut().unwrap().1.iter_mut() { match item { syn::Item::Fn(item_fn) => { + check_is_stub(&item_fn.block)?; rewrite_fn(item_fn, &path); } syn::Item::Mod(inner_mod) => { diff --git a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs index 820345f0509..e41c84a59ed 100644 --- a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs +++ b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs @@ -148,10 +148,7 @@ impl<'a> GeneratedStruct<'a> { } syn::TraitItem::Method(trait_method) => { if let Some(default) = &trait_method.default { - return Err(syn::Error::new( - default.span(), - "Default methods in external trait specs are invalid", - )); + return Err(check_is_stub(&default).expect_err("this cannot be a stub")); } let (method, spec_fns) = self.generate_method_stub(trait_method)?; From 01122410ab5fb19a22a8da88e3c280a31ff56a46 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Mon, 28 Nov 2022 15:47:05 +0100 Subject: [PATCH 09/64] add unit test for bodies in extern specs --- .../tests/parse/fail/extern-spec/no-bodies.rs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 prusti-tests/tests/parse/fail/extern-spec/no-bodies.rs diff --git a/prusti-tests/tests/parse/fail/extern-spec/no-bodies.rs b/prusti-tests/tests/parse/fail/extern-spec/no-bodies.rs new file mode 100644 index 00000000000..5080759c6a4 --- /dev/null +++ b/prusti-tests/tests/parse/fail/extern-spec/no-bodies.rs @@ -0,0 +1,29 @@ +use prusti_contracts::*; + +#[extern_spec] +impl Option { + #[pure] + fn is_some(&self) -> bool {} //~ ERROR: Unexpected method body. (Extern specs only define specifications.) +} + +#[extern_spec] +trait Clone { + #[pure] + fn clone(&self) -> Self {} //~ ERROR: Unexpected method body. (Extern specs only define specifications.) +} + +#[extern_spec] +impl Clone for i32 { + #[pure] + fn clone(&self) -> Self {} //~ ERROR: Unexpected method body. (Extern specs only define specifications.) +} + +#[extern_spec] +mod core { + mod mem { + use crate::*; + + #[pure] + pub fn size_of() -> usize {} //~ ERROR: Unexpected method body. (Extern specs only define specifications.) + } +} From 44358db71adb159ca1b2c21c7dff67151cee8a35 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Mon, 28 Nov 2022 16:08:56 +0100 Subject: [PATCH 10/64] update unit tests --- .../src/specifications/preparser.rs | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/prusti-contracts/prusti-specs/src/specifications/preparser.rs b/prusti-contracts/prusti-specs/src/specifications/preparser.rs index b39a0fc0ad6..fd539cc64d5 100644 --- a/prusti-contracts/prusti-specs/src/specifications/preparser.rs +++ b/prusti-contracts/prusti-specs/src/specifications/preparser.rs @@ -556,7 +556,7 @@ fn parse_trait_bounds(input: ParseStream) -> syn::Result input .parse::() .map_err(with_ghost_constraint_example)?; - if input.peek(syn::token::Bracket) { + if input.peek(syn::token::Bracket) || input.is_empty() { break; } } @@ -1035,18 +1035,18 @@ mod tests { ); assert_error!( parse_ghost_constraint(quote! {T: A, {} }), - "expected nested specification in brackets" + err_invalid_bounds ); } #[test] fn multiple_bounds_multiple_specs() { let constraint = parse_ghost_constraint( - quote! { T: A+B+Foo, [requires(true), ensures(false), pure]}, + quote! { T: A+B+Foo, U: C, [requires(true), ensures(false), pure]}, ) .unwrap(); - assert_bounds_eq(constraint.trait_bounds, quote! { T : A + B + Foo < i32 > }); + assert_bounds_eq(&constraint.trait_bounds, &[quote! { T : A + B + Foo < i32 > }, quote! { U : C }]); match &constraint.specs[0] { NestedSpec::Requires(ts) => assert_eq!(ts.to_string(), "true"), _ => panic!(), @@ -1062,7 +1062,7 @@ mod tests { #[test] fn no_specs() { let constraint = parse_ghost_constraint(quote! { T: A, []}).unwrap(); - assert_bounds_eq(constraint.trait_bounds, quote! { T : A }); + assert_bounds_eq(&constraint.trait_bounds, &[quote! { T : A }]); assert!(constraint.specs.is_empty()); } @@ -1070,7 +1070,7 @@ mod tests { fn fully_qualified_trait_path() { let constraint = parse_ghost_constraint(quote! { T: path::to::A, [requires(true)]}).unwrap(); - assert_bounds_eq(constraint.trait_bounds, quote! { T : path :: to :: A }); + assert_bounds_eq(&constraint.trait_bounds, &[quote! { T : path :: to :: A }]); } #[test] @@ -1082,11 +1082,14 @@ mod tests { assert!(parse_ghost_constraint(quote! { T: Fn<(i32, bool,)>, []}).is_ok()); } - fn assert_bounds_eq(parsed: syn::PredicateType, quote: TokenStream) { - assert_eq!( - syn::WherePredicate::Type(parsed), - syn::parse_quote! { #quote } - ); + fn assert_bounds_eq(parsed: &[syn::PredicateType], quotes: &[TokenStream]) { + assert_eq!(parsed.len(), quotes.len()); + for (parsed, quote) in parsed.iter().zip(quotes.iter()) { + assert_eq!( + syn::WherePredicate::Type(parsed.clone()), + syn::parse_quote! { #quote } + ); + } } } } From 3535dbb8f62203fdd3caa12b76465d96912554ea Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Wed, 7 Dec 2022 05:47:07 +0100 Subject: [PATCH 11/64] parse new syntax for ghost constraints/conditional spec refinements --- .../prusti-contracts-proc-macros/src/lib.rs | 4 +- prusti-contracts/prusti-contracts/src/lib.rs | 2 +- .../prusti-specs/src/spec_attribute_kind.rs | 2 +- .../src/specifications/preparser.rs | 47 +++++++++---------- .../trait-bounds-illegal-1.rs | 2 +- .../trait-bounds-illegal-2.rs | 2 +- .../trait-bounds-illegal-3.rs | 3 +- .../trait-bounds-invalid-macro-arguments-1.rs | 4 +- .../trait-bounds-invalid-macro-arguments-2.rs | 2 +- .../verify/fail/ghost-constraints/purity.rs | 2 +- .../verify/fail/ghost-constraints/traits-1.rs | 4 +- .../ghost-constraints/extern-spec/traits-1.rs | 4 +- .../verify/pass/ghost-constraints/purity.rs | 2 +- .../invalid-trait-refinement-1.rs | 4 +- .../invalid-trait-refinement-1.stderr | 6 +-- .../invalid-trait-refinement-2.rs | 6 +-- .../invalid-trait-refinement-2.stderr | 10 ++-- .../ghost-constraints/associated-types-1.rs | 6 +-- .../ghost-constraints/associated-types-2.rs | 6 +-- .../ghost-constraints/associated-types-3.rs | 6 +-- .../ghost-constraints/associated-types-4.rs | 6 +-- .../ghost-constraints/associated-types-5.rs | 6 +-- .../ghost-constraints/associated-types-6.rs | 4 +- .../ghost-constraints/associated-types-7.rs | 6 +-- .../ghost-constraints/different-bounds.rs | 4 +- .../in-local-refinement-disallowed.rs | 8 ++-- .../in-non-trusted-function.rs | 6 +-- .../fail/ghost-constraints/nested-generics.rs | 2 +- .../ghost-constraints/associated-types-1.rs | 6 +-- .../ghost-constraints/associated-types-2.rs | 6 +-- .../ghost-constraints/associated-types-3.rs | 6 +-- .../ghost-constraints/associated-types-4.rs | 6 +-- .../ghost-constraints/associated-types-5.rs | 6 +-- ...host-constraints-extend-base-attributes.rs | 6 +-- .../ghost-constraints/merge-where-clause.rs | 2 +- .../pass/ghost-constraints/nested-generics.rs | 2 +- .../normalize-associated-types.rs | 8 ++-- .../ghost-constraints/split-constraint.rs | 4 +- .../pass/ghost-constraints/traits-1.rs | 4 +- 39 files changed, 111 insertions(+), 111 deletions(-) diff --git a/prusti-contracts/prusti-contracts-proc-macros/src/lib.rs b/prusti-contracts/prusti-contracts-proc-macros/src/lib.rs index 2edd74c80cc..5a13946787d 100644 --- a/prusti-contracts/prusti-contracts-proc-macros/src/lib.rs +++ b/prusti-contracts/prusti-contracts-proc-macros/src/lib.rs @@ -90,7 +90,7 @@ pub fn model(_attr: TokenStream, _tokens: TokenStream) -> TokenStream { #[cfg(not(feature = "prusti"))] #[proc_macro_attribute] -pub fn ghost_constraint(_attr: TokenStream, tokens: TokenStream) -> TokenStream { +pub fn refine_spec(_attr: TokenStream, tokens: TokenStream) -> TokenStream { tokens } @@ -221,7 +221,7 @@ pub fn model(_attr: TokenStream, tokens: TokenStream) -> TokenStream { #[cfg(feature = "prusti")] #[proc_macro_attribute] -pub fn ghost_constraint(attr: TokenStream, tokens: TokenStream) -> TokenStream { +pub fn refine_spec(attr: TokenStream, tokens: TokenStream) -> TokenStream { rewrite_prusti_attributes( SpecAttributeKind::GhostConstraint, attr.into(), diff --git a/prusti-contracts/prusti-contracts/src/lib.rs b/prusti-contracts/prusti-contracts/src/lib.rs index 6fe66caae8f..9c299eeb7ef 100644 --- a/prusti-contracts/prusti-contracts/src/lib.rs +++ b/prusti-contracts/prusti-contracts/src/lib.rs @@ -45,7 +45,7 @@ pub use prusti_contracts_proc_macros::model; /// A macro to add trait bounds on a generic type parameter and specifications /// which are active only when these bounds are satisfied for a call. -pub use prusti_contracts_proc_macros::ghost_constraint; +pub use prusti_contracts_proc_macros::refine_spec; /// A macro for defining ghost blocks which will be left in for verification /// but omitted during compilation. diff --git a/prusti-contracts/prusti-specs/src/spec_attribute_kind.rs b/prusti-contracts/prusti-specs/src/spec_attribute_kind.rs index 67c7c3d8012..fb835acd81d 100644 --- a/prusti-contracts/prusti-specs/src/spec_attribute_kind.rs +++ b/prusti-contracts/prusti-specs/src/spec_attribute_kind.rs @@ -32,7 +32,7 @@ impl TryFrom for SpecAttributeKind { "trusted" => Ok(SpecAttributeKind::Trusted), "predicate" => Ok(SpecAttributeKind::Predicate), "invariant" => Ok(SpecAttributeKind::Invariant), - "ghost_constraint" => Ok(SpecAttributeKind::GhostConstraint), + "refine_spec" => Ok(SpecAttributeKind::GhostConstraint), "model" => Ok(SpecAttributeKind::Model), "print_counterexample" => Ok(SpecAttributeKind::PrintCounterexample), _ => Err(name), diff --git a/prusti-contracts/prusti-specs/src/specifications/preparser.rs b/prusti-contracts/prusti-specs/src/specifications/preparser.rs index fd539cc64d5..48cd21acafe 100644 --- a/prusti-contracts/prusti-specs/src/specifications/preparser.rs +++ b/prusti-contracts/prusti-specs/src/specifications/preparser.rs @@ -526,41 +526,37 @@ pub struct GhostConstraint { impl Parse for GhostConstraint { fn parse(input: ParseStream) -> syn::Result { + let where_clause = input + .parse::() + .map_err(with_ghost_constraint_example)?; Ok(GhostConstraint { - trait_bounds: parse_trait_bounds(input)?, + trait_bounds: where_clause + .predicates + .into_iter() + .map(validate_predicate) + .collect::>>()?, specs: PrustiTokenStream::new(input.parse().unwrap()) .parse_rest(|pts| pts.pop_group_of_nested_specs(input.span()))?, }) } } -fn parse_trait_bounds(input: ParseStream) -> syn::Result> { +fn validate_predicate(predicate: syn::WherePredicate) -> syn::Result { use syn::WherePredicate::*; - let mut bounds: Vec = Vec::new(); - loop { - let predicate = input - .parse::() - .map_err(with_ghost_constraint_example)?; - match predicate { - Type(type_bound) => { - validate_trait_bounds(&type_bound)?; - bounds.push(type_bound); - } - Lifetime(lifetime_bound) => disallowed_lifetime_error(lifetime_bound.span())?, - Eq(eq_bound) => err( - eq_bound.span(), - "equality predicates are not supported in trait bounds", - )?, + match predicate { + Type(type_bound) => { + validate_trait_bounds(&type_bound)?; + Ok(type_bound) } - input - .parse::() - .map_err(with_ghost_constraint_example)?; - if input.peek(syn::token::Bracket) || input.is_empty() { - break; + Lifetime(lifetime_bound) => { + disallowed_lifetime_error(lifetime_bound.span()) } + Eq(eq_bound) => err( + eq_bound.span(), + "equality constraints are not allowed in ghost constraints", + ), } - Ok(bounds) } fn disallowed_lifetime_error(span: Span) -> syn::Result { @@ -1046,7 +1042,10 @@ mod tests { ) .unwrap(); - assert_bounds_eq(&constraint.trait_bounds, &[quote! { T : A + B + Foo < i32 > }, quote! { U : C }]); + assert_bounds_eq( + &constraint.trait_bounds, + &[quote! { T : A + B + Foo < i32 > }, quote! { U : C }], + ); match &constraint.specs[0] { NestedSpec::Requires(ts) => assert_eq!(ts.to_string(), "true"), _ => panic!(), diff --git a/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-1.rs b/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-1.rs index ac5cf5fba03..f5544d6578d 100644 --- a/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-1.rs +++ b/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-1.rs @@ -2,7 +2,7 @@ use prusti_contracts::*; trait A { } -#[ghost_constraint(T: 'static + A, [ //~ ERROR: lifetimes are not allowed in ghost constraint trait bounds +#[refine_spec(where T: 'static + A [ //~ ERROR: lifetimes are not allowed in ghost constraint trait bounds ensures(result > 0) ])] fn foo(_x: T) -> i32 { diff --git a/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-2.rs b/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-2.rs index c4c494fe881..c8955923caa 100644 --- a/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-2.rs +++ b/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-2.rs @@ -2,7 +2,7 @@ use prusti_contracts::*; trait A { } -#[ghost_constraint(T: for<'a> A<&'a i32>, [ //~ ERROR: lifetimes are not allowed in ghost constraint trait bounds +#[refine_spec(where T: for<'a> A<&'a i32> [ //~ ERROR: lifetimes are not allowed in ghost constraint trait bounds ensures(result > 0) ])] fn foo(_x: T) -> i32 { diff --git a/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-3.rs b/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-3.rs index 0c19fddfbd9..cbf2ba32370 100644 --- a/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-3.rs +++ b/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-3.rs @@ -5,9 +5,10 @@ struct MyStruct { } impl MyStruct { - #[ghost_constraint(Self: MyStruct, [ //~ ERROR: expected trait, found struct `MyStruct` + #[refine_spec(where elf: MyStruct [ //~ ERROR: expected trait, found struct `MyStruct` requires(x > 0) ])] + //~| ERROR: cannot find type `elf` in this scope [E0412] fn set_x(&mut self, x: T) { self.x = x; } diff --git a/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-invalid-macro-arguments-1.rs b/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-invalid-macro-arguments-1.rs index 9c8dff2396a..f69ed774cd6 100644 --- a/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-invalid-macro-arguments-1.rs +++ b/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-invalid-macro-arguments-1.rs @@ -1,7 +1,7 @@ use prusti_contracts::*; -#[ghost_constraint([ - ensures(result > 0) //~ ERROR: expected `,` +#[refine_spec([ //~ ERROR: expected `where` + ensures(result > 0) ])] //~| ERROR: expected a trait bound and specifications in brackets, e.g.: `ghost_constraint(T: A + B + ..., [requires(...), ...])` fn foo(_x: T) -> i32 { diff --git a/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-invalid-macro-arguments-2.rs b/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-invalid-macro-arguments-2.rs index c610009df8a..038f5dc5f96 100644 --- a/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-invalid-macro-arguments-2.rs +++ b/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-invalid-macro-arguments-2.rs @@ -1,6 +1,6 @@ use prusti_contracts::*; -#[ghost_constraint(42, [ //~ ERROR: expected one of: `for`, parentheses, `fn`, `unsafe`, `extern`, identifier, `::`, `<`, square brackets, `*`, `&`, `!`, `impl`, `_`, lifetime +#[refine_spec(where 42 [ //~ ERROR: expected one of: `for`, parentheses, `fn`, `unsafe`, `extern`, identifier, `::`, `<`, square brackets, `*`, `&`, `!`, `impl`, `_`, lifetime ensures(result > 0) ])] //~| ERROR: expected a trait bound and specifications in brackets, e.g.: `ghost_constraint(T: A + B + ..., [requires(...), ...])` diff --git a/prusti-tests/tests/verify/fail/ghost-constraints/purity.rs b/prusti-tests/tests/verify/fail/ghost-constraints/purity.rs index b7b262bda52..e0bcbda6a2e 100644 --- a/prusti-tests/tests/verify/fail/ghost-constraints/purity.rs +++ b/prusti-tests/tests/verify/fail/ghost-constraints/purity.rs @@ -2,7 +2,7 @@ use prusti_contracts::*; -#[ghost_constraint(T: Copy, [pure])] +#[refine_spec(where T: Copy [pure])] #[trusted] fn test(_t: T) -> bool { true } diff --git a/prusti-tests/tests/verify/fail/ghost-constraints/traits-1.rs b/prusti-tests/tests/verify/fail/ghost-constraints/traits-1.rs index 8867f846448..50bc5dc41b9 100644 --- a/prusti-tests/tests/verify/fail/ghost-constraints/traits-1.rs +++ b/prusti-tests/tests/verify/fail/ghost-constraints/traits-1.rs @@ -5,7 +5,7 @@ use prusti_contracts::*; trait A {} trait MyTrait { - #[ghost_constraint(Self: A, [ensures(result > 0)])] + #[refine_spec(where Self: A [ensures(result > 0)])] #[trusted] fn foo(&self) -> i32; } @@ -21,4 +21,4 @@ impl MyTrait for MyStruct { fn main() { let s = MyStruct; assert!(s.foo() > 0); //~ ERROR: the asserted expression might not hold -} \ No newline at end of file +} diff --git a/prusti-tests/tests/verify/pass/ghost-constraints/extern-spec/traits-1.rs b/prusti-tests/tests/verify/pass/ghost-constraints/extern-spec/traits-1.rs index 04169626183..d2dec593bad 100644 --- a/prusti-tests/tests/verify/pass/ghost-constraints/extern-spec/traits-1.rs +++ b/prusti-tests/tests/verify/pass/ghost-constraints/extern-spec/traits-1.rs @@ -15,7 +15,7 @@ trait MyTrait { #[extern_spec] trait MyTrait { - #[ghost_constraint(Self: HasContract, [ + #[refine_spec(where Self: HasContract [ requires(self.pre()), ensures(self.post()) ])] @@ -49,4 +49,4 @@ fn main() { let mut s = MyStruct { x: 10 }; s.foo(); assert!(s.x >= 20); -} \ No newline at end of file +} diff --git a/prusti-tests/tests/verify/pass/ghost-constraints/purity.rs b/prusti-tests/tests/verify/pass/ghost-constraints/purity.rs index 2de4b07e018..dc58f371366 100644 --- a/prusti-tests/tests/verify/pass/ghost-constraints/purity.rs +++ b/prusti-tests/tests/verify/pass/ghost-constraints/purity.rs @@ -2,7 +2,7 @@ use prusti_contracts::*; -#[ghost_constraint(T: Copy, [pure])] +#[refine_spec(where T: Copy [pure])] #[trusted] fn test(_t: T) -> bool { true } diff --git a/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-1.rs b/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-1.rs index 99e6621988d..19977f9fe6f 100644 --- a/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-1.rs +++ b/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-1.rs @@ -15,7 +15,7 @@ trait MyTrait { #[extern_spec] trait MyTrait { - #[ghost_constraint(Self: HasContract, [ + #[refine_spec(where Self: HasContract [ requires(self.pre()), ensures(self.post()) ])] fn foo(&mut self); @@ -46,4 +46,4 @@ impl HasContract for MyStruct { } fn main() { -} \ No newline at end of file +} diff --git a/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-1.stderr b/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-1.stderr index 788c061004b..674a5476d94 100644 --- a/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-1.stderr +++ b/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-1.stderr @@ -1,8 +1,8 @@ error: [Prusti: verification error] the method's precondition may not be a valid weakening of the trait's precondition. - --> $DIR/invalid-trait-refinement-1.rs:18:30 + --> $DIR/invalid-trait-refinement-1.rs:18:31 | -18 | #[ghost_constraint(Self: HasContract, [ - | ______________________________^ +18 | #[refine_spec(where Self: HasContract [ + | _______________________________^ 19 | | requires(self.pre()), ensures(self.post()) | |___________________________^ ... diff --git a/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-2.rs b/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-2.rs index b8489c8f18f..e7fa3743cb9 100644 --- a/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-2.rs +++ b/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-2.rs @@ -15,8 +15,8 @@ trait MyTrait { #[extern_spec] trait MyTrait { - #[ghost_constraint(Self: HasContract, [ - requires(self.pre()), ensures(self.post()) + #[refine_spec(where Self: HasContract [ + requires(self.pre()), ensures(self.post()) ])] fn foo(&mut self); } @@ -46,4 +46,4 @@ impl HasContract for MyStruct { } fn main() { -} \ No newline at end of file +} diff --git a/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-2.stderr b/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-2.stderr index 3df59fbe094..06e52fcb738 100644 --- a/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-2.stderr +++ b/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-2.stderr @@ -1,10 +1,10 @@ error: [Prusti: verification error] the method's postcondition may not be a valid strengthening of the trait's postcondition. - --> $DIR/invalid-trait-refinement-2.rs:18:30 + --> $DIR/invalid-trait-refinement-2.rs:18:31 | -18 | #[ghost_constraint(Self: HasContract, [ - | ______________________________^ -19 | | requires(self.pre()), ensures(self.post()) - | |_____________________________________________^ +18 | #[refine_spec(where Self: HasContract [ + | _______________________________^ +19 | | requires(self.pre()), ensures(self.post()) + | |_________________________________________________^ ... 30 | #[ensures(self.x >= 15)] | ^^^^^^^^^^^^ diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-1.rs b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-1.rs index c42497d77d6..9d8e9f4d33a 100644 --- a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-1.rs +++ b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-1.rs @@ -11,8 +11,8 @@ impl A for Foo { } #[trusted] -#[ghost_constraint(T: A , [ -ensures(result > 0) +#[refine_spec(where T: A [ + ensures(result > 0) ])] fn foo(x: T) -> i32 { 42 @@ -23,4 +23,4 @@ fn main() { let f = Foo; let res = foo(f); assert!(res > 0); //~ ERROR: the asserted expression might not hold -} \ No newline at end of file +} diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-2.rs b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-2.rs index 785a5c94e61..4985e63a3a8 100644 --- a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-2.rs +++ b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-2.rs @@ -24,8 +24,8 @@ impl SomeTrait for Foo { #[extern_spec] trait SomeTrait { - #[ghost_constraint(Self: A::AssocType> , [ - ensures(result > 0) + #[refine_spec(where Self: A::AssocType> [ + ensures(result > 0) ])] fn foo(&self) -> i32; } @@ -34,4 +34,4 @@ fn main() { let f = Foo; let res = f.foo(); assert!(res > 0); //~ ERROR: [Prusti: verification error] the asserted expression might not hold -} \ No newline at end of file +} diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-3.rs b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-3.rs index c95f86d42c4..9115ed4100e 100644 --- a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-3.rs +++ b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-3.rs @@ -26,8 +26,8 @@ impl SomeTrait for Foo { #[extern_spec] trait SomeTrait { - #[ghost_constraint(Self: A::AssocType> , [ - ensures(result > 0) + #[refine_spec(where Self: A::AssocType> [ + ensures(result > 0) ])] fn foo(&self) -> i32; } @@ -38,4 +38,4 @@ fn main() { }; let res = f.foo(); assert!(res > 0); //~ ERROR: [Prusti: verification error] the asserted expression might not hold -} \ No newline at end of file +} diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-4.rs b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-4.rs index 8b742478a66..a7f9e625e95 100644 --- a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-4.rs +++ b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-4.rs @@ -24,8 +24,8 @@ impl SomeTrait for Foo { #[extern_spec] trait SomeTrait<#[generic] T> { - #[ghost_constraint(Self: A>::AssocType> , [ - ensures(result > 0) + #[refine_spec(where Self: A>::AssocType> [ + ensures(result > 0) ])] fn foo(&self, x: T) -> i32; } @@ -34,4 +34,4 @@ fn main() { let f = Foo; let res = f.foo(42 as u32); assert!(res > 0); //~ ERROR: [Prusti: verification error] the asserted expression might not hold -} \ No newline at end of file +} diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-5.rs b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-5.rs index 877741e5244..0c6453e596e 100644 --- a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-5.rs +++ b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-5.rs @@ -11,8 +11,8 @@ impl A for Foo { } #[trusted] -#[ghost_constraint(T: A , [ -ensures(result > 0) +#[refine_spec(where T: A [ + ensures(result > 0) ])] fn foo(x: T) -> i32 { 42 @@ -22,4 +22,4 @@ fn main() { let f = Foo; let res = foo(f); assert!(res > 0); //~ ERROR: [Prusti: verification error] the asserted expression might not hold -} \ No newline at end of file +} diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-6.rs b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-6.rs index afd0aa47ccd..a8db91432df 100644 --- a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-6.rs +++ b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-6.rs @@ -22,7 +22,7 @@ impl A for FooNoMatch2 { #[trusted] -#[ghost_constraint(T: A , [ +#[refine_spec(where T: A [ ensures(result > 0) ])] fn foo(x: T) -> i32 { @@ -45,4 +45,4 @@ fn verify_no_match_2() { } fn main() { -} \ No newline at end of file +} diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-7.rs b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-7.rs index c9eb6cbc754..ff4b87ed76e 100644 --- a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-7.rs +++ b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-7.rs @@ -39,8 +39,8 @@ impl SomeTrait for FooNoMatch2 { #[extern_spec] trait SomeTrait<#[generic] X, #[generic] Y> { - #[ghost_constraint(Self: A>::AssocType> , [ - ensures(result > 0) + #[refine_spec(where Self: A>::AssocType> [ + ensures(result > 0) ])] fn foo(&self) -> i32; } @@ -61,4 +61,4 @@ fn verify_no_match_2() { } fn main() { -} \ No newline at end of file +} diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/different-bounds.rs b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/different-bounds.rs index 4be7038043e..49407944cb7 100644 --- a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/different-bounds.rs +++ b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/different-bounds.rs @@ -9,11 +9,11 @@ trait A {} trait B {} #[trusted] -#[ghost_constraint(T: A, [ //~ ERROR: [Prusti: unsupported feature] Multiple ghost constraints with different bounds defined +#[refine_spec(where T: A [ //~ ERROR: [Prusti: unsupported feature] Multiple ghost constraints with different bounds defined requires(true), ensures(true), ])] -#[ghost_constraint(T: B, [ +#[refine_spec(where T: B [ requires(true), ensures(true), ])] diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-local-refinement-disallowed.rs b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-local-refinement-disallowed.rs index 4bbad810115..9e686a548e8 100644 --- a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-local-refinement-disallowed.rs +++ b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-local-refinement-disallowed.rs @@ -6,8 +6,8 @@ trait A {} trait MyTrait { #[ensures(result > 0)] - #[ghost_constraint(Self: A, [ - ensures(result % 2 == 0) + #[refine_spec(where Self: A [ + ensures(result % 2 == 0) ])] fn foo(&self) -> i32; } @@ -17,8 +17,8 @@ struct MyStruct; impl MyTrait for MyStruct { #[ensures(result > 10)] - #[ghost_constraint(Self: A, [ //~ ERROR: Ghost constraints in trait spec refinements not supported - ensures(result % 6 == 0) + #[refine_spec(where Self: A [ //~ ERROR: Ghost constraints in trait spec refinements not supported + ensures(result % 6 == 0) ])] fn foo(&self) -> i32 { 42 diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-non-trusted-function.rs b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-non-trusted-function.rs index e81fdc1549e..9759106e7c5 100644 --- a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-non-trusted-function.rs +++ b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-non-trusted-function.rs @@ -4,10 +4,10 @@ use prusti_contracts::*; trait A {} -#[ghost_constraint(T: A, [ -ensures(true) +#[refine_spec(where T: A [ + ensures(true) ])] fn foo() {} //~ ERROR: Ghost constraints can only be used on trusted functions fn main() { -} \ No newline at end of file +} diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/nested-generics.rs b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/nested-generics.rs index 37affbfcf6d..d5bba3474ca 100644 --- a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/nested-generics.rs +++ b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/nested-generics.rs @@ -11,7 +11,7 @@ impl A for i32 {} impl B for i32 {} #[trusted] -#[ghost_constraint(T: A + B + B , [ +#[refine_spec(where T: A + B + B [ ensures(result > 0) ])] fn foo(_x: T) -> i32 { diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-1.rs b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-1.rs index c8119cebba5..b0269fe8f23 100644 --- a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-1.rs +++ b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-1.rs @@ -11,8 +11,8 @@ impl A for Foo { } #[trusted] -#[ghost_constraint(T: A , [ -ensures(result > 0) +#[refine_spec(where T: A [ + ensures(result > 0) ])] fn foo(x: T) -> i32 { 42 @@ -23,4 +23,4 @@ fn main() { let f = Foo; let res = foo(f); assert!(res > 0); -} \ No newline at end of file +} diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-2.rs b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-2.rs index 19023db9664..15913ec564b 100644 --- a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-2.rs +++ b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-2.rs @@ -24,8 +24,8 @@ impl SomeTrait for Foo { #[extern_spec] trait SomeTrait { - #[ghost_constraint(Self: A::AssocType> , [ - ensures(result > 0) + #[refine_spec(where Self: A::AssocType> [ + ensures(result > 0) ])] fn foo(&self) -> i32; } @@ -34,4 +34,4 @@ fn main() { let f = Foo; let res = f.foo(); assert!(res > 0); // Ghost constraint satisfied! -} \ No newline at end of file +} diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-3.rs b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-3.rs index 54d8025c503..232d8f00bea 100644 --- a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-3.rs +++ b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-3.rs @@ -26,8 +26,8 @@ impl SomeTrait for Foo { #[extern_spec] trait SomeTrait { - #[ghost_constraint(Self: A::AssocType> , [ - ensures(result > 0) + #[refine_spec(where Self: A::AssocType> [ + ensures(result > 0) ])] fn foo(&self) -> i32; } @@ -38,4 +38,4 @@ fn main() { }; let res = f.foo(); assert!(res > 0); -} \ No newline at end of file +} diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-4.rs b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-4.rs index 8970ca1108d..8e4f7fd32d9 100644 --- a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-4.rs +++ b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-4.rs @@ -24,8 +24,8 @@ impl SomeTrait for Foo { #[extern_spec] trait SomeTrait<#[generic] T> { - #[ghost_constraint(Self: A>::AssocType> , [ - ensures(result > 0) + #[refine_spec(where Self: A>::AssocType> [ + ensures(result > 0) ])] fn foo(&self, x: T) -> i32; } @@ -34,4 +34,4 @@ fn main() { let f = Foo; let res = f.foo(42 as i32); assert!(res > 0); -} \ No newline at end of file +} diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-5.rs b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-5.rs index fba24fb2457..b52d74a4d98 100644 --- a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-5.rs +++ b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-5.rs @@ -11,8 +11,8 @@ impl A for Foo { } #[trusted] -#[ghost_constraint(T: A , [ -ensures(result > 0) +#[refine_spec(where T: A [ + ensures(result > 0) ])] fn foo(x: T) -> i32 { 42 @@ -22,4 +22,4 @@ fn main() { let f = Foo; let res = foo(f); assert!(res > 0); -} \ No newline at end of file +} diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/ghost-constraints-extend-base-attributes.rs b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/ghost-constraints-extend-base-attributes.rs index d6818ad2352..0a3f2cd9d6b 100644 --- a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/ghost-constraints-extend-base-attributes.rs +++ b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/ghost-constraints-extend-base-attributes.rs @@ -8,7 +8,7 @@ impl A for i32 {} #[pure] #[trusted] -#[ghost_constraint(T: A, [ +#[refine_spec(where T: A [ ensures(result == 42) ])] fn constrained_contract_stays_pure(_x: &T) -> i32 { @@ -20,7 +20,7 @@ fn verify_constrained_contract_stays_pure(a: i32) {} #[trusted] #[ensures(result % 2 == 0)] -#[ghost_constraint(T: A, [ +#[refine_spec(where T: A [ ensures(result == 42) ])] fn constrained_contract_inherits_posts(_x: T) -> i32 { @@ -37,4 +37,4 @@ fn verify_constrained_contract_inherits_posts() { } fn main() { -} \ No newline at end of file +} diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/merge-where-clause.rs b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/merge-where-clause.rs index 8e39686c423..302629fd89e 100644 --- a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/merge-where-clause.rs +++ b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/merge-where-clause.rs @@ -22,7 +22,7 @@ impl B for i32 { // The specs under the constraint `T: B` are also aware of the fact that `T: A` (defined on the function) #[trusted] -#[ghost_constraint(T: B, [ +#[refine_spec(where T: B [ requires(x.a() == 42), ensures(result == x.b()) ])] diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/nested-generics.rs b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/nested-generics.rs index 6ceed16ac0b..328f3735a93 100644 --- a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/nested-generics.rs +++ b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/nested-generics.rs @@ -11,7 +11,7 @@ impl B for i32 {} impl B for i32 {} #[trusted] -#[ghost_constraint(T: A + B + B , [ +#[refine_spec(where T: A + B + B [ ensures(result > 0) ])] fn foo(_x: T) -> i32 { diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/normalize-associated-types.rs b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/normalize-associated-types.rs index 090fdac046f..0c2d8716294 100644 --- a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/normalize-associated-types.rs +++ b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/normalize-associated-types.rs @@ -12,9 +12,9 @@ trait A { trait B { type BType; - #[ghost_constraint(Self: A::BType> , [ - requires(self.foo(&arg)), - ensures(self.foo(&arg)) + #[refine_spec(where Self: A::BType> [ + requires(self.foo(&arg)), + ensures(self.foo(&arg)) ])] #[trusted] fn bar(&self, arg: Self::BType); @@ -41,4 +41,4 @@ impl B for S { fn main() { let s = S; s.bar(43); -} \ No newline at end of file +} diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/split-constraint.rs b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/split-constraint.rs index 0490013cf96..92eb7d5b461 100644 --- a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/split-constraint.rs +++ b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/split-constraint.rs @@ -7,10 +7,10 @@ trait A {} impl A for i32 {} #[trusted] -#[ghost_constraint(T: A, [ +#[refine_spec(where T: A [ ensures(result % 2 == 0) ])] -#[ghost_constraint(T: A, [ +#[refine_spec(where T: A [ ensures(result > 0) ])] fn foo(_x: T) -> i32 { diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/traits-1.rs b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/traits-1.rs index 995c10a3513..a34879dfc19 100644 --- a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/traits-1.rs +++ b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/traits-1.rs @@ -5,7 +5,7 @@ use prusti_contracts::*; trait A {} trait MyTrait { - #[ghost_constraint(Self: A, [ensures(result > 0)])] + #[refine_spec(where Self: A [ensures(result > 0)])] #[trusted] fn foo(&self) -> i32; } @@ -23,4 +23,4 @@ impl A for MyStruct {} fn main() { let s = MyStruct; assert!(s.foo() > 0); -} \ No newline at end of file +} From f30d1310626da094a68440a80602301e4b4e6ebc Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Wed, 7 Dec 2022 05:52:49 +0100 Subject: [PATCH 12/64] add failing test for extraneous comma before specs --- .../trait-bounds-invalid-macro-arguments-3.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-invalid-macro-arguments-3.rs diff --git a/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-invalid-macro-arguments-3.rs b/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-invalid-macro-arguments-3.rs new file mode 100644 index 00000000000..f78c738ff1b --- /dev/null +++ b/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-invalid-macro-arguments-3.rs @@ -0,0 +1,12 @@ +use prusti_contracts::*; + +#[refine_spec(where T: Copy, [ + ensures(result > 0) //~ ERROR: expected `,` +])] +//~| ERROR: expected a trait bound and specifications in brackets, e.g.: `ghost_constraint(T: A + B + ..., [requires(...), ...])` +fn foo(_x: T) -> i32 { + 42 +} + +fn main() { +} From 5a6ab38e37f9d63a40524f94d08a631d37bfe944 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Wed, 7 Dec 2022 05:59:48 +0100 Subject: [PATCH 13/64] update example in error note --- prusti-contracts/prusti-specs/src/specifications/preparser.rs | 2 +- .../ghost-constraints/trait-bounds-invalid-macro-arguments-1.rs | 2 +- .../ghost-constraints/trait-bounds-invalid-macro-arguments-2.rs | 2 +- .../ghost-constraints/trait-bounds-invalid-macro-arguments-3.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/prusti-contracts/prusti-specs/src/specifications/preparser.rs b/prusti-contracts/prusti-specs/src/specifications/preparser.rs index 48cd21acafe..dc3647a8dd9 100644 --- a/prusti-contracts/prusti-specs/src/specifications/preparser.rs +++ b/prusti-contracts/prusti-specs/src/specifications/preparser.rs @@ -587,7 +587,7 @@ fn validate_trait_bounds(trait_bounds: &syn::PredicateType) -> syn::Result<()> { } fn with_ghost_constraint_example(mut err: syn::Error) -> syn::Error { - err.combine(error(err.span(), "expected a trait bound and specifications in brackets, e.g.: `ghost_constraint(T: A + B + ..., [requires(...), ...])`")); + err.combine(error(err.span(), "expected where constraint and specifications in brackets, e.g.: `refine_spec(where T: A + B, U: C [requires(...), ...])`")); err } diff --git a/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-invalid-macro-arguments-1.rs b/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-invalid-macro-arguments-1.rs index f69ed774cd6..c4a504de0c2 100644 --- a/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-invalid-macro-arguments-1.rs +++ b/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-invalid-macro-arguments-1.rs @@ -3,7 +3,7 @@ use prusti_contracts::*; #[refine_spec([ //~ ERROR: expected `where` ensures(result > 0) ])] -//~| ERROR: expected a trait bound and specifications in brackets, e.g.: `ghost_constraint(T: A + B + ..., [requires(...), ...])` +//~| ERROR: expected where constraint and specifications in brackets, e.g.: `refine_spec(where T: A + B, U: C [requires(...), ...])` fn foo(_x: T) -> i32 { 42 } diff --git a/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-invalid-macro-arguments-2.rs b/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-invalid-macro-arguments-2.rs index 038f5dc5f96..2098507ff56 100644 --- a/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-invalid-macro-arguments-2.rs +++ b/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-invalid-macro-arguments-2.rs @@ -3,7 +3,7 @@ use prusti_contracts::*; #[refine_spec(where 42 [ //~ ERROR: expected one of: `for`, parentheses, `fn`, `unsafe`, `extern`, identifier, `::`, `<`, square brackets, `*`, `&`, `!`, `impl`, `_`, lifetime ensures(result > 0) ])] -//~| ERROR: expected a trait bound and specifications in brackets, e.g.: `ghost_constraint(T: A + B + ..., [requires(...), ...])` +//~| ERROR: expected where constraint and specifications in brackets, e.g.: `refine_spec(where T: A + B, U: C [requires(...), ...])` fn foo(_x: T) -> i32 { 42 } diff --git a/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-invalid-macro-arguments-3.rs b/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-invalid-macro-arguments-3.rs index f78c738ff1b..f8b074a57d5 100644 --- a/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-invalid-macro-arguments-3.rs +++ b/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-invalid-macro-arguments-3.rs @@ -3,7 +3,7 @@ use prusti_contracts::*; #[refine_spec(where T: Copy, [ ensures(result > 0) //~ ERROR: expected `,` ])] -//~| ERROR: expected a trait bound and specifications in brackets, e.g.: `ghost_constraint(T: A + B + ..., [requires(...), ...])` +//~| ERROR: expected where constraint and specifications in brackets, e.g.: `refine_spec(where T: A + B, U: C [requires(...), ...])` fn foo(_x: T) -> i32 { 42 } From 6c30fef25453cbc044d82f443a96c93ac971cc7f Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Wed, 7 Dec 2022 06:30:49 +0100 Subject: [PATCH 14/64] remove ghost constraint feature flag you can still introduce unsound behavior with them, but they're far from the only way to do so, and absolutely necessary for prusti std --- docs/dev-guide/src/config/flags.md | 10 ---------- prusti-interface/src/specs/mod.rs | 9 --------- .../tests/verify/fail/ghost-constraints/purity.rs | 2 -- .../tests/verify/fail/ghost-constraints/traits-1.rs | 2 -- .../pass/ghost-constraints/extern-spec/traits-1.rs | 2 -- .../tests/verify/pass/ghost-constraints/purity.rs | 2 -- .../ghost-constraints/invalid-trait-refinement-1.rs | 2 -- .../ghost-constraints/invalid-trait-refinement-2.rs | 2 -- .../fail/ghost-constraints/associated-types-1.rs | 1 - .../fail/ghost-constraints/associated-types-2.rs | 1 - .../fail/ghost-constraints/associated-types-3.rs | 1 - .../fail/ghost-constraints/associated-types-4.rs | 1 - .../fail/ghost-constraints/associated-types-5.rs | 1 - .../fail/ghost-constraints/associated-types-6.rs | 1 - .../fail/ghost-constraints/associated-types-7.rs | 1 - .../fail/ghost-constraints/different-bounds.rs | 2 -- .../in-local-refinement-disallowed.rs | 2 -- .../ghost-constraints/in-non-trusted-function.rs | 2 -- .../fail/ghost-constraints/nested-generics.rs | 2 -- .../pass/ghost-constraints/associated-types-1.rs | 1 - .../pass/ghost-constraints/associated-types-2.rs | 1 - .../pass/ghost-constraints/associated-types-3.rs | 1 - .../pass/ghost-constraints/associated-types-4.rs | 1 - .../pass/ghost-constraints/associated-types-5.rs | 1 - .../ghost-constraints-extend-base-attributes.rs | 1 - .../pass/ghost-constraints/merge-where-clause.rs | 2 -- .../pass/ghost-constraints/nested-generics.rs | 2 -- .../ghost-constraints/normalize-associated-types.rs | 2 -- .../pass/ghost-constraints/split-constraint.rs | 2 -- .../pass/ghost-constraints/traits-1.rs | 2 -- prusti-utils/src/config.rs | 13 ------------- .../src/encoder/mir/specifications/constraints.rs | 5 ----- 32 files changed, 80 deletions(-) diff --git a/docs/dev-guide/src/config/flags.md b/docs/dev-guide/src/config/flags.md index 5db4e14b230..0d18b0612e6 100644 --- a/docs/dev-guide/src/config/flags.md +++ b/docs/dev-guide/src/config/flags.md @@ -23,7 +23,6 @@ | [`DUMP_REBORROWING_DAG_IN_DEBUG_INFO`](#dump_reborrowing_dag_in_debug_info) | `bool` | `false` | A | | [`DUMP_VIPER_PROGRAM`](#dump_viper_program) | `bool` | `false` | A | | [`ENABLE_CACHE`](#enable_cache) | `bool` | `true` | A | -| [`ENABLE_GHOST_CONSTRAINTS`](#enable_ghost_constraints) | `bool` | `false` | A | | [`ENABLE_PURIFICATION_OPTIMIZATION`](#enable_purification_optimization) | `bool` | `false` | A | | [`ENABLE_TYPE_INVARIANTS`](#enable_type_invariants) | `bool` | `false` | A | | [`ENABLE_VERIFY_ONLY_BASIC_BLOCK_PATH`](#enable_verify_only_basic_block_path) | `bool` | `false` | A | @@ -179,15 +178,6 @@ When enabled, the encoded Viper program will be output. When enabled, verification requests (to verify individual `fn`s) are cached to improve future verification. By default the cache is only saved in memory (of the `prusti-server` if enabled). For long-running verification projects use [`CACHE_PATH`](#cache_path) to save to disk. -## `ENABLE_GHOST_CONSTRAINTS` - -When enabled, ghost constraints can be used in Prusti specifications. - -Ghost constraints allow for specifications which are only active if a certain "constraint" (i.e. a trait bound -on a generic type parameter) is satisfied. - -**This is an experimental feature**, because it is currently possible to introduce unsound verification behavior. - ## `ENABLE_PURIFICATION_OPTIMIZATION` When enabled, impure methods are optimized using the purification optimization, which tries to convert heap operations to pure (snapshot-based) operations. diff --git a/prusti-interface/src/specs/mod.rs b/prusti-interface/src/specs/mod.rs index 428351214d3..ff05681ffd1 100644 --- a/prusti-interface/src/specs/mod.rs +++ b/prusti-interface/src/specs/mod.rs @@ -167,15 +167,6 @@ impl<'a, 'tcx> SpecCollector<'a, 'tcx> { } if !spec.specs_with_constraints.is_empty() - && !prusti_common::config::enable_ghost_constraints() - { - let span = self.env.query.get_def_span(*local_id); - PrustiError::unsupported( - "Ghost constraints need to be enabled with the feature flag `enable_ghost_constraints`", - MultiSpan::from(span), - ) - .emit(&self.env.diagnostic); - } else if !spec.specs_with_constraints.is_empty() && !*spec.base_spec.trusted.expect_inherent() { let span = self.env.query.get_def_span(*local_id); diff --git a/prusti-tests/tests/verify/fail/ghost-constraints/purity.rs b/prusti-tests/tests/verify/fail/ghost-constraints/purity.rs index e0bcbda6a2e..a8e36e403de 100644 --- a/prusti-tests/tests/verify/fail/ghost-constraints/purity.rs +++ b/prusti-tests/tests/verify/fail/ghost-constraints/purity.rs @@ -1,5 +1,3 @@ -// compile-flags: -Penable_ghost_constraints=true - use prusti_contracts::*; #[refine_spec(where T: Copy [pure])] diff --git a/prusti-tests/tests/verify/fail/ghost-constraints/traits-1.rs b/prusti-tests/tests/verify/fail/ghost-constraints/traits-1.rs index 50bc5dc41b9..0a6fba3fc03 100644 --- a/prusti-tests/tests/verify/fail/ghost-constraints/traits-1.rs +++ b/prusti-tests/tests/verify/fail/ghost-constraints/traits-1.rs @@ -1,5 +1,3 @@ -// compile-flags: -Penable_ghost_constraints=true - use prusti_contracts::*; trait A {} diff --git a/prusti-tests/tests/verify/pass/ghost-constraints/extern-spec/traits-1.rs b/prusti-tests/tests/verify/pass/ghost-constraints/extern-spec/traits-1.rs index d2dec593bad..1cf9994e9ee 100644 --- a/prusti-tests/tests/verify/pass/ghost-constraints/extern-spec/traits-1.rs +++ b/prusti-tests/tests/verify/pass/ghost-constraints/extern-spec/traits-1.rs @@ -1,5 +1,3 @@ -// compile-flags: -Penable_ghost_constraints=true - use prusti_contracts::*; trait HasContract { diff --git a/prusti-tests/tests/verify/pass/ghost-constraints/purity.rs b/prusti-tests/tests/verify/pass/ghost-constraints/purity.rs index dc58f371366..d0e9fe686fd 100644 --- a/prusti-tests/tests/verify/pass/ghost-constraints/purity.rs +++ b/prusti-tests/tests/verify/pass/ghost-constraints/purity.rs @@ -1,5 +1,3 @@ -// compile-flags: -Penable_ghost_constraints=true - use prusti_contracts::*; #[refine_spec(where T: Copy [pure])] diff --git a/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-1.rs b/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-1.rs index 19977f9fe6f..4a6674b95ff 100644 --- a/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-1.rs +++ b/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-1.rs @@ -1,5 +1,3 @@ -// compile-flags: -Penable_ghost_constraints=true - use prusti_contracts::*; trait HasContract { diff --git a/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-2.rs b/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-2.rs index e7fa3743cb9..700ed2c09fa 100644 --- a/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-2.rs +++ b/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-2.rs @@ -1,5 +1,3 @@ -// compile-flags: -Penable_ghost_constraints=true - use prusti_contracts::*; trait HasContract { diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-1.rs b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-1.rs index 9d8e9f4d33a..0739b7ab581 100644 --- a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-1.rs +++ b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-1.rs @@ -1,4 +1,3 @@ -// compile-flags: -Penable_ghost_constraints=true use prusti_contracts::*; trait A { diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-2.rs b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-2.rs index 4985e63a3a8..812bbd69ed3 100644 --- a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-2.rs +++ b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-2.rs @@ -1,4 +1,3 @@ -// compile-flags: -Penable_ghost_constraints=true use prusti_contracts::*; trait A { diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-3.rs b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-3.rs index 9115ed4100e..2dd3ed105b5 100644 --- a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-3.rs +++ b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-3.rs @@ -1,4 +1,3 @@ -// compile-flags: -Penable_ghost_constraints=true use prusti_contracts::*; trait A { diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-4.rs b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-4.rs index a7f9e625e95..6ca83d1ef12 100644 --- a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-4.rs +++ b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-4.rs @@ -1,4 +1,3 @@ -// compile-flags: -Penable_ghost_constraints=true use prusti_contracts::*; trait A { diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-5.rs b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-5.rs index 0c6453e596e..eb9f03bf019 100644 --- a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-5.rs +++ b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-5.rs @@ -1,4 +1,3 @@ -// compile-flags: -Penable_ghost_constraints=true use prusti_contracts::*; trait A { diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-6.rs b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-6.rs index a8db91432df..7558b69a007 100644 --- a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-6.rs +++ b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-6.rs @@ -1,4 +1,3 @@ -// compile-flags: -Penable_ghost_constraints=true use prusti_contracts::*; trait A { diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-7.rs b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-7.rs index ff4b87ed76e..52c3d142e56 100644 --- a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-7.rs +++ b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-7.rs @@ -1,4 +1,3 @@ -// compile-flags: -Penable_ghost_constraints=true use prusti_contracts::*; trait A { diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/different-bounds.rs b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/different-bounds.rs index 49407944cb7..46c3a92d973 100644 --- a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/different-bounds.rs +++ b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/different-bounds.rs @@ -1,5 +1,3 @@ -// compile-flags: -Penable_ghost_constraints=true - // Note: For now, it is completely fine to _declare_ two ghost constraints with different bounds // since resolving happens for specific callsites. That is, without the call in main, this // file verifies. diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-local-refinement-disallowed.rs b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-local-refinement-disallowed.rs index 9e686a548e8..b4f2c902930 100644 --- a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-local-refinement-disallowed.rs +++ b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-local-refinement-disallowed.rs @@ -1,5 +1,3 @@ -// compile-flags: -Penable_ghost_constraints=true - use prusti_contracts::*; trait A {} diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-non-trusted-function.rs b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-non-trusted-function.rs index 9759106e7c5..3a3aa5b546f 100644 --- a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-non-trusted-function.rs +++ b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-non-trusted-function.rs @@ -1,5 +1,3 @@ -// compile-flags: -Penable_ghost_constraints=true - use prusti_contracts::*; trait A {} diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/nested-generics.rs b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/nested-generics.rs index d5bba3474ca..b2977e70630 100644 --- a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/nested-generics.rs +++ b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/nested-generics.rs @@ -1,5 +1,3 @@ -// compile-flags: -Penable_ghost_constraints=true - use prusti_contracts::*; trait A {} diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-1.rs b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-1.rs index b0269fe8f23..e63f3b35f31 100644 --- a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-1.rs +++ b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-1.rs @@ -1,4 +1,3 @@ -// compile-flags: -Penable_ghost_constraints=true use prusti_contracts::*; trait A { diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-2.rs b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-2.rs index 15913ec564b..cce3c1ebeed 100644 --- a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-2.rs +++ b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-2.rs @@ -1,4 +1,3 @@ -// compile-flags: -Penable_ghost_constraints=true use prusti_contracts::*; trait A { diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-3.rs b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-3.rs index 232d8f00bea..195c80505d1 100644 --- a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-3.rs +++ b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-3.rs @@ -1,4 +1,3 @@ -// compile-flags: -Penable_ghost_constraints=true use prusti_contracts::*; trait A { diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-4.rs b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-4.rs index 8e4f7fd32d9..d299e42fea3 100644 --- a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-4.rs +++ b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-4.rs @@ -1,4 +1,3 @@ -// compile-flags: -Penable_ghost_constraints=true use prusti_contracts::*; trait A { diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-5.rs b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-5.rs index b52d74a4d98..af53f69a7fd 100644 --- a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-5.rs +++ b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-5.rs @@ -1,4 +1,3 @@ -// compile-flags: -Penable_ghost_constraints=true use prusti_contracts::*; trait A { diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/ghost-constraints-extend-base-attributes.rs b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/ghost-constraints-extend-base-attributes.rs index 0a3f2cd9d6b..458ab379542 100644 --- a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/ghost-constraints-extend-base-attributes.rs +++ b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/ghost-constraints-extend-base-attributes.rs @@ -1,4 +1,3 @@ -// compile-flags: -Penable_ghost_constraints=true // This test demonstrates that ghost constraints inherit the specs from the function. use prusti_contracts::*; diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/merge-where-clause.rs b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/merge-where-clause.rs index 302629fd89e..df248d6b5dc 100644 --- a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/merge-where-clause.rs +++ b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/merge-where-clause.rs @@ -1,5 +1,3 @@ -// compile-flags: -Penable_ghost_constraints=true - use prusti_contracts::*; trait A { diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/nested-generics.rs b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/nested-generics.rs index 328f3735a93..ee0e3f9509c 100644 --- a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/nested-generics.rs +++ b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/nested-generics.rs @@ -1,5 +1,3 @@ -// compile-flags: -Penable_ghost_constraints=true - use prusti_contracts::*; trait A {} diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/normalize-associated-types.rs b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/normalize-associated-types.rs index 0c2d8716294..8c2f5b0f6aa 100644 --- a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/normalize-associated-types.rs +++ b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/normalize-associated-types.rs @@ -1,5 +1,3 @@ -// compile-flags: -Penable_ghost_constraints=true - use prusti_contracts::*; trait A { diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/split-constraint.rs b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/split-constraint.rs index 92eb7d5b461..202988e0e1f 100644 --- a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/split-constraint.rs +++ b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/split-constraint.rs @@ -1,5 +1,3 @@ -// compile-flags: -Penable_ghost_constraints=true - use prusti_contracts::*; trait A {} diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/traits-1.rs b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/traits-1.rs index a34879dfc19..7ab5e9b4b0f 100644 --- a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/traits-1.rs +++ b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/traits-1.rs @@ -1,5 +1,3 @@ -// compile-flags: -Penable_ghost_constraints=true - use prusti_contracts::*; trait A {} diff --git a/prusti-utils/src/config.rs b/prusti-utils/src/config.rs index 00c4b046b33..7951192173d 100644 --- a/prusti-utils/src/config.rs +++ b/prusti-utils/src/config.rs @@ -138,7 +138,6 @@ lazy_static::lazy_static! { settings.set_default::>("dump_fold_unfold_state_of_blocks", None).unwrap(); settings.set_default("print_hash", false).unwrap(); settings.set_default("enable_cache", true).unwrap(); - settings.set_default("enable_ghost_constraints", false).unwrap(); settings.set_default("cargo_path", "cargo").unwrap(); settings.set_default("cargo_command", "check").unwrap(); @@ -995,18 +994,6 @@ pub fn intern_names() -> bool { read_setting("intern_names") } -/// When enabled, ghost constraints can be used in Prusti specifications. -/// -/// Ghost constraints allow for specifications which are only active if a -/// certain "constraint" (i.e. a trait bound on a generic type parameter) is -/// satisfied. -/// -/// **This is an experimental feature**, because it is currently possible to -/// introduce unsound verification behavior. -pub fn enable_ghost_constraints() -> bool { - read_setting("enable_ghost_constraints") -} - /// Determines which cargo `cargo-prusti` should run (e.g. if "cargo" isn't in /// the path can point to it directly). Not relevant when only running as `prusti=rustc`. pub fn cargo_path() -> String { diff --git a/prusti-viper/src/encoder/mir/specifications/constraints.rs b/prusti-viper/src/encoder/mir/specifications/constraints.rs index 1aa69277b03..10c51ec04f7 100644 --- a/prusti-viper/src/encoder/mir/specifications/constraints.rs +++ b/prusti-viper/src/encoder/mir/specifications/constraints.rs @@ -47,11 +47,6 @@ impl<'spec, 'env: 'spec, 'tcx: 'env> ConstraintResolver<'spec, 'env, 'tcx> ) -> Result<&'spec ProcedureSpecification, PrustiError> { debug!("Resolving spec constraints for {query:?}"); - if !prusti_common::config::enable_ghost_constraints() { - trace!("Ghost constraints are disabled, using base spec"); - return Ok(&self.base_spec); - } - if self.specs_with_constraints.is_empty() { trace!("Spec has no constraints, using base spec"); return Ok(&self.base_spec); From 4a5dc333595d3ab80944ff1d2cf2438c5c46be5c Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Wed, 7 Dec 2022 06:37:19 +0100 Subject: [PATCH 15/64] rename ghost constraints to conditional spec refinements in user-facing strings & comments --- .../prusti-specs/src/ghost_constraints/mod.rs | 2 +- prusti-contracts/prusti-specs/src/lib.rs | 4 ++-- .../prusti-specs/src/specifications/preparser.rs | 6 +++--- prusti-interface/src/specs/mod.rs | 2 +- prusti-interface/src/specs/typed.rs | 6 +++--- .../fail/ghost-constraints/trait-bounds-illegal-1.rs | 2 +- .../fail/ghost-constraints/trait-bounds-illegal-2.rs | 2 +- .../ghost-constraints/invalid-trait-refinement-1.stderr | 8 ++++---- .../ghost-constraints/invalid-trait-refinement-2.stderr | 8 ++++---- .../fail/ghost-constraints/different-bounds.rs | 4 ++-- .../ghost-constraints/in-local-refinement-disallowed.rs | 2 +- .../fail/ghost-constraints/in-non-trusted-function.rs | 2 +- .../pass/ghost-constraints/associated-types-2.rs | 2 +- .../ghost-constraints-extend-base-attributes.rs | 2 +- .../src/encoder/mir/specifications/constraints.rs | 6 +++--- prusti-viper/src/encoder/mir/specifications/specs.rs | 4 ++-- 16 files changed, 31 insertions(+), 31 deletions(-) diff --git a/prusti-contracts/prusti-specs/src/ghost_constraints/mod.rs b/prusti-contracts/prusti-specs/src/ghost_constraints/mod.rs index 7ee32d47693..d3280fa6cfe 100644 --- a/prusti-contracts/prusti-specs/src/ghost_constraints/mod.rs +++ b/prusti-contracts/prusti-specs/src/ghost_constraints/mod.rs @@ -8,7 +8,7 @@ use syn::{parse_quote_spanned, spanned::Spanned}; pub fn generate(attr: TokenStream, item: &untyped::AnyFnItem) -> GeneratedResult { let tokens_span = attr.span(); - // Parse ghost constraint information + // Parse conditional spec refinements information let ghost_constraint = parse_ghost_constraint(attr)?; let mut new_items = vec![]; diff --git a/prusti-contracts/prusti-specs/src/lib.rs b/prusti-contracts/prusti-specs/src/lib.rs index 9119876ee1f..4d45b5726ae 100644 --- a/prusti-contracts/prusti-specs/src/lib.rs +++ b/prusti-contracts/prusti-specs/src/lib.rs @@ -288,7 +288,7 @@ fn generate_for_pure(attr: TokenStream, item: &untyped::AnyFnItem) -> GeneratedR )) } -/// Generate spec items and attributes to typecheck and later retrieve "pure" annotations, but encoded as a referenced separate function that ghost constraints can apply trait bounds to. +/// Generate spec items and attributes to typecheck and later retrieve "pure" annotations, but encoded as a referenced separate function that conditional spec refinements can apply trait bounds to. fn generate_for_pure_ghost_constraint(item: &untyped::AnyFnItem) -> GeneratedResult { let mut rewriter = rewriter::AstRewriter::new(); let spec_id = rewriter.generate_spec_id(); @@ -540,7 +540,7 @@ pub fn refine_trait_spec(_attr: TokenStream, tokens: TokenStream) -> TokenStream if let Some(span) = illegal_attribute_span { let err = Err(syn::Error::new( span, - "Ghost constraints in trait spec refinements not supported", + "Conditional spec refinements in trait spec refinements not supported", )); handle_result!(err); } diff --git a/prusti-contracts/prusti-specs/src/specifications/preparser.rs b/prusti-contracts/prusti-specs/src/specifications/preparser.rs index dc3647a8dd9..0ea742906b7 100644 --- a/prusti-contracts/prusti-specs/src/specifications/preparser.rs +++ b/prusti-contracts/prusti-specs/src/specifications/preparser.rs @@ -554,7 +554,7 @@ fn validate_predicate(predicate: syn::WherePredicate) -> syn::Result err( eq_bound.span(), - "equality constraints are not allowed in ghost constraints", + "equality constraints are not allowed in conditional spec refinements", ), } } @@ -562,7 +562,7 @@ fn validate_predicate(predicate: syn::WherePredicate) -> syn::Result(span: Span) -> syn::Result { err( span, - "lifetimes are not allowed in ghost constraint trait bounds", + "lifetimes are not allowed in conditional spec refinement trait bounds", ) } @@ -591,7 +591,7 @@ fn with_ghost_constraint_example(mut err: syn::Error) -> syn::Error { err } -/// A specification enclosed in another specification (e.g. in spec entailments or ghost constraints) +/// A specification enclosed in another specification (e.g. in spec entailments or conditional spec refinements) #[derive(Debug)] pub enum NestedSpec { Requires(T), diff --git a/prusti-interface/src/specs/mod.rs b/prusti-interface/src/specs/mod.rs index ff05681ffd1..da9a1e64029 100644 --- a/prusti-interface/src/specs/mod.rs +++ b/prusti-interface/src/specs/mod.rs @@ -171,7 +171,7 @@ impl<'a, 'tcx> SpecCollector<'a, 'tcx> { { let span = self.env.query.get_def_span(*local_id); PrustiError::unsupported( - "Ghost constraints can only be used on trusted functions", + "Conditional spec refinements can only be applied to trusted functions", MultiSpan::from(span), ) .emit(&self.env.diagnostic); diff --git a/prusti-interface/src/specs/typed.rs b/prusti-interface/src/specs/typed.rs index 1cb687f48c5..af061e7ea95 100644 --- a/prusti-interface/src/specs/typed.rs +++ b/prusti-interface/src/specs/typed.rs @@ -203,7 +203,7 @@ pub struct ProcedureSpecification { pub pledges: SpecificationItem>, pub trusted: SpecificationItem, pub terminates: SpecificationItem>, - pub purity: SpecificationItem>, // for ghost constraints + pub purity: SpecificationItem>, // for conditional spec refinements } impl ProcedureSpecification { @@ -440,7 +440,7 @@ impl SpecGraph { pub fn add_purity<'tcx>(&mut self, purity: LocalDefId, env: &Environment<'tcx>) { match self.get_constraint(purity, env) { - None => unreachable!("separate purity defs are only used for ghost constraints"), + None => unreachable!("separate purity defs are only used for conditional spec refinements"), Some(constraint) => { let constrained_spec = self.get_constrained_spec_mut(constraint); constrained_spec.kind = @@ -767,7 +767,7 @@ impl Refinable for ProcedureSpecification { kind: self.kind.refine(&other.kind), trusted: self.trusted.refine(&other.trusted), terminates: self.terminates.refine(&other.terminates), - purity: self.purity.refine(&other.purity), // ASK: include purity in refinement? only used for ghost constraints so doesn't really apply + purity: self.purity.refine(&other.purity) } } } diff --git a/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-1.rs b/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-1.rs index f5544d6578d..aa7a666a9c4 100644 --- a/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-1.rs +++ b/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-1.rs @@ -2,7 +2,7 @@ use prusti_contracts::*; trait A { } -#[refine_spec(where T: 'static + A [ //~ ERROR: lifetimes are not allowed in ghost constraint trait bounds +#[refine_spec(where T: 'static + A [ //~ ERROR: lifetimes are not allowed in conditional spec refinement trait bounds ensures(result > 0) ])] fn foo(_x: T) -> i32 { diff --git a/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-2.rs b/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-2.rs index c8955923caa..299cae00f3c 100644 --- a/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-2.rs +++ b/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-2.rs @@ -2,7 +2,7 @@ use prusti_contracts::*; trait A { } -#[refine_spec(where T: for<'a> A<&'a i32> [ //~ ERROR: lifetimes are not allowed in ghost constraint trait bounds +#[refine_spec(where T: for<'a> A<&'a i32> [ //~ ERROR: lifetimes are not allowed in conditional spec refinement trait bounds ensures(result > 0) ])] fn foo(_x: T) -> i32 { diff --git a/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-1.stderr b/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-1.stderr index 674a5476d94..b38e9f5088f 100644 --- a/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-1.stderr +++ b/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-1.stderr @@ -1,12 +1,12 @@ error: [Prusti: verification error] the method's precondition may not be a valid weakening of the trait's precondition. - --> $DIR/invalid-trait-refinement-1.rs:18:31 + --> $DIR/invalid-trait-refinement-1.rs:16:31 | -18 | #[refine_spec(where Self: HasContract [ +16 | #[refine_spec(where Self: HasContract [ | _______________________________^ -19 | | requires(self.pre()), ensures(self.post()) +17 | | requires(self.pre()), ensures(self.post()) | |___________________________^ ... -30 | #[requires(self.x >= 15)] +28 | #[requires(self.x >= 15)] | ^^^^^^^^^^^^ | = help: The trait's precondition should imply the implemented method's precondition. diff --git a/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-2.stderr b/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-2.stderr index 06e52fcb738..bb5de7d704e 100644 --- a/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-2.stderr +++ b/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-2.stderr @@ -1,12 +1,12 @@ error: [Prusti: verification error] the method's postcondition may not be a valid strengthening of the trait's postcondition. - --> $DIR/invalid-trait-refinement-2.rs:18:31 + --> $DIR/invalid-trait-refinement-2.rs:16:31 | -18 | #[refine_spec(where Self: HasContract [ +16 | #[refine_spec(where Self: HasContract [ | _______________________________^ -19 | | requires(self.pre()), ensures(self.post()) +17 | | requires(self.pre()), ensures(self.post()) | |_________________________________________________^ ... -30 | #[ensures(self.x >= 15)] +28 | #[ensures(self.x >= 15)] | ^^^^^^^^^^^^ | = help: The implemented method's postcondition should imply the trait's postcondition. diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/different-bounds.rs b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/different-bounds.rs index 46c3a92d973..a98a97e4fcc 100644 --- a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/different-bounds.rs +++ b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/different-bounds.rs @@ -1,4 +1,4 @@ -// Note: For now, it is completely fine to _declare_ two ghost constraints with different bounds +// Note: For now, it is completely fine to _declare_ two conditional spec refinements with different bounds // since resolving happens for specific callsites. That is, without the call in main, this // file verifies. use prusti_contracts::*; @@ -7,7 +7,7 @@ trait A {} trait B {} #[trusted] -#[refine_spec(where T: A [ //~ ERROR: [Prusti: unsupported feature] Multiple ghost constraints with different bounds defined +#[refine_spec(where T: A [ //~ ERROR: [Prusti: unsupported feature] Multiple conditional spec refinements with different bounds defined requires(true), ensures(true), ])] diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-local-refinement-disallowed.rs b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-local-refinement-disallowed.rs index b4f2c902930..adf715af455 100644 --- a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-local-refinement-disallowed.rs +++ b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-local-refinement-disallowed.rs @@ -15,7 +15,7 @@ struct MyStruct; impl MyTrait for MyStruct { #[ensures(result > 10)] - #[refine_spec(where Self: A [ //~ ERROR: Ghost constraints in trait spec refinements not supported + #[refine_spec(where Self: A [ //~ ERROR: Conditional spec refinements in trait spec refinements not supported ensures(result % 6 == 0) ])] fn foo(&self) -> i32 { diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-non-trusted-function.rs b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-non-trusted-function.rs index 3a3aa5b546f..abb1937813c 100644 --- a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-non-trusted-function.rs +++ b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-non-trusted-function.rs @@ -5,7 +5,7 @@ trait A {} #[refine_spec(where T: A [ ensures(true) ])] -fn foo() {} //~ ERROR: Ghost constraints can only be used on trusted functions +fn foo() {} //~ ERROR: Conditional spec refinements can only be applied to trusted functions fn main() { } diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-2.rs b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-2.rs index cce3c1ebeed..c625d433230 100644 --- a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-2.rs +++ b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-2.rs @@ -32,5 +32,5 @@ trait SomeTrait { fn main() { let f = Foo; let res = f.foo(); - assert!(res > 0); // Ghost constraint satisfied! + assert!(res > 0); // Conditional spec refinement satisfied! } diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/ghost-constraints-extend-base-attributes.rs b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/ghost-constraints-extend-base-attributes.rs index 458ab379542..67b912eea4a 100644 --- a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/ghost-constraints-extend-base-attributes.rs +++ b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/ghost-constraints-extend-base-attributes.rs @@ -1,4 +1,4 @@ -// This test demonstrates that ghost constraints inherit the specs from the function. +// This test demonstrates that conditional spec refinements inherit the specs from the function. use prusti_contracts::*; diff --git a/prusti-viper/src/encoder/mir/specifications/constraints.rs b/prusti-viper/src/encoder/mir/specifications/constraints.rs index 10c51ec04f7..0ff33246015 100644 --- a/prusti-viper/src/encoder/mir/specifications/constraints.rs +++ b/prusti-viper/src/encoder/mir/specifications/constraints.rs @@ -67,7 +67,7 @@ impl<'spec, 'env: 'spec, 'tcx: 'env> ConstraintResolver<'spec, 'env, 'tcx> substs: call_substs, }, // Obligations are resolved for function definition encodings to account - // for ghost constraints on traits (behavioral subtyping rules will be checked + // for conditional spec refinements on traits (behavioral subtyping rules will be checked // against the resolved spec). SpecQuery::FunctionDefEncoding(proc_def_id, substs) | SpecQuery::GetProcKind(proc_def_id, substs) => ConstraintSolvingContext { @@ -159,7 +159,7 @@ mod trait_bounds { .iter() .all(|predicate| { // Normalize any associated type projections. - // This needs to be done because ghost constraints might contain "deeply nested" + // This needs to be done because conditional spec refinements might contain "deeply nested" // associated types, e.g. `T: A::OtherAssocType` // where `::OtherAssocType` can be normalized to some concrete type. let normalized_predicate = @@ -249,7 +249,7 @@ mod trait_bounds { if param_envs.len() > 1 { let spans = param_envs.values().flatten().cloned().collect(); PrustiError::unsupported( - "Multiple ghost constraints with different bounds defined", + "Multiple conditional spec refinements with different bounds defined", MultiSpan::from_spans(spans), ) .add_note("This is currently not supported.", None) diff --git a/prusti-viper/src/encoder/mir/specifications/specs.rs b/prusti-viper/src/encoder/mir/specifications/specs.rs index acc47eafd9a..002060751d4 100644 --- a/prusti-viper/src/encoder/mir/specifications/specs.rs +++ b/prusti-viper/src/encoder/mir/specifications/specs.rs @@ -57,8 +57,8 @@ pub(super) struct Specifications<'tcx> { user_typed_specs: DefSpecificationMap, /// A refinement can be different based on the query. - /// The query can resolve to different [ProcedureSpecification]s due to ghost constraints. - /// Since Prusti does currently not support refinements of ghost constraints, we + /// The query can resolve to different [ProcedureSpecification]s due to conditional spec refinements. + /// Since Prusti does currently not support refinements of conditional spec refinements, we /// store different refined versions for different queries. refined_specs: FxHashMap, ProcedureSpecification>, } From eae12e0d435b8ffc3ac5a68e032de7b680f26fa0 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Wed, 7 Dec 2022 18:43:30 +0100 Subject: [PATCH 16/64] formatting --- .../prusti-specs/src/extern_spec_rewriter/impls.rs | 2 +- .../prusti-specs/src/extern_spec_rewriter/mods.rs | 2 +- .../prusti-specs/src/specifications/preparser.rs | 4 +--- prusti-interface/src/specs/mod.rs | 3 +-- prusti-interface/src/specs/typed.rs | 6 ++++-- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs index 10d56cedf68..9f412b7c8af 100644 --- a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs +++ b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs @@ -153,7 +153,7 @@ fn rewrite_trait_impl( } syn::ImplItem::Method(method) => { check_is_stub(&method.block)?; - + let (rewritten_method, spec_items) = generate_extern_spec_method_stub( &method, &item_ty, diff --git a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/mods.rs b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/mods.rs index 4e30a6acc20..7e84dbe9187 100644 --- a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/mods.rs +++ b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/mods.rs @@ -5,7 +5,7 @@ //! Modules are rewritten so that their name does not clash with the module //! they are specifying. -use super::common::{generate_extern_spec_function_stub, check_is_stub}; +use super::common::{check_is_stub, generate_extern_spec_function_stub}; use crate::{specifications::common::generate_mod_name, ExternSpecKind}; use proc_macro2::{Group, TokenStream, TokenTree}; use quote::{quote, ToTokens}; diff --git a/prusti-contracts/prusti-specs/src/specifications/preparser.rs b/prusti-contracts/prusti-specs/src/specifications/preparser.rs index 0ea742906b7..63238c06c9e 100644 --- a/prusti-contracts/prusti-specs/src/specifications/preparser.rs +++ b/prusti-contracts/prusti-specs/src/specifications/preparser.rs @@ -549,9 +549,7 @@ fn validate_predicate(predicate: syn::WherePredicate) -> syn::Result { - disallowed_lifetime_error(lifetime_bound.span()) - } + Lifetime(lifetime_bound) => disallowed_lifetime_error(lifetime_bound.span()), Eq(eq_bound) => err( eq_bound.span(), "equality constraints are not allowed in conditional spec refinements", diff --git a/prusti-interface/src/specs/mod.rs b/prusti-interface/src/specs/mod.rs index da9a1e64029..2b9ee0dbcf6 100644 --- a/prusti-interface/src/specs/mod.rs +++ b/prusti-interface/src/specs/mod.rs @@ -166,8 +166,7 @@ impl<'a, 'tcx> SpecCollector<'a, 'tcx> { spec.set_kind(kind); } - if !spec.specs_with_constraints.is_empty() - && !*spec.base_spec.trusted.expect_inherent() + if !spec.specs_with_constraints.is_empty() && !*spec.base_spec.trusted.expect_inherent() { let span = self.env.query.get_def_span(*local_id); PrustiError::unsupported( diff --git a/prusti-interface/src/specs/typed.rs b/prusti-interface/src/specs/typed.rs index af061e7ea95..77dcb76c1ca 100644 --- a/prusti-interface/src/specs/typed.rs +++ b/prusti-interface/src/specs/typed.rs @@ -440,7 +440,9 @@ impl SpecGraph { pub fn add_purity<'tcx>(&mut self, purity: LocalDefId, env: &Environment<'tcx>) { match self.get_constraint(purity, env) { - None => unreachable!("separate purity defs are only used for conditional spec refinements"), + None => { + unreachable!("separate purity defs are only used for conditional spec refinements") + } Some(constraint) => { let constrained_spec = self.get_constrained_spec_mut(constraint); constrained_spec.kind = @@ -767,7 +769,7 @@ impl Refinable for ProcedureSpecification { kind: self.kind.refine(&other.kind), trusted: self.trusted.refine(&other.trusted), terminates: self.terminates.refine(&other.terminates), - purity: self.purity.refine(&other.purity) + purity: self.purity.refine(&other.purity), } } } From b187acc2fd86e9f67b069217b9edd20a5bf99dbc Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Wed, 7 Dec 2022 18:54:11 +0100 Subject: [PATCH 17/64] address clippy's concerns --- .../src/extern_spec_rewriter/common.rs | 11 +++++----- .../src/extern_spec_rewriter/impls.rs | 20 +------------------ .../src/extern_spec_rewriter/traits.rs | 2 +- .../prusti-specs/src/ghost_constraints/mod.rs | 2 +- 4 files changed, 8 insertions(+), 27 deletions(-) diff --git a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/common.rs b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/common.rs index d1a9e88b6ba..be43359dc7a 100644 --- a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/common.rs +++ b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/common.rs @@ -5,6 +5,7 @@ use crate::{ untyped::AnyFnItem, ExternSpecKind, RewritableReceiver, SelfTypeRewriter, }; +use itertools::Itertools; use quote::{quote, ToTokens}; use syn::{ parse_quote_spanned, punctuated::Punctuated, spanned::Spanned, visit::Visit, @@ -343,12 +344,10 @@ pub(super) fn check_is_stub(block: &syn::Block) -> Result<(), syn::Error> { /// The absence of a body is represented in a roundabout way: /// They have a body comprising a single verbatim item containing a single semicolon token. fn is_stub(block: &syn::Block) -> bool { - if block.stmts.len() != 1 { - return false; - } - if let syn::Stmt::Item(syn::Item::Verbatim(tokens)) = &block.stmts[0] { - return tokens.to_string() == ";"; + if let Ok(Some(syn::Stmt::Item(syn::Item::Verbatim(tokens)))) = block.stmts.iter().at_most_one() + { + tokens.to_string() == ";" } else { - return false; + false } } diff --git a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs index 9f412b7c8af..597a4318dbb 100644 --- a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs +++ b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs @@ -32,14 +32,7 @@ fn rewrite_extern_spec_internal(item_impl: &syn::ItemImpl) -> syn::Result bool { - for seg in path.segments.iter() { - if let syn::PathArguments::AngleBracketed(args) = &seg.arguments { - if !args.args.is_empty() { - return true; - } - } - } - false -} - #[cfg(test)] mod tests { use super::rewrite_extern_spec_internal; diff --git a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs index e41c84a59ed..5718efe16e0 100644 --- a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs +++ b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs @@ -148,7 +148,7 @@ impl<'a> GeneratedStruct<'a> { } syn::TraitItem::Method(trait_method) => { if let Some(default) = &trait_method.default { - return Err(check_is_stub(&default).expect_err("this cannot be a stub")); + return Err(check_is_stub(default).expect_err("this cannot be a stub")); } let (method, spec_fns) = self.generate_method_stub(trait_method)?; diff --git a/prusti-contracts/prusti-specs/src/ghost_constraints/mod.rs b/prusti-contracts/prusti-specs/src/ghost_constraints/mod.rs index d3280fa6cfe..45fbffadead 100644 --- a/prusti-contracts/prusti-specs/src/ghost_constraints/mod.rs +++ b/prusti-contracts/prusti-specs/src/ghost_constraints/mod.rs @@ -47,7 +47,7 @@ pub fn generate(attr: TokenStream, item: &untyped::AnyFnItem) -> GeneratedResult } fn generate_where_clause_for_spec( - trait_bounds: &Vec, + trait_bounds: &[syn::PredicateType], existing_where_clause: Option<&syn::WhereClause>, ) -> syn::WhereClause { let mut where_clause = existing_where_clause From d0e3fd2904d250bacdc8dc7b6146ce07d9dd7a8f Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Sun, 11 Dec 2022 04:46:28 +0100 Subject: [PATCH 18/64] add unit test for trait impls with generic arguments removed a check preventing use of this feature previously; this effectively formalizes it as working --- .../pass/extern-spec/trait-impl-generics.rs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 prusti-tests/tests/verify/pass/extern-spec/trait-impl-generics.rs diff --git a/prusti-tests/tests/verify/pass/extern-spec/trait-impl-generics.rs b/prusti-tests/tests/verify/pass/extern-spec/trait-impl-generics.rs new file mode 100644 index 00000000000..c38073ed214 --- /dev/null +++ b/prusti-tests/tests/verify/pass/extern-spec/trait-impl-generics.rs @@ -0,0 +1,36 @@ +use prusti_contracts::*; + +fn main() { + let value = 42; + assert!(value.combine(5) == 47); + assert!(value.combine(true) == 42); + assert!(value.combine(false) == 0); +} + +trait Combine { + fn combine(&self, other: T) -> Self; +} + +impl Combine for i32 { + fn combine(&self, other: i32) -> Self { + self + other + } +} + +impl Combine for i32 { + fn combine(&self, other: bool) -> Self { + if other { *self } else { 0 } + } +} + +#[extern_spec] +impl Combine for i32 { + #[ensures(result == *self + other)] + fn combine(&self, other: i32) -> Self; +} + +#[extern_spec] +impl Combine for i32 { + #[ensures(result == if other { *self } else { 0 })] + fn combine(&self, other: bool) -> Self; +} From a9cb3177ca15030c77b9c292f6be636c561cc948 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Mon, 12 Dec 2022 16:22:19 +0100 Subject: [PATCH 19/64] improve test --- .../verify/pass/extern-spec/trait-impl-generics.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/prusti-tests/tests/verify/pass/extern-spec/trait-impl-generics.rs b/prusti-tests/tests/verify/pass/extern-spec/trait-impl-generics.rs index c38073ed214..94c510345fc 100644 --- a/prusti-tests/tests/verify/pass/extern-spec/trait-impl-generics.rs +++ b/prusti-tests/tests/verify/pass/extern-spec/trait-impl-generics.rs @@ -5,6 +5,8 @@ fn main() { assert!(value.combine(5) == 47); assert!(value.combine(true) == 42); assert!(value.combine(false) == 0); + let t = true; + assert!(t.combine(value)); } trait Combine { @@ -23,6 +25,12 @@ impl Combine for i32 { } } +impl Combine for bool { + fn combine(&self, _other: T) -> Self { + *self + } +} + #[extern_spec] impl Combine for i32 { #[ensures(result == *self + other)] @@ -34,3 +42,9 @@ impl Combine for i32 { #[ensures(result == if other { *self } else { 0 })] fn combine(&self, other: bool) -> Self; } + +#[extern_spec] +impl Combine for bool { + #[ensures(result == *self)] + fn combine(&self, _other: T) -> Self; +} From d4069dd6e86805754cfa48090f88e08bac2090e8 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Fri, 16 Dec 2022 05:43:27 +0100 Subject: [PATCH 20/64] desugaring fixes expressions are not implicitly in parentheses, creating very strange errors when desugaring e.g. a + b to &a + b --- .../prusti-specs/src/specifications/preparser.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/prusti-contracts/prusti-specs/src/specifications/preparser.rs b/prusti-contracts/prusti-specs/src/specifications/preparser.rs index 63238c06c9e..37d0ce084ef 100644 --- a/prusti-contracts/prusti-specs/src/specifications/preparser.rs +++ b/prusti-contracts/prusti-specs/src/specifications/preparser.rs @@ -874,9 +874,9 @@ impl PrustiBinaryOp { let not_lhs = quote_spanned! { lhs.span() => !(#lhs) }; quote_spanned! { span => (#not_lhs || (#rhs)) } } - Self::Or => quote_spanned! { span => #lhs || #rhs }, - Self::And => quote_spanned! { span => #lhs && #rhs }, - Self::SnapEq => quote_spanned! { span => snapshot_equality(&#lhs, &#rhs) }, + Self::Or => quote_spanned! { span => (#lhs) || (#rhs) }, + Self::And => quote_spanned! { span => (#lhs) && (#rhs) }, + Self::SnapEq => quote_spanned! { span => snapshot_equality(&(#lhs), &(#rhs)) }, } } } From c9ae6efc1f0d7a0538cbded2f3c1370e9313701f Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Fri, 16 Dec 2022 05:48:53 +0100 Subject: [PATCH 21/64] conditional spec refinements -> type-conditional spec refinements --- prusti-contracts/prusti-specs/src/ghost_constraints/mod.rs | 2 +- prusti-contracts/prusti-specs/src/lib.rs | 4 ++-- .../prusti-specs/src/specifications/preparser.rs | 6 +++--- prusti-interface/src/specs/mod.rs | 2 +- prusti-interface/src/specs/typed.rs | 4 ++-- .../parse/fail/ghost-constraints/trait-bounds-illegal-1.rs | 2 +- .../parse/fail/ghost-constraints/trait-bounds-illegal-2.rs | 2 +- .../fail/ghost-constraints/different-bounds.rs | 4 ++-- .../ghost-constraints/in-local-refinement-disallowed.rs | 2 +- .../pass/ghost-constraints/associated-types-2.rs | 2 +- .../ghost-constraints-extend-base-attributes.rs | 2 +- prusti-viper/src/encoder/mir/specifications/constraints.rs | 6 +++--- prusti-viper/src/encoder/mir/specifications/specs.rs | 4 ++-- 13 files changed, 21 insertions(+), 21 deletions(-) diff --git a/prusti-contracts/prusti-specs/src/ghost_constraints/mod.rs b/prusti-contracts/prusti-specs/src/ghost_constraints/mod.rs index 45fbffadead..4bbf96ecf93 100644 --- a/prusti-contracts/prusti-specs/src/ghost_constraints/mod.rs +++ b/prusti-contracts/prusti-specs/src/ghost_constraints/mod.rs @@ -8,7 +8,7 @@ use syn::{parse_quote_spanned, spanned::Spanned}; pub fn generate(attr: TokenStream, item: &untyped::AnyFnItem) -> GeneratedResult { let tokens_span = attr.span(); - // Parse conditional spec refinements information + // Parse type-conditional spec refinements information let ghost_constraint = parse_ghost_constraint(attr)?; let mut new_items = vec![]; diff --git a/prusti-contracts/prusti-specs/src/lib.rs b/prusti-contracts/prusti-specs/src/lib.rs index 4d45b5726ae..652ce40bac7 100644 --- a/prusti-contracts/prusti-specs/src/lib.rs +++ b/prusti-contracts/prusti-specs/src/lib.rs @@ -288,7 +288,7 @@ fn generate_for_pure(attr: TokenStream, item: &untyped::AnyFnItem) -> GeneratedR )) } -/// Generate spec items and attributes to typecheck and later retrieve "pure" annotations, but encoded as a referenced separate function that conditional spec refinements can apply trait bounds to. +/// Generate spec items and attributes to typecheck and later retrieve "pure" annotations, but encoded as a referenced separate function that type-conditional spec refinements can apply trait bounds to. fn generate_for_pure_ghost_constraint(item: &untyped::AnyFnItem) -> GeneratedResult { let mut rewriter = rewriter::AstRewriter::new(); let spec_id = rewriter.generate_spec_id(); @@ -540,7 +540,7 @@ pub fn refine_trait_spec(_attr: TokenStream, tokens: TokenStream) -> TokenStream if let Some(span) = illegal_attribute_span { let err = Err(syn::Error::new( span, - "Conditional spec refinements in trait spec refinements not supported", + "Type-onditional spec refinements in trait spec refinements not supported", )); handle_result!(err); } diff --git a/prusti-contracts/prusti-specs/src/specifications/preparser.rs b/prusti-contracts/prusti-specs/src/specifications/preparser.rs index 37d0ce084ef..2dadfebf273 100644 --- a/prusti-contracts/prusti-specs/src/specifications/preparser.rs +++ b/prusti-contracts/prusti-specs/src/specifications/preparser.rs @@ -552,7 +552,7 @@ fn validate_predicate(predicate: syn::WherePredicate) -> syn::Result disallowed_lifetime_error(lifetime_bound.span()), Eq(eq_bound) => err( eq_bound.span(), - "equality constraints are not allowed in conditional spec refinements", + "equality constraints are not allowed in type-conditional spec refinements", ), } } @@ -560,7 +560,7 @@ fn validate_predicate(predicate: syn::WherePredicate) -> syn::Result(span: Span) -> syn::Result { err( span, - "lifetimes are not allowed in conditional spec refinement trait bounds", + "lifetimes are not allowed in type-conditional spec refinement trait bounds", ) } @@ -589,7 +589,7 @@ fn with_ghost_constraint_example(mut err: syn::Error) -> syn::Error { err } -/// A specification enclosed in another specification (e.g. in spec entailments or conditional spec refinements) +/// A specification enclosed in another specification (e.g. in spec entailments or type-conditional spec refinements) #[derive(Debug)] pub enum NestedSpec { Requires(T), diff --git a/prusti-interface/src/specs/mod.rs b/prusti-interface/src/specs/mod.rs index 2b9ee0dbcf6..d81d28f0185 100644 --- a/prusti-interface/src/specs/mod.rs +++ b/prusti-interface/src/specs/mod.rs @@ -170,7 +170,7 @@ impl<'a, 'tcx> SpecCollector<'a, 'tcx> { { let span = self.env.query.get_def_span(*local_id); PrustiError::unsupported( - "Conditional spec refinements can only be applied to trusted functions", + "Type-conditional spec refinements can only be applied to trusted functions", MultiSpan::from(span), ) .emit(&self.env.diagnostic); diff --git a/prusti-interface/src/specs/typed.rs b/prusti-interface/src/specs/typed.rs index 77dcb76c1ca..65a2f436573 100644 --- a/prusti-interface/src/specs/typed.rs +++ b/prusti-interface/src/specs/typed.rs @@ -203,7 +203,7 @@ pub struct ProcedureSpecification { pub pledges: SpecificationItem>, pub trusted: SpecificationItem, pub terminates: SpecificationItem>, - pub purity: SpecificationItem>, // for conditional spec refinements + pub purity: SpecificationItem>, // for type-conditional spec refinements } impl ProcedureSpecification { @@ -441,7 +441,7 @@ impl SpecGraph { pub fn add_purity<'tcx>(&mut self, purity: LocalDefId, env: &Environment<'tcx>) { match self.get_constraint(purity, env) { None => { - unreachable!("separate purity defs are only used for conditional spec refinements") + unreachable!("separate purity defs are only used for type-conditional spec refinements") } Some(constraint) => { let constrained_spec = self.get_constrained_spec_mut(constraint); diff --git a/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-1.rs b/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-1.rs index aa7a666a9c4..05705bba0a4 100644 --- a/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-1.rs +++ b/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-1.rs @@ -2,7 +2,7 @@ use prusti_contracts::*; trait A { } -#[refine_spec(where T: 'static + A [ //~ ERROR: lifetimes are not allowed in conditional spec refinement trait bounds +#[refine_spec(where T: 'static + A [ //~ ERROR: lifetimes are not allowed in type-conditional spec refinement trait bounds ensures(result > 0) ])] fn foo(_x: T) -> i32 { diff --git a/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-2.rs b/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-2.rs index 299cae00f3c..9332f03fb3b 100644 --- a/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-2.rs +++ b/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-2.rs @@ -2,7 +2,7 @@ use prusti_contracts::*; trait A { } -#[refine_spec(where T: for<'a> A<&'a i32> [ //~ ERROR: lifetimes are not allowed in conditional spec refinement trait bounds +#[refine_spec(where T: for<'a> A<&'a i32> [ //~ ERROR: lifetimes are not allowed in type-conditional spec refinement trait bounds ensures(result > 0) ])] fn foo(_x: T) -> i32 { diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/different-bounds.rs b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/different-bounds.rs index a98a97e4fcc..8beb94186e8 100644 --- a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/different-bounds.rs +++ b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/different-bounds.rs @@ -1,4 +1,4 @@ -// Note: For now, it is completely fine to _declare_ two conditional spec refinements with different bounds +// Note: For now, it is completely fine to _declare_ two type-conditional spec refinements with different bounds // since resolving happens for specific callsites. That is, without the call in main, this // file verifies. use prusti_contracts::*; @@ -7,7 +7,7 @@ trait A {} trait B {} #[trusted] -#[refine_spec(where T: A [ //~ ERROR: [Prusti: unsupported feature] Multiple conditional spec refinements with different bounds defined +#[refine_spec(where T: A [ //~ ERROR: [Prusti: unsupported feature] Multiple type-conditional spec refinements with different bounds defined requires(true), ensures(true), ])] diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-local-refinement-disallowed.rs b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-local-refinement-disallowed.rs index adf715af455..1b3077a2c6f 100644 --- a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-local-refinement-disallowed.rs +++ b/prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-local-refinement-disallowed.rs @@ -15,7 +15,7 @@ struct MyStruct; impl MyTrait for MyStruct { #[ensures(result > 10)] - #[refine_spec(where Self: A [ //~ ERROR: Conditional spec refinements in trait spec refinements not supported + #[refine_spec(where Self: A [ //~ ERROR: Type-conditional spec refinements in trait spec refinements not supported ensures(result % 6 == 0) ])] fn foo(&self) -> i32 { diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-2.rs b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-2.rs index c625d433230..35923374cb8 100644 --- a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-2.rs +++ b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-2.rs @@ -32,5 +32,5 @@ trait SomeTrait { fn main() { let f = Foo; let res = f.foo(); - assert!(res > 0); // Conditional spec refinement satisfied! + assert!(res > 0); // Type-conditional spec refinement satisfied! } diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/ghost-constraints-extend-base-attributes.rs b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/ghost-constraints-extend-base-attributes.rs index 67b912eea4a..d7600d5ecb9 100644 --- a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/ghost-constraints-extend-base-attributes.rs +++ b/prusti-tests/tests/verify_overflow/pass/ghost-constraints/ghost-constraints-extend-base-attributes.rs @@ -1,4 +1,4 @@ -// This test demonstrates that conditional spec refinements inherit the specs from the function. +// This test demonstrates that type-conditional spec refinements inherit the specs from the function. use prusti_contracts::*; diff --git a/prusti-viper/src/encoder/mir/specifications/constraints.rs b/prusti-viper/src/encoder/mir/specifications/constraints.rs index 0ff33246015..15a4977e5dc 100644 --- a/prusti-viper/src/encoder/mir/specifications/constraints.rs +++ b/prusti-viper/src/encoder/mir/specifications/constraints.rs @@ -67,7 +67,7 @@ impl<'spec, 'env: 'spec, 'tcx: 'env> ConstraintResolver<'spec, 'env, 'tcx> substs: call_substs, }, // Obligations are resolved for function definition encodings to account - // for conditional spec refinements on traits (behavioral subtyping rules will be checked + // for type-conditional spec refinements on traits (behavioral subtyping rules will be checked // against the resolved spec). SpecQuery::FunctionDefEncoding(proc_def_id, substs) | SpecQuery::GetProcKind(proc_def_id, substs) => ConstraintSolvingContext { @@ -159,7 +159,7 @@ mod trait_bounds { .iter() .all(|predicate| { // Normalize any associated type projections. - // This needs to be done because conditional spec refinements might contain "deeply nested" + // This needs to be done because type-conditional spec refinements might contain "deeply nested" // associated types, e.g. `T: A::OtherAssocType` // where `::OtherAssocType` can be normalized to some concrete type. let normalized_predicate = @@ -249,7 +249,7 @@ mod trait_bounds { if param_envs.len() > 1 { let spans = param_envs.values().flatten().cloned().collect(); PrustiError::unsupported( - "Multiple conditional spec refinements with different bounds defined", + "Multiple type-conditional spec refinements with different bounds defined", MultiSpan::from_spans(spans), ) .add_note("This is currently not supported.", None) diff --git a/prusti-viper/src/encoder/mir/specifications/specs.rs b/prusti-viper/src/encoder/mir/specifications/specs.rs index 002060751d4..b02e97cfa17 100644 --- a/prusti-viper/src/encoder/mir/specifications/specs.rs +++ b/prusti-viper/src/encoder/mir/specifications/specs.rs @@ -57,8 +57,8 @@ pub(super) struct Specifications<'tcx> { user_typed_specs: DefSpecificationMap, /// A refinement can be different based on the query. - /// The query can resolve to different [ProcedureSpecification]s due to conditional spec refinements. - /// Since Prusti does currently not support refinements of conditional spec refinements, we + /// The query can resolve to different [ProcedureSpecification]s due to type-conditional spec refinements. + /// Since Prusti does currently not support refinements of type-conditional spec refinements, we /// store different refined versions for different queries. refined_specs: FxHashMap, ProcedureSpecification>, } From 5e85a131b42ddd34e2266b7c3cc5b36470a29be6 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Fri, 16 Dec 2022 23:06:29 +0100 Subject: [PATCH 22/64] rename ghost constraints to type-conditional spec refinements everywhere --- .../prusti-contracts-proc-macros/src/lib.rs | 7 +-- prusti-contracts/prusti-specs/src/lib.rs | 18 ++++---- prusti-contracts/prusti-specs/src/rewriter.rs | 2 +- .../prusti-specs/src/spec_attribute_kind.rs | 4 +- .../src/specifications/preparser.rs | 45 +++++++++---------- .../mod.rs | 8 ++-- prusti-interface/src/environment/body.rs | 2 +- prusti-interface/src/specs/typed.rs | 12 ++--- prusti-interface/src/utils.rs | 4 +- .../trait-bounds-illegal-1.rs | 0 .../trait-bounds-illegal-2.rs | 0 .../trait-bounds-illegal-3.rs | 0 .../trait-bounds-invalid-macro-arguments-1.rs | 0 .../trait-bounds-invalid-macro-arguments-2.rs | 0 .../trait-bounds-invalid-macro-arguments-3.rs | 0 .../extern-spec/traits-1.rs | 0 .../purity.rs | 0 .../associated-types-1.rs | 0 .../associated-types-2.rs | 0 .../associated-types-3.rs | 0 .../associated-types-4.rs | 0 .../associated-types-5.rs | 0 .../associated-types-6.rs | 0 .../associated-types-7.rs | 0 .../different-bounds.rs | 0 .../in-local-refinement-disallowed.rs | 0 .../in-non-trusted-function.rs | 0 .../nested-generics.rs | 0 .../associated-types-1.rs | 0 .../associated-types-2.rs | 0 .../associated-types-3.rs | 0 .../associated-types-4.rs | 0 .../associated-types-5.rs | 0 .../merge-where-clause.rs | 0 .../nested-generics.rs | 0 .../normalize-associated-types.rs | 0 .../refinements-extend-base-attributes.rs} | 0 .../split-constraint.rs | 0 .../traits-1.rs | 0 .../encoder/mir/specifications/constraints.rs | 4 +- 40 files changed, 50 insertions(+), 56 deletions(-) rename prusti-contracts/prusti-specs/src/{ghost_constraints => type_cond_specs}/mod.rs (87%) rename prusti-tests/tests/parse/fail/{ghost-constraints => type-cond-specs}/trait-bounds-illegal-1.rs (100%) rename prusti-tests/tests/parse/fail/{ghost-constraints => type-cond-specs}/trait-bounds-illegal-2.rs (100%) rename prusti-tests/tests/parse/fail/{ghost-constraints => type-cond-specs}/trait-bounds-illegal-3.rs (100%) rename prusti-tests/tests/parse/fail/{ghost-constraints => type-cond-specs}/trait-bounds-invalid-macro-arguments-1.rs (100%) rename prusti-tests/tests/parse/fail/{ghost-constraints => type-cond-specs}/trait-bounds-invalid-macro-arguments-2.rs (100%) rename prusti-tests/tests/parse/fail/{ghost-constraints => type-cond-specs}/trait-bounds-invalid-macro-arguments-3.rs (100%) rename prusti-tests/tests/verify/pass/{ghost-constraints => type-cond-specs}/extern-spec/traits-1.rs (100%) rename prusti-tests/tests/verify/pass/{ghost-constraints => type-cond-specs}/purity.rs (100%) rename prusti-tests/tests/verify_overflow/fail/{ghost-constraints => type-cond-specs}/associated-types-1.rs (100%) rename prusti-tests/tests/verify_overflow/fail/{ghost-constraints => type-cond-specs}/associated-types-2.rs (100%) rename prusti-tests/tests/verify_overflow/fail/{ghost-constraints => type-cond-specs}/associated-types-3.rs (100%) rename prusti-tests/tests/verify_overflow/fail/{ghost-constraints => type-cond-specs}/associated-types-4.rs (100%) rename prusti-tests/tests/verify_overflow/fail/{ghost-constraints => type-cond-specs}/associated-types-5.rs (100%) rename prusti-tests/tests/verify_overflow/fail/{ghost-constraints => type-cond-specs}/associated-types-6.rs (100%) rename prusti-tests/tests/verify_overflow/fail/{ghost-constraints => type-cond-specs}/associated-types-7.rs (100%) rename prusti-tests/tests/verify_overflow/fail/{ghost-constraints => type-cond-specs}/different-bounds.rs (100%) rename prusti-tests/tests/verify_overflow/fail/{ghost-constraints => type-cond-specs}/in-local-refinement-disallowed.rs (100%) rename prusti-tests/tests/verify_overflow/fail/{ghost-constraints => type-cond-specs}/in-non-trusted-function.rs (100%) rename prusti-tests/tests/verify_overflow/fail/{ghost-constraints => type-cond-specs}/nested-generics.rs (100%) rename prusti-tests/tests/verify_overflow/pass/{ghost-constraints => type-cond-specs}/associated-types-1.rs (100%) rename prusti-tests/tests/verify_overflow/pass/{ghost-constraints => type-cond-specs}/associated-types-2.rs (100%) rename prusti-tests/tests/verify_overflow/pass/{ghost-constraints => type-cond-specs}/associated-types-3.rs (100%) rename prusti-tests/tests/verify_overflow/pass/{ghost-constraints => type-cond-specs}/associated-types-4.rs (100%) rename prusti-tests/tests/verify_overflow/pass/{ghost-constraints => type-cond-specs}/associated-types-5.rs (100%) rename prusti-tests/tests/verify_overflow/pass/{ghost-constraints => type-cond-specs}/merge-where-clause.rs (100%) rename prusti-tests/tests/verify_overflow/pass/{ghost-constraints => type-cond-specs}/nested-generics.rs (100%) rename prusti-tests/tests/verify_overflow/pass/{ghost-constraints => type-cond-specs}/normalize-associated-types.rs (100%) rename prusti-tests/tests/verify_overflow/pass/{ghost-constraints/ghost-constraints-extend-base-attributes.rs => type-cond-specs/refinements-extend-base-attributes.rs} (100%) rename prusti-tests/tests/verify_overflow/pass/{ghost-constraints => type-cond-specs}/split-constraint.rs (100%) rename prusti-tests/tests/verify_overflow/pass/{ghost-constraints => type-cond-specs}/traits-1.rs (100%) diff --git a/prusti-contracts/prusti-contracts-proc-macros/src/lib.rs b/prusti-contracts/prusti-contracts-proc-macros/src/lib.rs index 5a13946787d..2c56de6d0a2 100644 --- a/prusti-contracts/prusti-contracts-proc-macros/src/lib.rs +++ b/prusti-contracts/prusti-contracts-proc-macros/src/lib.rs @@ -222,12 +222,7 @@ pub fn model(_attr: TokenStream, tokens: TokenStream) -> TokenStream { #[cfg(feature = "prusti")] #[proc_macro_attribute] pub fn refine_spec(attr: TokenStream, tokens: TokenStream) -> TokenStream { - rewrite_prusti_attributes( - SpecAttributeKind::GhostConstraint, - attr.into(), - tokens.into(), - ) - .into() + rewrite_prusti_attributes(SpecAttributeKind::RefineSpec, attr.into(), tokens.into()).into() } #[cfg(feature = "prusti")] diff --git a/prusti-contracts/prusti-specs/src/lib.rs b/prusti-contracts/prusti-specs/src/lib.rs index 652ce40bac7..4cfe119fc6d 100644 --- a/prusti-contracts/prusti-specs/src/lib.rs +++ b/prusti-contracts/prusti-specs/src/lib.rs @@ -11,7 +11,7 @@ #[macro_use] mod common; mod extern_spec_rewriter; -mod ghost_constraints; +mod type_cond_specs; mod parse_closure_macro; mod parse_quote_spanned; mod predicate; @@ -32,7 +32,7 @@ use syn::{spanned::Spanned, visit::Visit}; use crate::{ common::{merge_generics, RewritableReceiver, SelfTypeRewriter}, predicate::{is_predicate_macro, ParsedPredicate}, - specifications::preparser::{parse_ghost_constraint, parse_prusti, NestedSpec}, + specifications::preparser::{parse_prusti, parse_type_cond_spec, NestedSpec}, }; pub use extern_spec_rewriter::ExternSpecKind; use parse_closure_macro::ClosureWithSpec; @@ -66,7 +66,7 @@ fn extract_prusti_attributes( | SpecAttributeKind::Ensures | SpecAttributeKind::AfterExpiry | SpecAttributeKind::AssertOnExpiry - | SpecAttributeKind::GhostConstraint => { + | SpecAttributeKind::RefineSpec => { // We need to drop the surrounding parenthesis to make the // tokens identical to the ones passed by the native procedural // macro call. @@ -165,7 +165,7 @@ fn generate_spec_and_assertions( // `check_incompatible_attrs`; so we'll never reach here. SpecAttributeKind::Predicate => unreachable!(), SpecAttributeKind::Invariant => unreachable!(), - SpecAttributeKind::GhostConstraint => ghost_constraints::generate(attr_tokens, item), + SpecAttributeKind::RefineSpec => type_cond_specs::generate(attr_tokens, item), SpecAttributeKind::Model => unreachable!(), SpecAttributeKind::PrintCounterexample => unreachable!(), }; @@ -289,11 +289,11 @@ fn generate_for_pure(attr: TokenStream, item: &untyped::AnyFnItem) -> GeneratedR } /// Generate spec items and attributes to typecheck and later retrieve "pure" annotations, but encoded as a referenced separate function that type-conditional spec refinements can apply trait bounds to. -fn generate_for_pure_ghost_constraint(item: &untyped::AnyFnItem) -> GeneratedResult { +fn generate_for_pure_refinements(item: &untyped::AnyFnItem) -> GeneratedResult { let mut rewriter = rewriter::AstRewriter::new(); let spec_id = rewriter.generate_spec_id(); let spec_id_str = spec_id.to_string(); - let spec_item = rewriter.process_pure_ghost_constraint(spec_id, item)?; + let spec_item = rewriter.process_pure_refinement(spec_id, item)?; Ok(( vec![spec_item], @@ -534,7 +534,7 @@ pub fn refine_trait_spec(_attr: TokenStream, tokens: TokenStream) -> TokenStream let illegal_attribute_span = prusti_attributes .iter() - .filter(|(kind, _)| kind == &SpecAttributeKind::GhostConstraint) + .filter(|(kind, _)| kind == &SpecAttributeKind::RefineSpec) .map(|(_, tokens)| tokens.span()) .next(); if let Some(span) = illegal_attribute_span { @@ -803,7 +803,7 @@ fn extract_prusti_attributes_for_types( SpecAttributeKind::Ensures => unreachable!("ensures on type"), SpecAttributeKind::AfterExpiry => unreachable!("after_expiry on type"), SpecAttributeKind::AssertOnExpiry => unreachable!("assert_on_expiry on type"), - SpecAttributeKind::GhostConstraint => unreachable!("ghost_constraint on type"), + SpecAttributeKind::RefineSpec => unreachable!("refine_spec on type"), SpecAttributeKind::Pure => unreachable!("pure on type"), SpecAttributeKind::Invariant => unreachable!("invariant on type"), SpecAttributeKind::Predicate => unreachable!("predicate on type"), @@ -850,7 +850,7 @@ fn generate_spec_and_assertions_for_types( SpecAttributeKind::Pure => unreachable!(), SpecAttributeKind::Predicate => unreachable!(), SpecAttributeKind::Invariant => unreachable!(), - SpecAttributeKind::GhostConstraint => unreachable!(), + SpecAttributeKind::RefineSpec => unreachable!(), SpecAttributeKind::Terminates => unreachable!(), SpecAttributeKind::Trusted => generate_for_trusted_for_types(attr_tokens, item), SpecAttributeKind::Model => generate_for_model(attr_tokens, item), diff --git a/prusti-contracts/prusti-specs/src/rewriter.rs b/prusti-contracts/prusti-specs/src/rewriter.rs index 483717ea223..9795fcefb1c 100644 --- a/prusti-contracts/prusti-specs/src/rewriter.rs +++ b/prusti-contracts/prusti-specs/src/rewriter.rs @@ -170,7 +170,7 @@ impl AstRewriter { ) } - pub fn process_pure_ghost_constraint( + pub fn process_pure_refinement( &mut self, spec_id: SpecificationId, item: &untyped::AnyFnItem, diff --git a/prusti-contracts/prusti-specs/src/spec_attribute_kind.rs b/prusti-contracts/prusti-specs/src/spec_attribute_kind.rs index fb835acd81d..8a64d3c0495 100644 --- a/prusti-contracts/prusti-specs/src/spec_attribute_kind.rs +++ b/prusti-contracts/prusti-specs/src/spec_attribute_kind.rs @@ -14,7 +14,7 @@ pub enum SpecAttributeKind { Trusted = 6, Predicate = 7, Invariant = 8, - GhostConstraint = 9, + RefineSpec = 9, Terminates = 10, PrintCounterexample = 11, } @@ -32,7 +32,7 @@ impl TryFrom for SpecAttributeKind { "trusted" => Ok(SpecAttributeKind::Trusted), "predicate" => Ok(SpecAttributeKind::Predicate), "invariant" => Ok(SpecAttributeKind::Invariant), - "refine_spec" => Ok(SpecAttributeKind::GhostConstraint), + "refine_spec" => Ok(SpecAttributeKind::RefineSpec), "model" => Ok(SpecAttributeKind::Model), "print_counterexample" => Ok(SpecAttributeKind::PrintCounterexample), _ => Err(name), diff --git a/prusti-contracts/prusti-specs/src/specifications/preparser.rs b/prusti-contracts/prusti-specs/src/specifications/preparser.rs index 2dadfebf273..74f98bbf39c 100644 --- a/prusti-contracts/prusti-specs/src/specifications/preparser.rs +++ b/prusti-contracts/prusti-specs/src/specifications/preparser.rs @@ -57,7 +57,7 @@ pub fn parse_prusti_assert_pledge(tokens: TokenStream) -> syn::Result<(TokenStre Ok((lhs, rhs)) } -pub fn parse_ghost_constraint(tokens: TokenStream) -> syn::Result { +pub fn parse_type_cond_spec(tokens: TokenStream) -> syn::Result { syn::parse2(tokens) } @@ -519,17 +519,17 @@ impl PrustiTokenStream { } #[derive(Debug)] -pub struct GhostConstraint { +pub struct TypeCondSpecRefinement { pub trait_bounds: Vec, pub specs: Vec>, } -impl Parse for GhostConstraint { +impl Parse for TypeCondSpecRefinement { fn parse(input: ParseStream) -> syn::Result { let where_clause = input .parse::() - .map_err(with_ghost_constraint_example)?; - Ok(GhostConstraint { + .map_err(with_type_cond_spec_example)?; + Ok(TypeCondSpecRefinement { trait_bounds: where_clause .predicates .into_iter() @@ -584,7 +584,7 @@ fn validate_trait_bounds(trait_bounds: &syn::PredicateType) -> syn::Result<()> { Ok(()) } -fn with_ghost_constraint_example(mut err: syn::Error) -> syn::Error { +fn with_type_cond_spec_example(mut err: syn::Error) -> syn::Error { err.combine(error(err.span(), "expected where constraint and specifications in brackets, e.g.: `refine_spec(where T: A + B, U: C [requires(...), ...])`")); err } @@ -998,7 +998,7 @@ mod tests { ); } - mod ghost_constraints { + mod type_cond_specs { use std::assert_matches::assert_matches; use super::*; @@ -1007,35 +1007,32 @@ mod tests { fn invalid_args() { let err_invalid_bounds = "expected one of: `for`, parentheses, `fn`, `unsafe`, `extern`, identifier, `::`, `<`, square brackets, `*`, `&`, `!`, `impl`, `_`, lifetime"; assert_error!( - parse_ghost_constraint(quote! { [requires(false)] }), + parse_type_cond_spec(quote! { [requires(false)] }), err_invalid_bounds ); assert_error!( - parse_ghost_constraint(quote! {}), + parse_type_cond_spec(quote! {}), format!("unexpected end of input, {}", err_invalid_bounds) ); - assert_error!(parse_ghost_constraint(quote! {T: A }), "expected `,`"); + assert_error!(parse_type_cond_spec(quote! {T: A }), "expected `,`"); assert_error!( - parse_ghost_constraint(quote! {T: A, [requires(false)], "nope" }), + parse_type_cond_spec(quote! {T: A, [requires(false)], "nope" }), "unexpected extra tokens" ); assert_error!( - parse_ghost_constraint(quote! {[requires(false)], T: A }), + parse_type_cond_spec(quote! {[requires(false)], T: A }), err_invalid_bounds ); assert_error!( - parse_ghost_constraint(quote! {T: A, }), + parse_type_cond_spec(quote! {T: A, }), "expected nested specification in brackets" ); - assert_error!( - parse_ghost_constraint(quote! {T: A, {} }), - err_invalid_bounds - ); + assert_error!(parse_type_cond_spec(quote! {T: A, {} }), err_invalid_bounds); } #[test] fn multiple_bounds_multiple_specs() { - let constraint = parse_ghost_constraint( + let constraint = parse_type_cond_spec( quote! { T: A+B+Foo, U: C, [requires(true), ensures(false), pure]}, ) .unwrap(); @@ -1058,7 +1055,7 @@ mod tests { #[test] fn no_specs() { - let constraint = parse_ghost_constraint(quote! { T: A, []}).unwrap(); + let constraint = parse_type_cond_spec(quote! { T: A, []}).unwrap(); assert_bounds_eq(&constraint.trait_bounds, &[quote! { T : A }]); assert!(constraint.specs.is_empty()); } @@ -1066,17 +1063,17 @@ mod tests { #[test] fn fully_qualified_trait_path() { let constraint = - parse_ghost_constraint(quote! { T: path::to::A, [requires(true)]}).unwrap(); + parse_type_cond_spec(quote! { T: path::to::A, [requires(true)]}).unwrap(); assert_bounds_eq(&constraint.trait_bounds, &[quote! { T : path :: to :: A }]); } #[test] fn tuple_generics() { // just check that parsing succeeds - assert!(parse_ghost_constraint(quote! { T: Fn<(i32,), Output = i32>, []}).is_ok()); - assert!(parse_ghost_constraint(quote! { T: Fn<(i32,)>, []}).is_ok()); - assert!(parse_ghost_constraint(quote! { T: Fn<(i32, bool)>, []}).is_ok()); - assert!(parse_ghost_constraint(quote! { T: Fn<(i32, bool,)>, []}).is_ok()); + assert!(parse_type_cond_spec(quote! { T: Fn<(i32,), Output = i32>, []}).is_ok()); + assert!(parse_type_cond_spec(quote! { T: Fn<(i32,)>, []}).is_ok()); + assert!(parse_type_cond_spec(quote! { T: Fn<(i32, bool)>, []}).is_ok()); + assert!(parse_type_cond_spec(quote! { T: Fn<(i32, bool,)>, []}).is_ok()); } fn assert_bounds_eq(parsed: &[syn::PredicateType], quotes: &[TokenStream]) { diff --git a/prusti-contracts/prusti-specs/src/ghost_constraints/mod.rs b/prusti-contracts/prusti-specs/src/type_cond_specs/mod.rs similarity index 87% rename from prusti-contracts/prusti-specs/src/ghost_constraints/mod.rs rename to prusti-contracts/prusti-specs/src/type_cond_specs/mod.rs index 4bbf96ecf93..4a020b5d429 100644 --- a/prusti-contracts/prusti-specs/src/ghost_constraints/mod.rs +++ b/prusti-contracts/prusti-specs/src/type_cond_specs/mod.rs @@ -1,6 +1,6 @@ use crate::{ - generate_for_ensures, generate_for_pure_ghost_constraint, generate_for_requires, - parse_ghost_constraint, untyped, GeneratedResult, NestedSpec, + generate_for_ensures, generate_for_pure_refinements, generate_for_requires, + parse_type_cond_spec, untyped, GeneratedResult, NestedSpec, }; use proc_macro2::TokenStream; use syn::{parse_quote_spanned, spanned::Spanned}; @@ -9,7 +9,7 @@ pub fn generate(attr: TokenStream, item: &untyped::AnyFnItem) -> GeneratedResult let tokens_span = attr.span(); // Parse type-conditional spec refinements information - let ghost_constraint = parse_ghost_constraint(attr)?; + let ghost_constraint = parse_type_cond_spec(attr)?; let mut new_items = vec![]; let mut new_attrs = vec![]; @@ -18,7 +18,7 @@ pub fn generate(attr: TokenStream, item: &untyped::AnyFnItem) -> GeneratedResult let (mut generated_items, generated_attrs) = match nested_spec { NestedSpec::Ensures(tokens) => generate_for_ensures(tokens, item)?, NestedSpec::Requires(tokens) => generate_for_requires(tokens, item)?, - NestedSpec::Pure => generate_for_pure_ghost_constraint(item)?, + NestedSpec::Pure => generate_for_pure_refinements(item)?, }; for generated_item in generated_items.iter_mut() { diff --git a/prusti-interface/src/environment/body.rs b/prusti-interface/src/environment/body.rs index 8c02460b3a1..615b44e2f9f 100644 --- a/prusti-interface/src/environment/body.rs +++ b/prusti-interface/src/environment/body.rs @@ -292,7 +292,7 @@ impl<'tcx> EnvBody<'tcx> { /// prior to requesting their bodies with `get_spec_body` or exporting with `CrossCrateBodies::from`! pub(crate) fn load_spec_body(&mut self, def_id: LocalDefId) { // The same `def_id` may be referenced twice, e.g. see fn `constrained_contract_inherits_posts` in - // the `ghost-constraints-extend-base-attributes.rs` test case + // the `refinements-extend-base-attributes.rs` test case if self.specs.local.contains_key(&def_id) { return; } diff --git a/prusti-interface/src/specs/typed.rs b/prusti-interface/src/specs/typed.rs index 65a2f436573..4db55242e42 100644 --- a/prusti-interface/src/specs/typed.rs +++ b/prusti-interface/src/specs/typed.rs @@ -1,4 +1,4 @@ -use crate::{environment::Environment, utils::has_trait_bounds_ghost_constraint, PrustiError}; +use crate::{environment::Environment, utils::has_trait_bounds_type_cond_spec, PrustiError}; pub use common::{SpecIdRef, SpecType, SpecificationId}; use log::trace; use prusti_rustc_interface::{ @@ -355,7 +355,7 @@ impl SpecGraph { /// trait SomeTrait { /// #[requires(x > 0)] /// #[ensures(x > 0)] -/// #[ghost_constraint(T: MarkerTrait, [ +/// #[refine_spec(where T: MarkerTrait, [ /// requires(x > 10), /// ensures(x > 10), /// ])] @@ -367,7 +367,7 @@ impl SpecGraph { /// impl SomeTrait for SomeStruct { /// #[requires(x >= 0)] /// #[ensures(x > 10)] -/// #[ghost_constraint(T: MarkerTrait, [ +/// #[refine_spec(where T: MarkerTrait, [ /// requires(x >= -5), /// ensures(x > 20), /// ])] @@ -441,7 +441,9 @@ impl SpecGraph { pub fn add_purity<'tcx>(&mut self, purity: LocalDefId, env: &Environment<'tcx>) { match self.get_constraint(purity, env) { None => { - unreachable!("separate purity defs are only used for type-conditional spec refinements") + unreachable!( + "separate purity defs are only used for type-conditional spec refinements" + ) } Some(constraint) => { let constrained_spec = self.get_constrained_spec_mut(constraint); @@ -506,7 +508,7 @@ impl SpecGraph { env: &Environment<'tcx>, ) -> Option { let attrs = env.query.get_local_attributes(spec); - if has_trait_bounds_ghost_constraint(attrs) { + if has_trait_bounds_type_cond_spec(attrs) { return Some(SpecConstraintKind::ResolveGenericParamTraitBounds); } None diff --git a/prusti-interface/src/utils.rs b/prusti-interface/src/utils.rs index bb8192048e7..268ab7ada70 100644 --- a/prusti-interface/src/utils.rs +++ b/prusti-interface/src/utils.rs @@ -245,8 +245,8 @@ pub fn has_to_model_impl_attr(attrs: &[ast::Attribute]) -> bool { has_prusti_attr(attrs, "type_models_to_model_impl") } -pub fn has_trait_bounds_ghost_constraint(attrs: &[ast::Attribute]) -> bool { - has_prusti_attr(attrs, "ghost_constraint_trait_bounds_in_where_clause") +pub fn has_trait_bounds_type_cond_spec(attrs: &[ast::Attribute]) -> bool { + has_prusti_attr(attrs, "type_cond_spec_trait_bounds_in_where_clause") } pub fn has_abstract_predicate_attr(attrs: &[ast::Attribute]) -> bool { diff --git a/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-1.rs b/prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-illegal-1.rs similarity index 100% rename from prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-1.rs rename to prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-illegal-1.rs diff --git a/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-2.rs b/prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-illegal-2.rs similarity index 100% rename from prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-2.rs rename to prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-illegal-2.rs diff --git a/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-3.rs b/prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-illegal-3.rs similarity index 100% rename from prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-illegal-3.rs rename to prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-illegal-3.rs diff --git a/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-invalid-macro-arguments-1.rs b/prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-invalid-macro-arguments-1.rs similarity index 100% rename from prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-invalid-macro-arguments-1.rs rename to prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-invalid-macro-arguments-1.rs diff --git a/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-invalid-macro-arguments-2.rs b/prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-invalid-macro-arguments-2.rs similarity index 100% rename from prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-invalid-macro-arguments-2.rs rename to prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-invalid-macro-arguments-2.rs diff --git a/prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-invalid-macro-arguments-3.rs b/prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-invalid-macro-arguments-3.rs similarity index 100% rename from prusti-tests/tests/parse/fail/ghost-constraints/trait-bounds-invalid-macro-arguments-3.rs rename to prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-invalid-macro-arguments-3.rs diff --git a/prusti-tests/tests/verify/pass/ghost-constraints/extern-spec/traits-1.rs b/prusti-tests/tests/verify/pass/type-cond-specs/extern-spec/traits-1.rs similarity index 100% rename from prusti-tests/tests/verify/pass/ghost-constraints/extern-spec/traits-1.rs rename to prusti-tests/tests/verify/pass/type-cond-specs/extern-spec/traits-1.rs diff --git a/prusti-tests/tests/verify/pass/ghost-constraints/purity.rs b/prusti-tests/tests/verify/pass/type-cond-specs/purity.rs similarity index 100% rename from prusti-tests/tests/verify/pass/ghost-constraints/purity.rs rename to prusti-tests/tests/verify/pass/type-cond-specs/purity.rs diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-1.rs b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-1.rs similarity index 100% rename from prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-1.rs rename to prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-1.rs diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-2.rs b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-2.rs similarity index 100% rename from prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-2.rs rename to prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-2.rs diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-3.rs b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-3.rs similarity index 100% rename from prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-3.rs rename to prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-3.rs diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-4.rs b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-4.rs similarity index 100% rename from prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-4.rs rename to prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-4.rs diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-5.rs b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-5.rs similarity index 100% rename from prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-5.rs rename to prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-5.rs diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-6.rs b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-6.rs similarity index 100% rename from prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-6.rs rename to prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-6.rs diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-7.rs b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-7.rs similarity index 100% rename from prusti-tests/tests/verify_overflow/fail/ghost-constraints/associated-types-7.rs rename to prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-7.rs diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/different-bounds.rs b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/different-bounds.rs similarity index 100% rename from prusti-tests/tests/verify_overflow/fail/ghost-constraints/different-bounds.rs rename to prusti-tests/tests/verify_overflow/fail/type-cond-specs/different-bounds.rs diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-local-refinement-disallowed.rs b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/in-local-refinement-disallowed.rs similarity index 100% rename from prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-local-refinement-disallowed.rs rename to prusti-tests/tests/verify_overflow/fail/type-cond-specs/in-local-refinement-disallowed.rs diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-non-trusted-function.rs b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/in-non-trusted-function.rs similarity index 100% rename from prusti-tests/tests/verify_overflow/fail/ghost-constraints/in-non-trusted-function.rs rename to prusti-tests/tests/verify_overflow/fail/type-cond-specs/in-non-trusted-function.rs diff --git a/prusti-tests/tests/verify_overflow/fail/ghost-constraints/nested-generics.rs b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/nested-generics.rs similarity index 100% rename from prusti-tests/tests/verify_overflow/fail/ghost-constraints/nested-generics.rs rename to prusti-tests/tests/verify_overflow/fail/type-cond-specs/nested-generics.rs diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-1.rs b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-1.rs similarity index 100% rename from prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-1.rs rename to prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-1.rs diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-2.rs b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-2.rs similarity index 100% rename from prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-2.rs rename to prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-2.rs diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-3.rs b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-3.rs similarity index 100% rename from prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-3.rs rename to prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-3.rs diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-4.rs b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-4.rs similarity index 100% rename from prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-4.rs rename to prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-4.rs diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-5.rs b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-5.rs similarity index 100% rename from prusti-tests/tests/verify_overflow/pass/ghost-constraints/associated-types-5.rs rename to prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-5.rs diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/merge-where-clause.rs b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/merge-where-clause.rs similarity index 100% rename from prusti-tests/tests/verify_overflow/pass/ghost-constraints/merge-where-clause.rs rename to prusti-tests/tests/verify_overflow/pass/type-cond-specs/merge-where-clause.rs diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/nested-generics.rs b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/nested-generics.rs similarity index 100% rename from prusti-tests/tests/verify_overflow/pass/ghost-constraints/nested-generics.rs rename to prusti-tests/tests/verify_overflow/pass/type-cond-specs/nested-generics.rs diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/normalize-associated-types.rs b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/normalize-associated-types.rs similarity index 100% rename from prusti-tests/tests/verify_overflow/pass/ghost-constraints/normalize-associated-types.rs rename to prusti-tests/tests/verify_overflow/pass/type-cond-specs/normalize-associated-types.rs diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/ghost-constraints-extend-base-attributes.rs b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/refinements-extend-base-attributes.rs similarity index 100% rename from prusti-tests/tests/verify_overflow/pass/ghost-constraints/ghost-constraints-extend-base-attributes.rs rename to prusti-tests/tests/verify_overflow/pass/type-cond-specs/refinements-extend-base-attributes.rs diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/split-constraint.rs b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/split-constraint.rs similarity index 100% rename from prusti-tests/tests/verify_overflow/pass/ghost-constraints/split-constraint.rs rename to prusti-tests/tests/verify_overflow/pass/type-cond-specs/split-constraint.rs diff --git a/prusti-tests/tests/verify_overflow/pass/ghost-constraints/traits-1.rs b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/traits-1.rs similarity index 100% rename from prusti-tests/tests/verify_overflow/pass/ghost-constraints/traits-1.rs rename to prusti-tests/tests/verify_overflow/pass/type-cond-specs/traits-1.rs diff --git a/prusti-viper/src/encoder/mir/specifications/constraints.rs b/prusti-viper/src/encoder/mir/specifications/constraints.rs index 15a4977e5dc..2f592b6bd9a 100644 --- a/prusti-viper/src/encoder/mir/specifications/constraints.rs +++ b/prusti-viper/src/encoder/mir/specifications/constraints.rs @@ -129,7 +129,7 @@ fn constraint_fulfilled<'spec, 'env: 'spec, 'tcx: 'env>( mod trait_bounds { use super::*; - use prusti_interface::{utils::has_trait_bounds_ghost_constraint, PrustiError}; + use prusti_interface::{utils::has_trait_bounds_type_cond_spec, PrustiError}; use rustc_hash::FxHashMap; pub(super) fn resolve<'spec, 'env: 'spec, 'tcx: 'env>( @@ -236,7 +236,7 @@ mod trait_bounds { let param_env = env.tcx().param_env(spec_id); let spec_span = env.query.get_def_span(spec_id); let attrs = env.query.get_attributes(*spec_id); - if has_trait_bounds_ghost_constraint(attrs) { + if has_trait_bounds_type_cond_spec(attrs) { param_envs.entry(param_env).or_default().push(spec_span); } } From 76e6f6598f6161d0afa5ce23ce0fa03ebfe90a73 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Sat, 17 Dec 2022 00:40:06 +0100 Subject: [PATCH 23/64] update test to reflect that generics are supported not thoroughly tested, but let's not let perfect be the enemy of good enough --- .../src/extern_spec_rewriter/impls.rs | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs index 597a4318dbb..a74595bbc86 100644 --- a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs +++ b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs @@ -329,16 +329,28 @@ mod tests { } #[test] - fn generics_not_supported() { + fn generics_supported() { let mut inp_impl: syn::ItemImpl = parse_quote!( - impl MyTrait for MyStruct { + impl MyTrait for MyStruct { fn foo(&mut self, arg1: I); } ); - let rewritten = rewrite_extern_spec_internal(&mut inp_impl); + let rewritten = rewrite_extern_spec_internal(&mut inp_impl).unwrap(); + + let newtype_ident = &rewritten.generated_struct.ident; + let expected_impl: syn::ItemImpl = parse_quote! { + impl #newtype_ident <> { + #[prusti::extern_spec = "trait_impl"] + #[allow(unused, dead_code)] + #[prusti::trusted] + fn foo(_self: &mut MyStruct, arg1: I) { + > :: foo :: <>(_self, arg1) + } + } + }; - assert!(rewritten.is_err()); + assert_eq_tokenizable(rewritten.generated_impl.clone(), expected_impl); } } } From c1c8cc0010971f06fcbbb83a855b2ad11e293c15 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Sat, 17 Dec 2022 00:40:51 +0100 Subject: [PATCH 24/64] update test to reflect that generics are supported not thoroughly tested, but let's not let perfect be the enemy of good enough --- prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs index a74595bbc86..1bca1fd74cf 100644 --- a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs +++ b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs @@ -331,7 +331,7 @@ mod tests { #[test] fn generics_supported() { let mut inp_impl: syn::ItemImpl = parse_quote!( - impl MyTrait for MyStruct { + impl MyTrait for MyStruct { fn foo(&mut self, arg1: I); } ); From 32b342ce01a6d377de6fc98b2520994fe3088a42 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Sat, 17 Dec 2022 01:26:20 +0100 Subject: [PATCH 25/64] adjust join_spans testing-specific behavior testing-specific workaround is now only present when cfg(test) is active --- .../prusti-specs/src/specifications/preparser.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/prusti-contracts/prusti-specs/src/specifications/preparser.rs b/prusti-contracts/prusti-specs/src/specifications/preparser.rs index 74f98bbf39c..70c29694e14 100644 --- a/prusti-contracts/prusti-specs/src/specifications/preparser.rs +++ b/prusti-contracts/prusti-specs/src/specifications/preparser.rs @@ -931,17 +931,16 @@ impl RustOp { } fn join_spans(s1: Span, s2: Span) -> Span { - // Tests don't run in the proc macro context - let is_proc_macro = std::panic::catch_unwind(|| s1.unwrap()).is_ok(); - if is_proc_macro { - // This works even when compiled with stable + // Tests don't run in the proc macro context, so this gets a little funky for them + if cfg!(test) { + // During tests we don't care so much about returning a default + s1.join(s2).unwrap_or(s1) + } else { + // This works even when compiled with stable, unlike `s1.join(s2)` s1.unwrap() .join(s2.unwrap()) .expect("Failed to join spans!") .into() - } else { - // During tests we don't care so much about returning a default - s1.join(s2).unwrap_or(s1) } } From 33669eac93548fbbca3c6fb9433b035e6d4f8027 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Sat, 17 Dec 2022 01:26:57 +0100 Subject: [PATCH 26/64] make typecondspec parser more robust, require comma again --- .../src/specifications/preparser.rs | 77 +++++++++++++------ 1 file changed, 54 insertions(+), 23 deletions(-) diff --git a/prusti-contracts/prusti-specs/src/specifications/preparser.rs b/prusti-contracts/prusti-specs/src/specifications/preparser.rs index 70c29694e14..edcac6d2c64 100644 --- a/prusti-contracts/prusti-specs/src/specifications/preparser.rs +++ b/prusti-contracts/prusti-specs/src/specifications/preparser.rs @@ -526,21 +526,36 @@ pub struct TypeCondSpecRefinement { impl Parse for TypeCondSpecRefinement { fn parse(input: ParseStream) -> syn::Result { - let where_clause = input - .parse::() + input + .parse::() .map_err(with_type_cond_spec_example)?; Ok(TypeCondSpecRefinement { - trait_bounds: where_clause - .predicates - .into_iter() - .map(validate_predicate) - .collect::>>()?, + trait_bounds: parse_trait_bounds(input)?, specs: PrustiTokenStream::new(input.parse().unwrap()) .parse_rest(|pts| pts.pop_group_of_nested_specs(input.span()))?, }) } } +fn parse_trait_bounds(input: ParseStream) -> syn::Result> { + let mut bounds: Vec = Vec::new(); + loop { + let predicate = input + .parse::() + .map_err(with_type_cond_spec_example)?; + bounds.push(validate_predicate(predicate)?); + input + .parse::() + .map_err(with_type_cond_spec_example)?; + if input.peek(syn::token::Bracket) || input.is_empty() { + // now expecting specs in [] + // also breaking when empty, to handle that as missing specs rather than a missing constraint + break; + } + } + Ok(bounds) +} + fn validate_predicate(predicate: syn::WherePredicate) -> syn::Result { use syn::WherePredicate::*; @@ -585,7 +600,7 @@ fn validate_trait_bounds(trait_bounds: &syn::PredicateType) -> syn::Result<()> { } fn with_type_cond_spec_example(mut err: syn::Error) -> syn::Error { - err.combine(error(err.span(), "expected where constraint and specifications in brackets, e.g.: `refine_spec(where T: A + B, U: C [requires(...), ...])`")); + err.combine(error(err.span(), "expected where constraint and specifications in brackets, e.g.: `refine_spec(where T: A + B, U: C, [requires(...), ...])`")); err } @@ -1007,32 +1022,48 @@ mod tests { let err_invalid_bounds = "expected one of: `for`, parentheses, `fn`, `unsafe`, `extern`, identifier, `::`, `<`, square brackets, `*`, `&`, `!`, `impl`, `_`, lifetime"; assert_error!( parse_type_cond_spec(quote! { [requires(false)] }), + "expected `where`" + ); + assert_error!( + parse_type_cond_spec(quote! { where [requires(false)] }), + err_invalid_bounds + ); + assert_error!( + parse_type_cond_spec(quote! { [requires(false)], T: A }), + "expected `where`" + ); + assert_error!( + parse_type_cond_spec(quote! { where [requires(false)], T: A }), err_invalid_bounds ); assert_error!( parse_type_cond_spec(quote! {}), - format!("unexpected end of input, {}", err_invalid_bounds) + format!("unexpected end of input, {}", "expected `where`") ); - assert_error!(parse_type_cond_spec(quote! {T: A }), "expected `,`"); + assert_error!(parse_type_cond_spec(quote! { T: A }), "expected `where`"); + assert_error!(parse_type_cond_spec(quote! { where T: A }), "expected `,`"); assert_error!( - parse_type_cond_spec(quote! {T: A, [requires(false)], "nope" }), - "unexpected extra tokens" + parse_type_cond_spec(quote! { where T: A, }), + "expected nested specification in brackets" ); assert_error!( - parse_type_cond_spec(quote! {[requires(false)], T: A }), + parse_type_cond_spec(quote! { where T: A, {} }), err_invalid_bounds ); assert_error!( - parse_type_cond_spec(quote! {T: A, }), - "expected nested specification in brackets" + parse_type_cond_spec(quote! { where T: A [requires(false)] }), + "expected `,`" + ); + assert_error!( + parse_type_cond_spec(quote! { where T: A, [requires(false)], "nope" }), + "unexpected extra tokens" ); - assert_error!(parse_type_cond_spec(quote! {T: A, {} }), err_invalid_bounds); } #[test] fn multiple_bounds_multiple_specs() { let constraint = parse_type_cond_spec( - quote! { T: A+B+Foo, U: C, [requires(true), ensures(false), pure]}, + quote! { where T: A+B+Foo, U: C, [requires(true), ensures(false), pure]}, ) .unwrap(); @@ -1054,7 +1085,7 @@ mod tests { #[test] fn no_specs() { - let constraint = parse_type_cond_spec(quote! { T: A, []}).unwrap(); + let constraint = parse_type_cond_spec(quote! { where T: A, []}).unwrap(); assert_bounds_eq(&constraint.trait_bounds, &[quote! { T : A }]); assert!(constraint.specs.is_empty()); } @@ -1062,17 +1093,17 @@ mod tests { #[test] fn fully_qualified_trait_path() { let constraint = - parse_type_cond_spec(quote! { T: path::to::A, [requires(true)]}).unwrap(); + parse_type_cond_spec(quote! { where T: path::to::A, [requires(true)]}).unwrap(); assert_bounds_eq(&constraint.trait_bounds, &[quote! { T : path :: to :: A }]); } #[test] fn tuple_generics() { // just check that parsing succeeds - assert!(parse_type_cond_spec(quote! { T: Fn<(i32,), Output = i32>, []}).is_ok()); - assert!(parse_type_cond_spec(quote! { T: Fn<(i32,)>, []}).is_ok()); - assert!(parse_type_cond_spec(quote! { T: Fn<(i32, bool)>, []}).is_ok()); - assert!(parse_type_cond_spec(quote! { T: Fn<(i32, bool,)>, []}).is_ok()); + assert!(parse_type_cond_spec(quote! { where T: Fn<(i32,), Output = i32>, []}).is_ok()); + assert!(parse_type_cond_spec(quote! { where T: Fn<(i32,)>, []}).is_ok()); + assert!(parse_type_cond_spec(quote! { where T: Fn<(i32, bool)>, []}).is_ok()); + assert!(parse_type_cond_spec(quote! { where T: Fn<(i32, bool,)>, []}).is_ok()); } fn assert_bounds_eq(parsed: &[syn::PredicateType], quotes: &[TokenStream]) { From 9d2fe45c9ac2e50fbdbd97b23a27a0babaeccbbe Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Sat, 17 Dec 2022 01:40:01 +0100 Subject: [PATCH 27/64] update overlooked holdover of old ghost constraint term --- prusti-contracts/prusti-specs/src/type_cond_specs/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/prusti-contracts/prusti-specs/src/type_cond_specs/mod.rs b/prusti-contracts/prusti-specs/src/type_cond_specs/mod.rs index 4a020b5d429..bb6b8348d36 100644 --- a/prusti-contracts/prusti-specs/src/type_cond_specs/mod.rs +++ b/prusti-contracts/prusti-specs/src/type_cond_specs/mod.rs @@ -9,12 +9,12 @@ pub fn generate(attr: TokenStream, item: &untyped::AnyFnItem) -> GeneratedResult let tokens_span = attr.span(); // Parse type-conditional spec refinements information - let ghost_constraint = parse_type_cond_spec(attr)?; + let type_cond_spec = parse_type_cond_spec(attr)?; let mut new_items = vec![]; let mut new_attrs = vec![]; - for nested_spec in ghost_constraint.specs { + for nested_spec in type_cond_spec.specs { let (mut generated_items, generated_attrs) = match nested_spec { NestedSpec::Ensures(tokens) => generate_for_ensures(tokens, item)?, NestedSpec::Requires(tokens) => generate_for_requires(tokens, item)?, @@ -29,13 +29,13 @@ pub fn generate(attr: TokenStream, item: &untyped::AnyFnItem) -> GeneratedResult // Add bounds as a where clause item_fn.sig.generics.where_clause = Some(generate_where_clause_for_spec( - &ghost_constraint.trait_bounds, + &type_cond_spec.trait_bounds, item_fn.sig.generics.where_clause.as_ref(), )); // Add attribute to mark this as a "specification with constraint" (used for processing the contract in `SpecCollector`) item_fn.attrs.push(parse_quote_spanned! {tokens_span=> - #[prusti::ghost_constraint_trait_bounds_in_where_clause] + #[prusti::type_cond_spec_trait_bounds_in_where_clause] }); } From 3cc43884e12bb5183620dc667a0e7a7a34cdc083 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Sat, 17 Dec 2022 01:49:52 +0100 Subject: [PATCH 28/64] fix typo --- prusti-contracts/prusti-specs/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prusti-contracts/prusti-specs/src/lib.rs b/prusti-contracts/prusti-specs/src/lib.rs index 4cfe119fc6d..8d3e57bfc39 100644 --- a/prusti-contracts/prusti-specs/src/lib.rs +++ b/prusti-contracts/prusti-specs/src/lib.rs @@ -540,7 +540,7 @@ pub fn refine_trait_spec(_attr: TokenStream, tokens: TokenStream) -> TokenStream if let Some(span) = illegal_attribute_span { let err = Err(syn::Error::new( span, - "Type-onditional spec refinements in trait spec refinements not supported", + "Type-conditional spec refinements in trait spec refinements not supported", )); handle_result!(err); } From c080ee7e4ccd51a280158d146c638b6fca3a1c10 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Sat, 17 Dec 2022 01:51:35 +0100 Subject: [PATCH 29/64] update compiletests to new typecondspec syntax --- .../parse/fail/type-cond-specs/trait-bounds-illegal-1.rs | 2 +- .../parse/fail/type-cond-specs/trait-bounds-illegal-3.rs | 2 +- .../trait-bounds-invalid-macro-arguments-1.rs | 2 +- .../trait-bounds-invalid-macro-arguments-2.rs | 4 ++-- .../trait-bounds-invalid-macro-arguments-3.rs | 6 +++--- prusti-tests/tests/verify/fail/ghost-constraints/purity.rs | 2 +- .../tests/verify/fail/ghost-constraints/traits-1.rs | 2 +- .../verify/pass/type-cond-specs/extern-spec/traits-1.rs | 2 +- prusti-tests/tests/verify/pass/type-cond-specs/purity.rs | 2 +- .../ui/ghost-constraints/invalid-trait-refinement-1.rs | 2 +- .../ui/ghost-constraints/invalid-trait-refinement-2.rs | 2 +- .../fail/type-cond-specs/associated-types-1.rs | 2 +- .../fail/type-cond-specs/associated-types-2.rs | 2 +- .../fail/type-cond-specs/associated-types-3.rs | 2 +- .../fail/type-cond-specs/associated-types-4.rs | 2 +- .../fail/type-cond-specs/associated-types-5.rs | 2 +- .../fail/type-cond-specs/associated-types-6.rs | 2 +- .../fail/type-cond-specs/associated-types-7.rs | 2 +- .../fail/type-cond-specs/different-bounds.rs | 4 ++-- .../fail/type-cond-specs/in-local-refinement-disallowed.rs | 4 ++-- .../fail/type-cond-specs/in-non-trusted-function.rs | 4 ++-- .../verify_overflow/fail/type-cond-specs/nested-generics.rs | 2 +- .../pass/type-cond-specs/associated-types-1.rs | 2 +- .../pass/type-cond-specs/associated-types-2.rs | 2 +- .../pass/type-cond-specs/associated-types-3.rs | 2 +- .../pass/type-cond-specs/associated-types-4.rs | 2 +- .../pass/type-cond-specs/associated-types-5.rs | 2 +- .../pass/type-cond-specs/merge-where-clause.rs | 2 +- .../verify_overflow/pass/type-cond-specs/nested-generics.rs | 2 +- .../pass/type-cond-specs/normalize-associated-types.rs | 2 +- .../type-cond-specs/refinements-extend-base-attributes.rs | 4 ++-- .../pass/type-cond-specs/split-constraint.rs | 4 ++-- .../tests/verify_overflow/pass/type-cond-specs/traits-1.rs | 2 +- 33 files changed, 41 insertions(+), 41 deletions(-) diff --git a/prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-illegal-1.rs b/prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-illegal-1.rs index 05705bba0a4..95268dc13ec 100644 --- a/prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-illegal-1.rs +++ b/prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-illegal-1.rs @@ -2,7 +2,7 @@ use prusti_contracts::*; trait A { } -#[refine_spec(where T: 'static + A [ //~ ERROR: lifetimes are not allowed in type-conditional spec refinement trait bounds +#[refine_spec(where T: 'static + A, [ //~ ERROR: lifetimes are not allowed in type-conditional spec refinement trait bounds ensures(result > 0) ])] fn foo(_x: T) -> i32 { diff --git a/prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-illegal-3.rs b/prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-illegal-3.rs index cbf2ba32370..15c3eb32bd4 100644 --- a/prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-illegal-3.rs +++ b/prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-illegal-3.rs @@ -5,7 +5,7 @@ struct MyStruct { } impl MyStruct { - #[refine_spec(where elf: MyStruct [ //~ ERROR: expected trait, found struct `MyStruct` + #[refine_spec(where elf: MyStruct, [ //~ ERROR: expected trait, found struct `MyStruct` requires(x > 0) ])] //~| ERROR: cannot find type `elf` in this scope [E0412] diff --git a/prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-invalid-macro-arguments-1.rs b/prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-invalid-macro-arguments-1.rs index c4a504de0c2..0320a38a263 100644 --- a/prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-invalid-macro-arguments-1.rs +++ b/prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-invalid-macro-arguments-1.rs @@ -3,7 +3,7 @@ use prusti_contracts::*; #[refine_spec([ //~ ERROR: expected `where` ensures(result > 0) ])] -//~| ERROR: expected where constraint and specifications in brackets, e.g.: `refine_spec(where T: A + B, U: C [requires(...), ...])` +//~| ERROR: expected where constraint and specifications in brackets, e.g.: `refine_spec(where T: A + B, U: C, [requires(...), ...])` fn foo(_x: T) -> i32 { 42 } diff --git a/prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-invalid-macro-arguments-2.rs b/prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-invalid-macro-arguments-2.rs index 2098507ff56..a8748bf2cfe 100644 --- a/prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-invalid-macro-arguments-2.rs +++ b/prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-invalid-macro-arguments-2.rs @@ -1,9 +1,9 @@ use prusti_contracts::*; -#[refine_spec(where 42 [ //~ ERROR: expected one of: `for`, parentheses, `fn`, `unsafe`, `extern`, identifier, `::`, `<`, square brackets, `*`, `&`, `!`, `impl`, `_`, lifetime +#[refine_spec(where 42, [ //~ ERROR: expected one of: `for`, parentheses, `fn`, `unsafe`, `extern`, identifier, `::`, `<`, square brackets, `*`, `&`, `!`, `impl`, `_`, lifetime ensures(result > 0) ])] -//~| ERROR: expected where constraint and specifications in brackets, e.g.: `refine_spec(where T: A + B, U: C [requires(...), ...])` +//~| ERROR: expected where constraint and specifications in brackets, e.g.: `refine_spec(where T: A + B, U: C, [requires(...), ...])` fn foo(_x: T) -> i32 { 42 } diff --git a/prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-invalid-macro-arguments-3.rs b/prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-invalid-macro-arguments-3.rs index f8b074a57d5..18794677db2 100644 --- a/prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-invalid-macro-arguments-3.rs +++ b/prusti-tests/tests/parse/fail/type-cond-specs/trait-bounds-invalid-macro-arguments-3.rs @@ -1,9 +1,9 @@ use prusti_contracts::*; -#[refine_spec(where T: Copy, [ - ensures(result > 0) //~ ERROR: expected `,` +#[refine_spec(where T: Copy [ //~ ERROR: expected `,` + ensures(result > 0) ])] -//~| ERROR: expected where constraint and specifications in brackets, e.g.: `refine_spec(where T: A + B, U: C [requires(...), ...])` +//~| ERROR: expected where constraint and specifications in brackets, e.g.: `refine_spec(where T: A + B, U: C, [requires(...), ...])` fn foo(_x: T) -> i32 { 42 } diff --git a/prusti-tests/tests/verify/fail/ghost-constraints/purity.rs b/prusti-tests/tests/verify/fail/ghost-constraints/purity.rs index a8e36e403de..9efccf23f24 100644 --- a/prusti-tests/tests/verify/fail/ghost-constraints/purity.rs +++ b/prusti-tests/tests/verify/fail/ghost-constraints/purity.rs @@ -1,6 +1,6 @@ use prusti_contracts::*; -#[refine_spec(where T: Copy [pure])] +#[refine_spec(where T: Copy, [pure])] #[trusted] fn test(_t: T) -> bool { true } diff --git a/prusti-tests/tests/verify/fail/ghost-constraints/traits-1.rs b/prusti-tests/tests/verify/fail/ghost-constraints/traits-1.rs index 0a6fba3fc03..2825640927a 100644 --- a/prusti-tests/tests/verify/fail/ghost-constraints/traits-1.rs +++ b/prusti-tests/tests/verify/fail/ghost-constraints/traits-1.rs @@ -3,7 +3,7 @@ use prusti_contracts::*; trait A {} trait MyTrait { - #[refine_spec(where Self: A [ensures(result > 0)])] + #[refine_spec(where Self: A, [ensures(result > 0)])] #[trusted] fn foo(&self) -> i32; } diff --git a/prusti-tests/tests/verify/pass/type-cond-specs/extern-spec/traits-1.rs b/prusti-tests/tests/verify/pass/type-cond-specs/extern-spec/traits-1.rs index 1cf9994e9ee..a23cc354a71 100644 --- a/prusti-tests/tests/verify/pass/type-cond-specs/extern-spec/traits-1.rs +++ b/prusti-tests/tests/verify/pass/type-cond-specs/extern-spec/traits-1.rs @@ -13,7 +13,7 @@ trait MyTrait { #[extern_spec] trait MyTrait { - #[refine_spec(where Self: HasContract [ + #[refine_spec(where Self: HasContract, [ requires(self.pre()), ensures(self.post()) ])] diff --git a/prusti-tests/tests/verify/pass/type-cond-specs/purity.rs b/prusti-tests/tests/verify/pass/type-cond-specs/purity.rs index d0e9fe686fd..d62fb59320d 100644 --- a/prusti-tests/tests/verify/pass/type-cond-specs/purity.rs +++ b/prusti-tests/tests/verify/pass/type-cond-specs/purity.rs @@ -1,6 +1,6 @@ use prusti_contracts::*; -#[refine_spec(where T: Copy [pure])] +#[refine_spec(where T: Copy, [pure])] #[trusted] fn test(_t: T) -> bool { true } diff --git a/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-1.rs b/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-1.rs index 4a6674b95ff..af9c3a8df5e 100644 --- a/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-1.rs +++ b/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-1.rs @@ -13,7 +13,7 @@ trait MyTrait { #[extern_spec] trait MyTrait { - #[refine_spec(where Self: HasContract [ + #[refine_spec(where Self: HasContract, [ requires(self.pre()), ensures(self.post()) ])] fn foo(&mut self); diff --git a/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-2.rs b/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-2.rs index 700ed2c09fa..87599686b30 100644 --- a/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-2.rs +++ b/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-2.rs @@ -13,7 +13,7 @@ trait MyTrait { #[extern_spec] trait MyTrait { - #[refine_spec(where Self: HasContract [ + #[refine_spec(where Self: HasContract, [ requires(self.pre()), ensures(self.post()) ])] fn foo(&mut self); diff --git a/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-1.rs b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-1.rs index 0739b7ab581..26a225ae10e 100644 --- a/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-1.rs +++ b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-1.rs @@ -10,7 +10,7 @@ impl A for Foo { } #[trusted] -#[refine_spec(where T: A [ +#[refine_spec(where T: A, [ ensures(result > 0) ])] fn foo(x: T) -> i32 { diff --git a/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-2.rs b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-2.rs index 812bbd69ed3..3582791a9b1 100644 --- a/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-2.rs +++ b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-2.rs @@ -23,7 +23,7 @@ impl SomeTrait for Foo { #[extern_spec] trait SomeTrait { - #[refine_spec(where Self: A::AssocType> [ + #[refine_spec(where Self: A::AssocType>, [ ensures(result > 0) ])] fn foo(&self) -> i32; diff --git a/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-3.rs b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-3.rs index 2dd3ed105b5..5e8fa08ae9e 100644 --- a/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-3.rs +++ b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-3.rs @@ -25,7 +25,7 @@ impl SomeTrait for Foo { #[extern_spec] trait SomeTrait { - #[refine_spec(where Self: A::AssocType> [ + #[refine_spec(where Self: A::AssocType>, [ ensures(result > 0) ])] fn foo(&self) -> i32; diff --git a/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-4.rs b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-4.rs index 6ca83d1ef12..9e89dbf956f 100644 --- a/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-4.rs +++ b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-4.rs @@ -23,7 +23,7 @@ impl SomeTrait for Foo { #[extern_spec] trait SomeTrait<#[generic] T> { - #[refine_spec(where Self: A>::AssocType> [ + #[refine_spec(where Self: A>::AssocType>, [ ensures(result > 0) ])] fn foo(&self, x: T) -> i32; diff --git a/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-5.rs b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-5.rs index eb9f03bf019..37976542539 100644 --- a/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-5.rs +++ b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-5.rs @@ -10,7 +10,7 @@ impl A for Foo { } #[trusted] -#[refine_spec(where T: A [ +#[refine_spec(where T: A, [ ensures(result > 0) ])] fn foo(x: T) -> i32 { diff --git a/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-6.rs b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-6.rs index 7558b69a007..1bde1157949 100644 --- a/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-6.rs +++ b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-6.rs @@ -21,7 +21,7 @@ impl A for FooNoMatch2 { #[trusted] -#[refine_spec(where T: A [ +#[refine_spec(where T: A, [ ensures(result > 0) ])] fn foo(x: T) -> i32 { diff --git a/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-7.rs b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-7.rs index 52c3d142e56..85006e6017e 100644 --- a/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-7.rs +++ b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-7.rs @@ -38,7 +38,7 @@ impl SomeTrait for FooNoMatch2 { #[extern_spec] trait SomeTrait<#[generic] X, #[generic] Y> { - #[refine_spec(where Self: A>::AssocType> [ + #[refine_spec(where Self: A>::AssocType>, [ ensures(result > 0) ])] fn foo(&self) -> i32; diff --git a/prusti-tests/tests/verify_overflow/fail/type-cond-specs/different-bounds.rs b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/different-bounds.rs index 8beb94186e8..76ad0c87e08 100644 --- a/prusti-tests/tests/verify_overflow/fail/type-cond-specs/different-bounds.rs +++ b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/different-bounds.rs @@ -7,11 +7,11 @@ trait A {} trait B {} #[trusted] -#[refine_spec(where T: A [ //~ ERROR: [Prusti: unsupported feature] Multiple type-conditional spec refinements with different bounds defined +#[refine_spec(where T: A, [ //~ ERROR: [Prusti: unsupported feature] Multiple type-conditional spec refinements with different bounds defined requires(true), ensures(true), ])] -#[refine_spec(where T: B [ +#[refine_spec(where T: B, [ requires(true), ensures(true), ])] diff --git a/prusti-tests/tests/verify_overflow/fail/type-cond-specs/in-local-refinement-disallowed.rs b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/in-local-refinement-disallowed.rs index 1b3077a2c6f..ae8c48de354 100644 --- a/prusti-tests/tests/verify_overflow/fail/type-cond-specs/in-local-refinement-disallowed.rs +++ b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/in-local-refinement-disallowed.rs @@ -4,7 +4,7 @@ trait A {} trait MyTrait { #[ensures(result > 0)] - #[refine_spec(where Self: A [ + #[refine_spec(where Self: A, [ ensures(result % 2 == 0) ])] fn foo(&self) -> i32; @@ -15,7 +15,7 @@ struct MyStruct; impl MyTrait for MyStruct { #[ensures(result > 10)] - #[refine_spec(where Self: A [ //~ ERROR: Type-conditional spec refinements in trait spec refinements not supported + #[refine_spec(where Self: A, [ //~ ERROR: Type-conditional spec refinements in trait spec refinements not supported ensures(result % 6 == 0) ])] fn foo(&self) -> i32 { diff --git a/prusti-tests/tests/verify_overflow/fail/type-cond-specs/in-non-trusted-function.rs b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/in-non-trusted-function.rs index abb1937813c..f34479dcab0 100644 --- a/prusti-tests/tests/verify_overflow/fail/type-cond-specs/in-non-trusted-function.rs +++ b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/in-non-trusted-function.rs @@ -2,10 +2,10 @@ use prusti_contracts::*; trait A {} -#[refine_spec(where T: A [ +#[refine_spec(where T: A, [ ensures(true) ])] -fn foo() {} //~ ERROR: Conditional spec refinements can only be applied to trusted functions +fn foo() {} //~ ERROR: Type-conditional spec refinements can only be applied to trusted functions fn main() { } diff --git a/prusti-tests/tests/verify_overflow/fail/type-cond-specs/nested-generics.rs b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/nested-generics.rs index b2977e70630..cbf4e9fb242 100644 --- a/prusti-tests/tests/verify_overflow/fail/type-cond-specs/nested-generics.rs +++ b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/nested-generics.rs @@ -9,7 +9,7 @@ impl A for i32 {} impl B for i32 {} #[trusted] -#[refine_spec(where T: A + B + B [ +#[refine_spec(where T: A + B + B, [ ensures(result > 0) ])] fn foo(_x: T) -> i32 { diff --git a/prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-1.rs b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-1.rs index e63f3b35f31..a00b3befa00 100644 --- a/prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-1.rs +++ b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-1.rs @@ -10,7 +10,7 @@ impl A for Foo { } #[trusted] -#[refine_spec(where T: A [ +#[refine_spec(where T: A, [ ensures(result > 0) ])] fn foo(x: T) -> i32 { diff --git a/prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-2.rs b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-2.rs index 35923374cb8..15db557c8bc 100644 --- a/prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-2.rs +++ b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-2.rs @@ -23,7 +23,7 @@ impl SomeTrait for Foo { #[extern_spec] trait SomeTrait { - #[refine_spec(where Self: A::AssocType> [ + #[refine_spec(where Self: A::AssocType>, [ ensures(result > 0) ])] fn foo(&self) -> i32; diff --git a/prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-3.rs b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-3.rs index 195c80505d1..081f253bee1 100644 --- a/prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-3.rs +++ b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-3.rs @@ -25,7 +25,7 @@ impl SomeTrait for Foo { #[extern_spec] trait SomeTrait { - #[refine_spec(where Self: A::AssocType> [ + #[refine_spec(where Self: A::AssocType>, [ ensures(result > 0) ])] fn foo(&self) -> i32; diff --git a/prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-4.rs b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-4.rs index d299e42fea3..3e8822af9ff 100644 --- a/prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-4.rs +++ b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-4.rs @@ -23,7 +23,7 @@ impl SomeTrait for Foo { #[extern_spec] trait SomeTrait<#[generic] T> { - #[refine_spec(where Self: A>::AssocType> [ + #[refine_spec(where Self: A>::AssocType>, [ ensures(result > 0) ])] fn foo(&self, x: T) -> i32; diff --git a/prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-5.rs b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-5.rs index af53f69a7fd..7bda6bc285a 100644 --- a/prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-5.rs +++ b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-5.rs @@ -10,7 +10,7 @@ impl A for Foo { } #[trusted] -#[refine_spec(where T: A [ +#[refine_spec(where T: A, [ ensures(result > 0) ])] fn foo(x: T) -> i32 { diff --git a/prusti-tests/tests/verify_overflow/pass/type-cond-specs/merge-where-clause.rs b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/merge-where-clause.rs index df248d6b5dc..4e3c159c176 100644 --- a/prusti-tests/tests/verify_overflow/pass/type-cond-specs/merge-where-clause.rs +++ b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/merge-where-clause.rs @@ -20,7 +20,7 @@ impl B for i32 { // The specs under the constraint `T: B` are also aware of the fact that `T: A` (defined on the function) #[trusted] -#[refine_spec(where T: B [ +#[refine_spec(where T: B, [ requires(x.a() == 42), ensures(result == x.b()) ])] diff --git a/prusti-tests/tests/verify_overflow/pass/type-cond-specs/nested-generics.rs b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/nested-generics.rs index ee0e3f9509c..ebec2142813 100644 --- a/prusti-tests/tests/verify_overflow/pass/type-cond-specs/nested-generics.rs +++ b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/nested-generics.rs @@ -9,7 +9,7 @@ impl B for i32 {} impl B for i32 {} #[trusted] -#[refine_spec(where T: A + B + B [ +#[refine_spec(where T: A + B + B, [ ensures(result > 0) ])] fn foo(_x: T) -> i32 { diff --git a/prusti-tests/tests/verify_overflow/pass/type-cond-specs/normalize-associated-types.rs b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/normalize-associated-types.rs index 8c2f5b0f6aa..acacc406d17 100644 --- a/prusti-tests/tests/verify_overflow/pass/type-cond-specs/normalize-associated-types.rs +++ b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/normalize-associated-types.rs @@ -10,7 +10,7 @@ trait A { trait B { type BType; - #[refine_spec(where Self: A::BType> [ + #[refine_spec(where Self: A::BType>, [ requires(self.foo(&arg)), ensures(self.foo(&arg)) ])] diff --git a/prusti-tests/tests/verify_overflow/pass/type-cond-specs/refinements-extend-base-attributes.rs b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/refinements-extend-base-attributes.rs index d7600d5ecb9..07460e92af7 100644 --- a/prusti-tests/tests/verify_overflow/pass/type-cond-specs/refinements-extend-base-attributes.rs +++ b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/refinements-extend-base-attributes.rs @@ -7,7 +7,7 @@ impl A for i32 {} #[pure] #[trusted] -#[refine_spec(where T: A [ +#[refine_spec(where T: A, [ ensures(result == 42) ])] fn constrained_contract_stays_pure(_x: &T) -> i32 { @@ -19,7 +19,7 @@ fn verify_constrained_contract_stays_pure(a: i32) {} #[trusted] #[ensures(result % 2 == 0)] -#[refine_spec(where T: A [ +#[refine_spec(where T: A, [ ensures(result == 42) ])] fn constrained_contract_inherits_posts(_x: T) -> i32 { diff --git a/prusti-tests/tests/verify_overflow/pass/type-cond-specs/split-constraint.rs b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/split-constraint.rs index 202988e0e1f..311a84e545e 100644 --- a/prusti-tests/tests/verify_overflow/pass/type-cond-specs/split-constraint.rs +++ b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/split-constraint.rs @@ -5,10 +5,10 @@ trait A {} impl A for i32 {} #[trusted] -#[refine_spec(where T: A [ +#[refine_spec(where T: A, [ ensures(result % 2 == 0) ])] -#[refine_spec(where T: A [ +#[refine_spec(where T: A, [ ensures(result > 0) ])] fn foo(_x: T) -> i32 { diff --git a/prusti-tests/tests/verify_overflow/pass/type-cond-specs/traits-1.rs b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/traits-1.rs index 7ab5e9b4b0f..aefcb74eb12 100644 --- a/prusti-tests/tests/verify_overflow/pass/type-cond-specs/traits-1.rs +++ b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/traits-1.rs @@ -3,7 +3,7 @@ use prusti_contracts::*; trait A {} trait MyTrait { - #[refine_spec(where Self: A [ensures(result > 0)])] + #[refine_spec(where Self: A, [ensures(result > 0)])] #[trusted] fn foo(&self) -> i32; } From 6c4076b16fb5f931074fdd72caca6923b4b360a9 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Sat, 17 Dec 2022 03:42:04 +0100 Subject: [PATCH 30/64] update preparser tests to include the new parentheses --- .../prusti-specs/src/specifications/preparser.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/prusti-contracts/prusti-specs/src/specifications/preparser.rs b/prusti-contracts/prusti-specs/src/specifications/preparser.rs index edcac6d2c64..afbe05c0c55 100644 --- a/prusti-contracts/prusti-specs/src/specifications/preparser.rs +++ b/prusti-contracts/prusti-specs/src/specifications/preparser.rs @@ -980,6 +980,12 @@ mod tests { .to_string(), "(! (a) || (b))", ); + assert_eq!( + parse_prusti("a === b + c".parse().unwrap()) + .unwrap() + .to_string(), + "snapshot_equality (& (a) , & (b + c))", + ); assert_eq!( parse_prusti("a ==> b ==> c".parse().unwrap()) .unwrap() @@ -990,7 +996,7 @@ mod tests { parse_prusti("(a ==> b && c) ==> d || e".parse().unwrap()) .unwrap() .to_string(), - "(! (((! (a) || (b && c)))) || (d || e))", + "(! (((! (a) || ((b) && (c))))) || ((d) || (e)))", ); assert_eq!( parse_prusti("forall(|x: i32| a ==> b)".parse().unwrap()).unwrap().to_string(), @@ -998,7 +1004,7 @@ 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(), @@ -1008,7 +1014,7 @@ mod tests { parse_prusti("assert!(a === b ==> b)".parse().unwrap()) .unwrap() .to_string(), - "assert ! ((! (snapshot_equality (& a , & b)) || (b)))", + "assert ! ((! (snapshot_equality (& (a) , & (b))) || (b)))", ); } From bb01b499b52641816f5e6c41c3b300217794345a Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Sat, 17 Dec 2022 04:33:37 +0100 Subject: [PATCH 31/64] update cargo test --- prusti-tests/tests/cargo_verify/prusti_toml/output.stdout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prusti-tests/tests/cargo_verify/prusti_toml/output.stdout b/prusti-tests/tests/cargo_verify/prusti_toml/output.stdout index de5fc6b22ab..8bf7fea5122 100644 --- a/prusti-tests/tests/cargo_verify/prusti_toml/output.stdout +++ b/prusti-tests/tests/cargo_verify/prusti_toml/output.stdout @@ -24,4 +24,4 @@ pub fn test2() { if !false { ::core::panicking::panic("assertion failed: false") }; } pub fn test3(x: usize) { let _y: usize = 1 - x; } -ProcedureSpecification { source: DefId(0:7 ~ prusti_toml[..]::test1), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:6 ~ prusti_toml[..]::prusti_post_item_test1_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } +ProcedureSpecification { source: DefId(0:7 ~ prusti_toml[..]::test1), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:6 ~ prusti_toml[..]::prusti_post_item_test1_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } From 6c6ba2014397c79cc56ce793058207c34310c2f0 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Sat, 17 Dec 2022 05:12:45 +0100 Subject: [PATCH 32/64] update more compiletests --- .../tests/parse/ui/after_expiry.stdout | 6 +- prusti-tests/tests/parse/ui/and.stdout | 20 ++-- .../tests/parse/ui/assert_on_expiry.stdout | 6 +- prusti-tests/tests/parse/ui/composite.stdout | 108 +++++++++--------- prusti-tests/tests/parse/ui/exists.stdout | 16 +-- prusti-tests/tests/parse/ui/expression.stdout | 8 +- prusti-tests/tests/parse/ui/forall.stdout | 16 +-- prusti-tests/tests/parse/ui/implies.stdout | 20 ++-- .../parse/ui/predicates-visibility.stdout | 4 +- prusti-tests/tests/parse/ui/predicates.stdout | 12 +- .../tests/parse/ui/trait-bounds.stdout | 2 +- prusti-tests/tests/parse/ui/traits.stdout | 24 ++-- prusti-tests/tests/parse/ui/true.stdout | 6 +- prusti-tests/tests/parse/ui/trusted.stdout | 2 +- .../typecheck/ui/forall_encode_typeck.stdout | 4 +- .../tests/typecheck/ui/forall_triggers.stdout | 24 ++-- .../tests/typecheck/ui/nested_forall.stdout | 16 +-- prusti-tests/tests/verify/ui/calls.stdout | 11 +- .../verify/ui/failing-postcondition.stderr | 4 +- prusti-tests/tests/verify/ui/false.stdout | 2 +- .../tests/verify/ui/forall_verify.stdout | 14 +-- .../invalid-trait-refinement-1.stderr | 2 +- .../invalid-trait-refinement-2.stderr | 2 +- prusti-tests/tests/verify/ui/pledges.stdout | 2 +- prusti-tests/tests/verify/ui/predicate.stdout | 20 ++-- prusti-tests/tests/verify/ui/pure.stdout | 15 +-- 26 files changed, 186 insertions(+), 180 deletions(-) diff --git a/prusti-tests/tests/parse/ui/after_expiry.stdout b/prusti-tests/tests/parse/ui/after_expiry.stdout index 75e9f494648..6c60519a6c5 100644 --- a/prusti-tests/tests/parse/ui/after_expiry.stdout +++ b/prusti-tests/tests/parse/ui/after_expiry.stdout @@ -48,6 +48,6 @@ fn prusti_pledge_item_test3_$(NUM_UUID)(x: u32, #[prusti::specs_version = $(SPECS_VERSION)] fn test3(x: u32) -> u32 { 1 } fn main() {} -ProcedureSpecification { source: DefId(0:6 ~ after_expiry[$(CRATE_ID)]::test1), kind: Inherent(Impure), pres: Empty, posts: Empty, pledges: Inherent([Pledge { reference: None, lhs: None, rhs: DefId(0:5 ~ after_expiry[$(CRATE_ID)]::prusti_pledge_item_test1_$(NUM_UUID)) }]), trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:8 ~ after_expiry[$(CRATE_ID)]::test2), kind: Inherent(Impure), pres: Empty, posts: Empty, pledges: Inherent([Pledge { reference: None, lhs: None, rhs: DefId(0:7 ~ after_expiry[$(CRATE_ID)]::prusti_pledge_item_test2_$(NUM_UUID)) }]), trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:10 ~ after_expiry[$(CRATE_ID)]::test3), kind: Inherent(Impure), pres: Empty, posts: Empty, pledges: Inherent([Pledge { reference: None, lhs: None, rhs: DefId(0:9 ~ after_expiry[$(CRATE_ID)]::prusti_pledge_item_test3_$(NUM_UUID)) }]), trusted: Inherent(false), terminates: Inherent(None) } +ProcedureSpecification { source: DefId(0:6 ~ after_expiry[$(CRATE_ID)]::test1), kind: Inherent(Impure), pres: Empty, posts: Empty, pledges: Inherent([Pledge { reference: None, lhs: None, rhs: DefId(0:5 ~ after_expiry[$(CRATE_ID)]::prusti_pledge_item_test1_$(NUM_UUID)) }]), trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:8 ~ after_expiry[$(CRATE_ID)]::test2), kind: Inherent(Impure), pres: Empty, posts: Empty, pledges: Inherent([Pledge { reference: None, lhs: None, rhs: DefId(0:7 ~ after_expiry[$(CRATE_ID)]::prusti_pledge_item_test2_$(NUM_UUID)) }]), trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:10 ~ after_expiry[$(CRATE_ID)]::test3), kind: Inherent(Impure), pres: Empty, posts: Empty, pledges: Inherent([Pledge { reference: None, lhs: None, rhs: DefId(0:9 ~ after_expiry[$(CRATE_ID)]::prusti_pledge_item_test3_$(NUM_UUID)) }]), trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } diff --git a/prusti-tests/tests/parse/ui/and.stdout b/prusti-tests/tests/parse/ui/and.stdout index e3025397829..b2b3216a935 100644 --- a/prusti-tests/tests/parse/ui/and.stdout +++ b/prusti-tests/tests/parse/ui/and.stdout @@ -23,7 +23,7 @@ use prusti_contracts::*; #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test1_$(NUM_UUID)() -> bool { - !!((true && true): bool) + !!(((true) && (true)): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -32,7 +32,7 @@ fn test1() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test2_$(NUM_UUID)() -> bool { - !!((true && true && true): bool) + !!((((true) && (true)) && (true)): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -41,7 +41,7 @@ fn test2() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test3_$(NUM_UUID)() -> bool { - !!((true && (true && true)): bool) + !!(((true) && (((true) && (true)))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -50,7 +50,7 @@ fn test3() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test4_$(NUM_UUID)() -> bool { - !!(((true && true) && true): bool) + !!(((((true) && (true))) && (true)): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -59,14 +59,14 @@ fn test4() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test5_$(NUM_UUID)() -> bool { - !!(((true && true) && (true && true)): bool) + !!(((((true) && (true))) && (((true) && (true)))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] fn test5() {} fn main() {} -ProcedureSpecification { source: DefId(0:6 ~ and[$(CRATE_ID)]::test1), kind: Inherent(Impure), pres: Inherent([DefId(0:5 ~ and[$(CRATE_ID)]::prusti_pre_item_test1_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:8 ~ and[$(CRATE_ID)]::test2), kind: Inherent(Impure), pres: Inherent([DefId(0:7 ~ and[$(CRATE_ID)]::prusti_pre_item_test2_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:10 ~ and[$(CRATE_ID)]::test3), kind: Inherent(Impure), pres: Inherent([DefId(0:9 ~ and[$(CRATE_ID)]::prusti_pre_item_test3_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:12 ~ and[$(CRATE_ID)]::test4), kind: Inherent(Impure), pres: Inherent([DefId(0:11 ~ and[$(CRATE_ID)]::prusti_pre_item_test4_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:14 ~ and[$(CRATE_ID)]::test5), kind: Inherent(Impure), pres: Inherent([DefId(0:13 ~ and[$(CRATE_ID)]::prusti_pre_item_test5_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } +ProcedureSpecification { source: DefId(0:6 ~ and[$(CRATE_ID)]::test1), kind: Inherent(Impure), pres: Inherent([DefId(0:5 ~ and[$(CRATE_ID)]::prusti_pre_item_test1_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:8 ~ and[$(CRATE_ID)]::test2), kind: Inherent(Impure), pres: Inherent([DefId(0:7 ~ and[$(CRATE_ID)]::prusti_pre_item_test2_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:10 ~ and[$(CRATE_ID)]::test3), kind: Inherent(Impure), pres: Inherent([DefId(0:9 ~ and[$(CRATE_ID)]::prusti_pre_item_test3_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:12 ~ and[$(CRATE_ID)]::test4), kind: Inherent(Impure), pres: Inherent([DefId(0:11 ~ and[$(CRATE_ID)]::prusti_pre_item_test4_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:14 ~ and[$(CRATE_ID)]::test5), kind: Inherent(Impure), pres: Inherent([DefId(0:13 ~ and[$(CRATE_ID)]::prusti_pre_item_test5_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } diff --git a/prusti-tests/tests/parse/ui/assert_on_expiry.stdout b/prusti-tests/tests/parse/ui/assert_on_expiry.stdout index 39f42d46fdf..f41d78124c3 100644 --- a/prusti-tests/tests/parse/ui/assert_on_expiry.stdout +++ b/prusti-tests/tests/parse/ui/assert_on_expiry.stdout @@ -73,6 +73,6 @@ fn prusti_pledge_item_test3_$(NUM_UUID)(x: u32, #[prusti::specs_version = $(SPECS_VERSION)] fn test3(x: u32) -> u32 { 1 } fn main() {} -ProcedureSpecification { source: DefId(0:7 ~ assert_on_expiry[$(CRATE_ID)]::test1), kind: Inherent(Impure), pres: Empty, posts: Empty, pledges: Inherent([Pledge { reference: None, lhs: Some(DefId(0:5 ~ assert_on_expiry[$(CRATE_ID)]::prusti_pledge_item_test1_$(NUM_UUID))), rhs: DefId(0:6 ~ assert_on_expiry[$(CRATE_ID)]::prusti_pledge_item_test1_$(NUM_UUID)) }]), trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:10 ~ assert_on_expiry[$(CRATE_ID)]::test2), kind: Inherent(Impure), pres: Empty, posts: Empty, pledges: Inherent([Pledge { reference: None, lhs: Some(DefId(0:8 ~ assert_on_expiry[$(CRATE_ID)]::prusti_pledge_item_test2_$(NUM_UUID))), rhs: DefId(0:9 ~ assert_on_expiry[$(CRATE_ID)]::prusti_pledge_item_test2_$(NUM_UUID)) }]), trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:13 ~ assert_on_expiry[$(CRATE_ID)]::test3), kind: Inherent(Impure), pres: Empty, posts: Empty, pledges: Inherent([Pledge { reference: None, lhs: Some(DefId(0:11 ~ assert_on_expiry[$(CRATE_ID)]::prusti_pledge_item_test3_$(NUM_UUID))), rhs: DefId(0:12 ~ assert_on_expiry[$(CRATE_ID)]::prusti_pledge_item_test3_$(NUM_UUID)) }]), trusted: Inherent(false), terminates: Inherent(None) } +ProcedureSpecification { source: DefId(0:7 ~ assert_on_expiry[$(CRATE_ID)]::test1), kind: Inherent(Impure), pres: Empty, posts: Empty, pledges: Inherent([Pledge { reference: None, lhs: Some(DefId(0:5 ~ assert_on_expiry[$(CRATE_ID)]::prusti_pledge_item_test1_$(NUM_UUID))), rhs: DefId(0:6 ~ assert_on_expiry[$(CRATE_ID)]::prusti_pledge_item_test1_$(NUM_UUID)) }]), trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:10 ~ assert_on_expiry[$(CRATE_ID)]::test2), kind: Inherent(Impure), pres: Empty, posts: Empty, pledges: Inherent([Pledge { reference: None, lhs: Some(DefId(0:8 ~ assert_on_expiry[$(CRATE_ID)]::prusti_pledge_item_test2_$(NUM_UUID))), rhs: DefId(0:9 ~ assert_on_expiry[$(CRATE_ID)]::prusti_pledge_item_test2_$(NUM_UUID)) }]), trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:13 ~ assert_on_expiry[$(CRATE_ID)]::test3), kind: Inherent(Impure), pres: Empty, posts: Empty, pledges: Inherent([Pledge { reference: None, lhs: Some(DefId(0:11 ~ assert_on_expiry[$(CRATE_ID)]::prusti_pledge_item_test3_$(NUM_UUID))), rhs: DefId(0:12 ~ assert_on_expiry[$(CRATE_ID)]::prusti_pledge_item_test3_$(NUM_UUID)) }]), trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } diff --git a/prusti-tests/tests/parse/ui/composite.stdout b/prusti-tests/tests/parse/ui/composite.stdout index 88d310516e4..7647d4db054 100644 --- a/prusti-tests/tests/parse/ui/composite.stdout +++ b/prusti-tests/tests/parse/ui/composite.stdout @@ -42,7 +42,7 @@ use prusti_contracts::*; #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test1_$(NUM_UUID)() -> bool { - !!(((!(true && true) || (true && true))): bool) + !!(((!((true) && (true)) || ((true) && (true)))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -51,7 +51,8 @@ fn test1() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test2_$(NUM_UUID)() -> bool { - !!((true && ((!(true) || (true))) && (true || true) && true): bool) + !!(((((true) && (((!(true) || (true))))) && (((true) || (true)))) && + (true)): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -60,7 +61,7 @@ fn test2() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test3_$(NUM_UUID)() -> bool { - !!(((!((true && true)) || (true))): bool) + !!(((!(((true) && (true))) || (true))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -69,7 +70,7 @@ fn test3() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test4_$(NUM_UUID)() -> bool { - !!(((!(((!(true) || (true))) && true) || (true))): bool) + !!(((!((((!(true) || (true)))) && (true)) || (true))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -78,8 +79,8 @@ fn test4() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test5_$(NUM_UUID)() -> bool { - !!((((!(true) || (true))) && ((!(true) || (true && (true || true))))): - bool) + !!(((((!(true) || (true)))) && + (((!(true) || ((true) && (((true) || (true)))))))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -88,7 +89,7 @@ fn test5() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test6_$(NUM_UUID)() -> bool { - !!(((!((true && true)) || + !!(((!(((true) && (true))) || ((!(true) || ((!(true) || ((!(true) || (true))))))))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] @@ -98,8 +99,8 @@ fn test6() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test7_$(NUM_UUID)() -> bool { - !!(((!((true && true)) || ((!((true && true)) || ((true && true)))))): - bool) + !!(((!(((true) && (true))) || + ((!(((true) && (true))) || (((true) && (true))))))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -108,7 +109,7 @@ fn test7() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test8_$(NUM_UUID)() -> bool { - !!(((!((true || true)) || ((true || true)))): bool) + !!(((!(((true) || (true))) || (((true) || (true))))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -117,7 +118,8 @@ fn test8() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test9_$(NUM_UUID)() -> bool { - !!(((!((true || true)) || ((true || (true && (true || true)))))): bool) + !!(((!(((true) || (true))) || + (((true) || (((true) && (((true) || (true))))))))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -126,10 +128,10 @@ fn test9() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test10_$(NUM_UUID)() -> bool { - !!((true && - forall((), - #[prusti::spec_only] |a: i32| -> bool - { ((a == 5): bool) })): bool) + !!(((true) && + (forall((), + #[prusti::spec_only] |a: i32| -> bool + { ((a == 5): bool) }))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -199,10 +201,10 @@ fn test16() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test17_$(NUM_UUID)() -> bool { - !!((true && - exists((), - #[prusti::spec_only] |a: i32| -> bool - { ((a == 5): bool) })): bool) + !!(((true) && + (exists((), + #[prusti::spec_only] |a: i32| -> bool + { ((a == 5): bool) }))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -272,7 +274,7 @@ fn test23() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test24_$(NUM_UUID)() -> bool { - !!((true && true || true): bool) + !!((((true) && (true)) || (true)): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -281,11 +283,12 @@ fn test24() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test25_$(NUM_UUID)() -> bool { - !!((forall((), #[prusti::spec_only] |a: i32| -> bool { ((a == 5): bool) }) + !!(((forall((), + #[prusti::spec_only] |a: i32| -> bool { ((a == 5): bool) })) || - forall((), - #[prusti::spec_only] |a: i32| -> bool - { ((a == 5): bool) })): bool) + (forall((), + #[prusti::spec_only] |a: i32| -> bool + { ((a == 5): bool) }))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -294,37 +297,38 @@ fn test25() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test26_$(NUM_UUID)() -> bool { - !!((exists((), #[prusti::spec_only] |a: i32| -> bool { ((a == 5): bool) }) + !!(((exists((), + #[prusti::spec_only] |a: i32| -> bool { ((a == 5): bool) })) || - exists((), - #[prusti::spec_only] |a: i32| -> bool - { ((a == 5): bool) })): bool) + (exists((), + #[prusti::spec_only] |a: i32| -> bool + { ((a == 5): bool) }))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] fn test26() {} fn main() {} -ProcedureSpecification { source: DefId(0:6 ~ composite[$(CRATE_ID)]::test1), kind: Inherent(Impure), pres: Inherent([DefId(0:5 ~ composite[$(CRATE_ID)]::prusti_pre_item_test1_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:8 ~ composite[$(CRATE_ID)]::test2), kind: Inherent(Impure), pres: Inherent([DefId(0:7 ~ composite[$(CRATE_ID)]::prusti_pre_item_test2_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:10 ~ composite[$(CRATE_ID)]::test3), kind: Inherent(Impure), pres: Inherent([DefId(0:9 ~ composite[$(CRATE_ID)]::prusti_pre_item_test3_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:12 ~ composite[$(CRATE_ID)]::test4), kind: Inherent(Impure), pres: Inherent([DefId(0:11 ~ composite[$(CRATE_ID)]::prusti_pre_item_test4_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:14 ~ composite[$(CRATE_ID)]::test5), kind: Inherent(Impure), pres: Inherent([DefId(0:13 ~ composite[$(CRATE_ID)]::prusti_pre_item_test5_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:16 ~ composite[$(CRATE_ID)]::test6), kind: Inherent(Impure), pres: Inherent([DefId(0:15 ~ composite[$(CRATE_ID)]::prusti_pre_item_test6_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:18 ~ composite[$(CRATE_ID)]::test7), kind: Inherent(Impure), pres: Inherent([DefId(0:17 ~ composite[$(CRATE_ID)]::prusti_pre_item_test7_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:20 ~ composite[$(CRATE_ID)]::test8), kind: Inherent(Impure), pres: Inherent([DefId(0:19 ~ composite[$(CRATE_ID)]::prusti_pre_item_test8_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:22 ~ composite[$(CRATE_ID)]::test9), kind: Inherent(Impure), pres: Inherent([DefId(0:21 ~ composite[$(CRATE_ID)]::prusti_pre_item_test9_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:25 ~ composite[$(CRATE_ID)]::test10), kind: Inherent(Impure), pres: Inherent([DefId(0:23 ~ composite[$(CRATE_ID)]::prusti_pre_item_test10_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:28 ~ composite[$(CRATE_ID)]::test12), kind: Inherent(Impure), pres: Inherent([DefId(0:26 ~ composite[$(CRATE_ID)]::prusti_pre_item_test12_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:31 ~ composite[$(CRATE_ID)]::test13), kind: Inherent(Impure), pres: Inherent([DefId(0:29 ~ composite[$(CRATE_ID)]::prusti_pre_item_test13_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:34 ~ composite[$(CRATE_ID)]::test14), kind: Inherent(Impure), pres: Inherent([DefId(0:32 ~ composite[$(CRATE_ID)]::prusti_pre_item_test14_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:37 ~ composite[$(CRATE_ID)]::test15), kind: Inherent(Impure), pres: Inherent([DefId(0:35 ~ composite[$(CRATE_ID)]::prusti_pre_item_test15_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:41 ~ composite[$(CRATE_ID)]::test16), kind: Inherent(Impure), pres: Inherent([DefId(0:38 ~ composite[$(CRATE_ID)]::prusti_pre_item_test16_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:44 ~ composite[$(CRATE_ID)]::test17), kind: Inherent(Impure), pres: Inherent([DefId(0:42 ~ composite[$(CRATE_ID)]::prusti_pre_item_test17_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:47 ~ composite[$(CRATE_ID)]::test19), kind: Inherent(Impure), pres: Inherent([DefId(0:45 ~ composite[$(CRATE_ID)]::prusti_pre_item_test19_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:50 ~ composite[$(CRATE_ID)]::test20), kind: Inherent(Impure), pres: Inherent([DefId(0:48 ~ composite[$(CRATE_ID)]::prusti_pre_item_test20_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:53 ~ composite[$(CRATE_ID)]::test21), kind: Inherent(Impure), pres: Inherent([DefId(0:51 ~ composite[$(CRATE_ID)]::prusti_pre_item_test21_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:56 ~ composite[$(CRATE_ID)]::test22), kind: Inherent(Impure), pres: Inherent([DefId(0:54 ~ composite[$(CRATE_ID)]::prusti_pre_item_test22_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:60 ~ composite[$(CRATE_ID)]::test23), kind: Inherent(Impure), pres: Inherent([DefId(0:57 ~ composite[$(CRATE_ID)]::prusti_pre_item_test23_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:62 ~ composite[$(CRATE_ID)]::test24), kind: Inherent(Impure), pres: Inherent([DefId(0:61 ~ composite[$(CRATE_ID)]::prusti_pre_item_test24_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:66 ~ composite[$(CRATE_ID)]::test25), kind: Inherent(Impure), pres: Inherent([DefId(0:63 ~ composite[$(CRATE_ID)]::prusti_pre_item_test25_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:70 ~ composite[$(CRATE_ID)]::test26), kind: Inherent(Impure), pres: Inherent([DefId(0:67 ~ composite[$(CRATE_ID)]::prusti_pre_item_test26_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } +ProcedureSpecification { source: DefId(0:6 ~ composite[$(CRATE_ID)]::test1), kind: Inherent(Impure), pres: Inherent([DefId(0:5 ~ composite[$(CRATE_ID)]::prusti_pre_item_test1_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:8 ~ composite[$(CRATE_ID)]::test2), kind: Inherent(Impure), pres: Inherent([DefId(0:7 ~ composite[$(CRATE_ID)]::prusti_pre_item_test2_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:10 ~ composite[$(CRATE_ID)]::test3), kind: Inherent(Impure), pres: Inherent([DefId(0:9 ~ composite[$(CRATE_ID)]::prusti_pre_item_test3_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:12 ~ composite[$(CRATE_ID)]::test4), kind: Inherent(Impure), pres: Inherent([DefId(0:11 ~ composite[$(CRATE_ID)]::prusti_pre_item_test4_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:14 ~ composite[$(CRATE_ID)]::test5), kind: Inherent(Impure), pres: Inherent([DefId(0:13 ~ composite[$(CRATE_ID)]::prusti_pre_item_test5_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:16 ~ composite[$(CRATE_ID)]::test6), kind: Inherent(Impure), pres: Inherent([DefId(0:15 ~ composite[$(CRATE_ID)]::prusti_pre_item_test6_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:18 ~ composite[$(CRATE_ID)]::test7), kind: Inherent(Impure), pres: Inherent([DefId(0:17 ~ composite[$(CRATE_ID)]::prusti_pre_item_test7_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:20 ~ composite[$(CRATE_ID)]::test8), kind: Inherent(Impure), pres: Inherent([DefId(0:19 ~ composite[$(CRATE_ID)]::prusti_pre_item_test8_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:22 ~ composite[$(CRATE_ID)]::test9), kind: Inherent(Impure), pres: Inherent([DefId(0:21 ~ composite[$(CRATE_ID)]::prusti_pre_item_test9_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:25 ~ composite[$(CRATE_ID)]::test10), kind: Inherent(Impure), pres: Inherent([DefId(0:23 ~ composite[$(CRATE_ID)]::prusti_pre_item_test10_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:28 ~ composite[$(CRATE_ID)]::test12), kind: Inherent(Impure), pres: Inherent([DefId(0:26 ~ composite[$(CRATE_ID)]::prusti_pre_item_test12_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:31 ~ composite[$(CRATE_ID)]::test13), kind: Inherent(Impure), pres: Inherent([DefId(0:29 ~ composite[$(CRATE_ID)]::prusti_pre_item_test13_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:34 ~ composite[$(CRATE_ID)]::test14), kind: Inherent(Impure), pres: Inherent([DefId(0:32 ~ composite[$(CRATE_ID)]::prusti_pre_item_test14_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:37 ~ composite[$(CRATE_ID)]::test15), kind: Inherent(Impure), pres: Inherent([DefId(0:35 ~ composite[$(CRATE_ID)]::prusti_pre_item_test15_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:41 ~ composite[$(CRATE_ID)]::test16), kind: Inherent(Impure), pres: Inherent([DefId(0:38 ~ composite[$(CRATE_ID)]::prusti_pre_item_test16_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:44 ~ composite[$(CRATE_ID)]::test17), kind: Inherent(Impure), pres: Inherent([DefId(0:42 ~ composite[$(CRATE_ID)]::prusti_pre_item_test17_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:47 ~ composite[$(CRATE_ID)]::test19), kind: Inherent(Impure), pres: Inherent([DefId(0:45 ~ composite[$(CRATE_ID)]::prusti_pre_item_test19_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:50 ~ composite[$(CRATE_ID)]::test20), kind: Inherent(Impure), pres: Inherent([DefId(0:48 ~ composite[$(CRATE_ID)]::prusti_pre_item_test20_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:53 ~ composite[$(CRATE_ID)]::test21), kind: Inherent(Impure), pres: Inherent([DefId(0:51 ~ composite[$(CRATE_ID)]::prusti_pre_item_test21_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:56 ~ composite[$(CRATE_ID)]::test22), kind: Inherent(Impure), pres: Inherent([DefId(0:54 ~ composite[$(CRATE_ID)]::prusti_pre_item_test22_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:60 ~ composite[$(CRATE_ID)]::test23), kind: Inherent(Impure), pres: Inherent([DefId(0:57 ~ composite[$(CRATE_ID)]::prusti_pre_item_test23_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:62 ~ composite[$(CRATE_ID)]::test24), kind: Inherent(Impure), pres: Inherent([DefId(0:61 ~ composite[$(CRATE_ID)]::prusti_pre_item_test24_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:66 ~ composite[$(CRATE_ID)]::test25), kind: Inherent(Impure), pres: Inherent([DefId(0:63 ~ composite[$(CRATE_ID)]::prusti_pre_item_test25_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:70 ~ composite[$(CRATE_ID)]::test26), kind: Inherent(Impure), pres: Inherent([DefId(0:67 ~ composite[$(CRATE_ID)]::prusti_pre_item_test26_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } diff --git a/prusti-tests/tests/parse/ui/exists.stdout b/prusti-tests/tests/parse/ui/exists.stdout index c524a069795..65b45f7a091 100644 --- a/prusti-tests/tests/parse/ui/exists.stdout +++ b/prusti-tests/tests/parse/ui/exists.stdout @@ -38,7 +38,7 @@ fn prusti_pre_item_test2_$(NUM_UUID)() -> bool { !!((exists((), #[prusti::spec_only] |a: i32, b: i32| -> bool { - (((a + b == a + b && true) == (a + b == a + b)): bool) + ((((a + b == a + b) && (true)) == (a + b == a + b)): bool) })): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] @@ -61,7 +61,7 @@ fn test3() {} #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test4_$(NUM_UUID)() -> bool { !!((exists(((#[prusti::spec_only] |a: i32| (1), - #[prusti::spec_only] |a: i32| (2 == 2 && true)),), + #[prusti::spec_only] |a: i32| ((2 == 2) && (true))),), #[prusti::spec_only] |a: i32| -> bool { ((a + a == a + a): bool) })): bool) } @@ -99,9 +99,9 @@ fn prusti_pre_item_test6_$(NUM_UUID)() -> bool { #[prusti::specs_version = $(SPECS_VERSION)] fn test6() {} fn main() {} -ProcedureSpecification { source: DefId(0:7 ~ exists[$(CRATE_ID)]::test1), kind: Inherent(Impure), pres: Inherent([DefId(0:5 ~ exists[$(CRATE_ID)]::prusti_pre_item_test1_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:10 ~ exists[$(CRATE_ID)]::test2), kind: Inherent(Impure), pres: Inherent([DefId(0:8 ~ exists[$(CRATE_ID)]::prusti_pre_item_test2_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:13 ~ exists[$(CRATE_ID)]::test3), kind: Inherent(Impure), pres: Inherent([DefId(0:11 ~ exists[$(CRATE_ID)]::prusti_pre_item_test3_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:18 ~ exists[$(CRATE_ID)]::test4), kind: Inherent(Impure), pres: Inherent([DefId(0:14 ~ exists[$(CRATE_ID)]::prusti_pre_item_test4_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:24 ~ exists[$(CRATE_ID)]::test5), kind: Inherent(Impure), pres: Inherent([DefId(0:19 ~ exists[$(CRATE_ID)]::prusti_pre_item_test5_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:33 ~ exists[$(CRATE_ID)]::test6), kind: Inherent(Impure), pres: Inherent([DefId(0:25 ~ exists[$(CRATE_ID)]::prusti_pre_item_test6_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } +ProcedureSpecification { source: DefId(0:7 ~ exists[$(CRATE_ID)]::test1), kind: Inherent(Impure), pres: Inherent([DefId(0:5 ~ exists[$(CRATE_ID)]::prusti_pre_item_test1_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:10 ~ exists[$(CRATE_ID)]::test2), kind: Inherent(Impure), pres: Inherent([DefId(0:8 ~ exists[$(CRATE_ID)]::prusti_pre_item_test2_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:13 ~ exists[$(CRATE_ID)]::test3), kind: Inherent(Impure), pres: Inherent([DefId(0:11 ~ exists[$(CRATE_ID)]::prusti_pre_item_test3_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:18 ~ exists[$(CRATE_ID)]::test4), kind: Inherent(Impure), pres: Inherent([DefId(0:14 ~ exists[$(CRATE_ID)]::prusti_pre_item_test4_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:24 ~ exists[$(CRATE_ID)]::test5), kind: Inherent(Impure), pres: Inherent([DefId(0:19 ~ exists[$(CRATE_ID)]::prusti_pre_item_test5_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:33 ~ exists[$(CRATE_ID)]::test6), kind: Inherent(Impure), pres: Inherent([DefId(0:25 ~ exists[$(CRATE_ID)]::prusti_pre_item_test6_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } diff --git a/prusti-tests/tests/parse/ui/expression.stdout b/prusti-tests/tests/parse/ui/expression.stdout index 0e7bbc77f6e..421486483a7 100644 --- a/prusti-tests/tests/parse/ui/expression.stdout +++ b/prusti-tests/tests/parse/ui/expression.stdout @@ -20,7 +20,7 @@ use prusti_contracts::*; #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test1_$(NUM_UUID)() -> bool { - !!((1 == 1 && 1 != 2): bool) + !!(((1 == 1) && (1 != 2)): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -30,11 +30,11 @@ fn test1() {} #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_post_item_test2_$(NUM_UUID)(result: ()) -> bool { - !!((1 == 1 || 1 == 2): bool) + !!(((1 == 1) || (1 == 2)): bool) } #[prusti::post_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] fn test2() {} fn main() {} -ProcedureSpecification { source: DefId(0:6 ~ expression[$(CRATE_ID)]::test1), kind: Inherent(Impure), pres: Inherent([DefId(0:5 ~ expression[$(CRATE_ID)]::prusti_pre_item_test1_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:8 ~ expression[$(CRATE_ID)]::test2), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:7 ~ expression[$(CRATE_ID)]::prusti_post_item_test2_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } +ProcedureSpecification { source: DefId(0:6 ~ expression[$(CRATE_ID)]::test1), kind: Inherent(Impure), pres: Inherent([DefId(0:5 ~ expression[$(CRATE_ID)]::prusti_pre_item_test1_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:8 ~ expression[$(CRATE_ID)]::test2), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:7 ~ expression[$(CRATE_ID)]::prusti_post_item_test2_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } diff --git a/prusti-tests/tests/parse/ui/forall.stdout b/prusti-tests/tests/parse/ui/forall.stdout index 69fddf77980..e1ecb7f4782 100644 --- a/prusti-tests/tests/parse/ui/forall.stdout +++ b/prusti-tests/tests/parse/ui/forall.stdout @@ -38,7 +38,7 @@ fn prusti_pre_item_test2_$(NUM_UUID)() -> bool { !!((forall((), #[prusti::spec_only] |a: i32, b: i32| -> bool { - (((a + b == a + b && true) == (a + b == a + b)): bool) + ((((a + b == a + b) && (true)) == (a + b == a + b)): bool) })): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] @@ -61,7 +61,7 @@ fn test3() {} #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test4_$(NUM_UUID)() -> bool { !!((forall(((#[prusti::spec_only] |a: i32| (1), - #[prusti::spec_only] |a: i32| (2 == 2 && true)),), + #[prusti::spec_only] |a: i32| ((2 == 2) && (true))),), #[prusti::spec_only] |a: i32| -> bool { ((a + a == a + a): bool) })): bool) } @@ -99,9 +99,9 @@ fn prusti_pre_item_test6_$(NUM_UUID)() -> bool { #[prusti::specs_version = $(SPECS_VERSION)] fn test6() {} fn main() {} -ProcedureSpecification { source: DefId(0:7 ~ forall[$(CRATE_ID)]::test1), kind: Inherent(Impure), pres: Inherent([DefId(0:5 ~ forall[$(CRATE_ID)]::prusti_pre_item_test1_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:10 ~ forall[$(CRATE_ID)]::test2), kind: Inherent(Impure), pres: Inherent([DefId(0:8 ~ forall[$(CRATE_ID)]::prusti_pre_item_test2_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:13 ~ forall[$(CRATE_ID)]::test3), kind: Inherent(Impure), pres: Inherent([DefId(0:11 ~ forall[$(CRATE_ID)]::prusti_pre_item_test3_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:18 ~ forall[$(CRATE_ID)]::test4), kind: Inherent(Impure), pres: Inherent([DefId(0:14 ~ forall[$(CRATE_ID)]::prusti_pre_item_test4_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:24 ~ forall[$(CRATE_ID)]::test5), kind: Inherent(Impure), pres: Inherent([DefId(0:19 ~ forall[$(CRATE_ID)]::prusti_pre_item_test5_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:33 ~ forall[$(CRATE_ID)]::test6), kind: Inherent(Impure), pres: Inherent([DefId(0:25 ~ forall[$(CRATE_ID)]::prusti_pre_item_test6_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } +ProcedureSpecification { source: DefId(0:7 ~ forall[$(CRATE_ID)]::test1), kind: Inherent(Impure), pres: Inherent([DefId(0:5 ~ forall[$(CRATE_ID)]::prusti_pre_item_test1_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:10 ~ forall[$(CRATE_ID)]::test2), kind: Inherent(Impure), pres: Inherent([DefId(0:8 ~ forall[$(CRATE_ID)]::prusti_pre_item_test2_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:13 ~ forall[$(CRATE_ID)]::test3), kind: Inherent(Impure), pres: Inherent([DefId(0:11 ~ forall[$(CRATE_ID)]::prusti_pre_item_test3_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:18 ~ forall[$(CRATE_ID)]::test4), kind: Inherent(Impure), pres: Inherent([DefId(0:14 ~ forall[$(CRATE_ID)]::prusti_pre_item_test4_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:24 ~ forall[$(CRATE_ID)]::test5), kind: Inherent(Impure), pres: Inherent([DefId(0:19 ~ forall[$(CRATE_ID)]::prusti_pre_item_test5_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:33 ~ forall[$(CRATE_ID)]::test6), kind: Inherent(Impure), pres: Inherent([DefId(0:25 ~ forall[$(CRATE_ID)]::prusti_pre_item_test6_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } diff --git a/prusti-tests/tests/parse/ui/implies.stdout b/prusti-tests/tests/parse/ui/implies.stdout index 3c9194c4b73..4caacc7707f 100644 --- a/prusti-tests/tests/parse/ui/implies.stdout +++ b/prusti-tests/tests/parse/ui/implies.stdout @@ -115,13 +115,13 @@ fn prusti_pre_item_test25_$(NUM_UUID)() -> bool { #[prusti::specs_version = $(SPECS_VERSION)] fn test25() {} fn main() {} -ProcedureSpecification { source: DefId(0:6 ~ implies[$(CRATE_ID)]::test1), kind: Inherent(Impure), pres: Inherent([DefId(0:5 ~ implies[$(CRATE_ID)]::prusti_pre_item_test1_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:8 ~ implies[$(CRATE_ID)]::test2), kind: Inherent(Impure), pres: Inherent([DefId(0:7 ~ implies[$(CRATE_ID)]::prusti_pre_item_test2_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:10 ~ implies[$(CRATE_ID)]::test3), kind: Inherent(Impure), pres: Inherent([DefId(0:9 ~ implies[$(CRATE_ID)]::prusti_pre_item_test3_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:12 ~ implies[$(CRATE_ID)]::test4), kind: Inherent(Impure), pres: Inherent([DefId(0:11 ~ implies[$(CRATE_ID)]::prusti_pre_item_test4_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:14 ~ implies[$(CRATE_ID)]::test5), kind: Inherent(Impure), pres: Inherent([DefId(0:13 ~ implies[$(CRATE_ID)]::prusti_pre_item_test5_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:16 ~ implies[$(CRATE_ID)]::test21), kind: Inherent(Impure), pres: Inherent([DefId(0:15 ~ implies[$(CRATE_ID)]::prusti_pre_item_test21_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:18 ~ implies[$(CRATE_ID)]::test22), kind: Inherent(Impure), pres: Inherent([DefId(0:17 ~ implies[$(CRATE_ID)]::prusti_pre_item_test22_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:20 ~ implies[$(CRATE_ID)]::test23), kind: Inherent(Impure), pres: Inherent([DefId(0:19 ~ implies[$(CRATE_ID)]::prusti_pre_item_test23_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:22 ~ implies[$(CRATE_ID)]::test24), kind: Inherent(Impure), pres: Inherent([DefId(0:21 ~ implies[$(CRATE_ID)]::prusti_pre_item_test24_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:24 ~ implies[$(CRATE_ID)]::test25), kind: Inherent(Impure), pres: Inherent([DefId(0:23 ~ implies[$(CRATE_ID)]::prusti_pre_item_test25_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } +ProcedureSpecification { source: DefId(0:6 ~ implies[$(CRATE_ID)]::test1), kind: Inherent(Impure), pres: Inherent([DefId(0:5 ~ implies[$(CRATE_ID)]::prusti_pre_item_test1_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:8 ~ implies[$(CRATE_ID)]::test2), kind: Inherent(Impure), pres: Inherent([DefId(0:7 ~ implies[$(CRATE_ID)]::prusti_pre_item_test2_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:10 ~ implies[$(CRATE_ID)]::test3), kind: Inherent(Impure), pres: Inherent([DefId(0:9 ~ implies[$(CRATE_ID)]::prusti_pre_item_test3_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:12 ~ implies[$(CRATE_ID)]::test4), kind: Inherent(Impure), pres: Inherent([DefId(0:11 ~ implies[$(CRATE_ID)]::prusti_pre_item_test4_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:14 ~ implies[$(CRATE_ID)]::test5), kind: Inherent(Impure), pres: Inherent([DefId(0:13 ~ implies[$(CRATE_ID)]::prusti_pre_item_test5_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:16 ~ implies[$(CRATE_ID)]::test21), kind: Inherent(Impure), pres: Inherent([DefId(0:15 ~ implies[$(CRATE_ID)]::prusti_pre_item_test21_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:18 ~ implies[$(CRATE_ID)]::test22), kind: Inherent(Impure), pres: Inherent([DefId(0:17 ~ implies[$(CRATE_ID)]::prusti_pre_item_test22_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:20 ~ implies[$(CRATE_ID)]::test23), kind: Inherent(Impure), pres: Inherent([DefId(0:19 ~ implies[$(CRATE_ID)]::prusti_pre_item_test23_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:22 ~ implies[$(CRATE_ID)]::test24), kind: Inherent(Impure), pres: Inherent([DefId(0:21 ~ implies[$(CRATE_ID)]::prusti_pre_item_test24_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:24 ~ implies[$(CRATE_ID)]::test25), kind: Inherent(Impure), pres: Inherent([DefId(0:23 ~ implies[$(CRATE_ID)]::prusti_pre_item_test25_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } diff --git a/prusti-tests/tests/parse/ui/predicates-visibility.stdout b/prusti-tests/tests/parse/ui/predicates-visibility.stdout index d70deca0a96..177fe3e688d 100644 --- a/prusti-tests/tests/parse/ui/predicates-visibility.stdout +++ b/prusti-tests/tests/parse/ui/predicates-visibility.stdout @@ -48,5 +48,5 @@ fn prusti_pre_item_test_pub_pred_$(NUM_UUID)() -> bool { #[prusti::specs_version = $(SPECS_VERSION)] fn test_pub_pred() {} fn main() {} -ProcedureSpecification { source: DefId(0:15 ~ predicates_visibility[$(CRATE_ID)]::foo::pred1), kind: Inherent(Predicate(Some(DefId(0:13 ~ predicates_visibility[$(CRATE_ID)]::foo::prusti_pred_item_pred1_$(NUM_UUID))))), pres: Empty, posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:17 ~ predicates_visibility[$(CRATE_ID)]::test_pub_pred), kind: Inherent(Impure), pres: Inherent([DefId(0:16 ~ predicates_visibility[$(CRATE_ID)]::prusti_pre_item_test_pub_pred_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } +ProcedureSpecification { source: DefId(0:15 ~ predicates_visibility[$(CRATE_ID)]::foo::pred1), kind: Inherent(Predicate(Some(DefId(0:13 ~ predicates_visibility[$(CRATE_ID)]::foo::prusti_pred_item_pred1_$(NUM_UUID))))), pres: Empty, posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:17 ~ predicates_visibility[$(CRATE_ID)]::test_pub_pred), kind: Inherent(Impure), pres: Inherent([DefId(0:16 ~ predicates_visibility[$(CRATE_ID)]::prusti_pre_item_test_pub_pred_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } diff --git a/prusti-tests/tests/parse/ui/predicates.stdout b/prusti-tests/tests/parse/ui/predicates.stdout index 93238683022..756b4bc5ad7 100644 --- a/prusti-tests/tests/parse/ui/predicates.stdout +++ b/prusti-tests/tests/parse/ui/predicates.stdout @@ -107,9 +107,9 @@ fn exists_implication() -> bool { &[]))])) } fn main() {} -ProcedureSpecification { source: DefId(0:7 ~ predicates[$(CRATE_ID)]::pred1), kind: Inherent(Predicate(Some(DefId(0:5 ~ predicates[$(CRATE_ID)]::prusti_pred_item_pred1_$(NUM_UUID))))), pres: Empty, posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:12 ~ predicates[$(CRATE_ID)]::pred2), kind: Inherent(Predicate(Some(DefId(0:10 ~ predicates[$(CRATE_ID)]::prusti_pred_item_pred2_$(NUM_UUID))))), pres: Empty, posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:9 ~ predicates[$(CRATE_ID)]::use_pred1), kind: Inherent(Impure), pres: Inherent([DefId(0:8 ~ predicates[$(CRATE_ID)]::prusti_pre_item_use_pred1_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:14 ~ predicates[$(CRATE_ID)]::use_pred2), kind: Inherent(Impure), pres: Inherent([DefId(0:13 ~ predicates[$(CRATE_ID)]::prusti_pre_item_use_pred2_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:17 ~ predicates[$(CRATE_ID)]::forall_implication), kind: Inherent(Predicate(Some(DefId(0:15 ~ predicates[$(CRATE_ID)]::prusti_pred_item_forall_implication_$(NUM_UUID))))), pres: Empty, posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:20 ~ predicates[$(CRATE_ID)]::exists_implication), kind: Inherent(Predicate(Some(DefId(0:18 ~ predicates[$(CRATE_ID)]::prusti_pred_item_exists_implication_$(NUM_UUID))))), pres: Empty, posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } +ProcedureSpecification { source: DefId(0:7 ~ predicates[$(CRATE_ID)]::pred1), kind: Inherent(Predicate(Some(DefId(0:5 ~ predicates[$(CRATE_ID)]::prusti_pred_item_pred1_$(NUM_UUID))))), pres: Empty, posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:12 ~ predicates[$(CRATE_ID)]::pred2), kind: Inherent(Predicate(Some(DefId(0:10 ~ predicates[$(CRATE_ID)]::prusti_pred_item_pred2_$(NUM_UUID))))), pres: Empty, posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:9 ~ predicates[$(CRATE_ID)]::use_pred1), kind: Inherent(Impure), pres: Inherent([DefId(0:8 ~ predicates[$(CRATE_ID)]::prusti_pre_item_use_pred1_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:14 ~ predicates[$(CRATE_ID)]::use_pred2), kind: Inherent(Impure), pres: Inherent([DefId(0:13 ~ predicates[$(CRATE_ID)]::prusti_pre_item_use_pred2_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:17 ~ predicates[$(CRATE_ID)]::forall_implication), kind: Inherent(Predicate(Some(DefId(0:15 ~ predicates[$(CRATE_ID)]::prusti_pred_item_forall_implication_$(NUM_UUID))))), pres: Empty, posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:20 ~ predicates[$(CRATE_ID)]::exists_implication), kind: Inherent(Predicate(Some(DefId(0:18 ~ predicates[$(CRATE_ID)]::prusti_pred_item_exists_implication_$(NUM_UUID))))), pres: Empty, posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } diff --git a/prusti-tests/tests/parse/ui/trait-bounds.stdout b/prusti-tests/tests/parse/ui/trait-bounds.stdout index 677aac613ee..c6a3c5fce5d 100644 --- a/prusti-tests/tests/parse/ui/trait-bounds.stdout +++ b/prusti-tests/tests/parse/ui/trait-bounds.stdout @@ -46,4 +46,4 @@ impl<'a, T: PartialEq, const L : usize> } } fn main() {} -ProcedureSpecification { source: DefId(0:31 ~ trait_bounds[$(CRATE_ID)]::{impl#1}::bar), kind: Inherent(Pure), pres: Empty, posts: Inherent([DefId(0:29 ~ trait_bounds[$(CRATE_ID)]::{impl#1}::prusti_post_item_bar_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(true), terminates: Inherent(None) } +ProcedureSpecification { source: DefId(0:31 ~ trait_bounds[$(CRATE_ID)]::{impl#1}::bar), kind: Inherent(Pure), pres: Empty, posts: Inherent([DefId(0:29 ~ trait_bounds[$(CRATE_ID)]::{impl#1}::prusti_post_item_bar_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(true), terminates: Inherent(None), purity: Inherent(None) } diff --git a/prusti-tests/tests/parse/ui/traits.stdout b/prusti-tests/tests/parse/ui/traits.stdout index a40808d6815..79e650f08bd 100644 --- a/prusti-tests/tests/parse/ui/traits.stdout +++ b/prusti-tests/tests/parse/ui/traits.stdout @@ -187,15 +187,15 @@ trait Test4 { fn test2(&self); } fn main() {} -ProcedureSpecification { source: DefId(0:10 ~ traits[$(CRATE_ID)]::Test1::test1), kind: Inherent(Impure), pres: Inherent([DefId(0:9 ~ traits[$(CRATE_ID)]::Test1::prusti_pre_item_test1_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:14 ~ traits[$(CRATE_ID)]::Test1::test3), kind: Inherent(Impure), pres: Inherent([DefId(0:13 ~ traits[$(CRATE_ID)]::Test1::prusti_pre_item_test3_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:24 ~ traits[$(CRATE_ID)]::Test3::test1), kind: Inherent(Impure), pres: Inherent([DefId(0:23 ~ traits[$(CRATE_ID)]::Test3::prusti_pre_item_test1_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:28 ~ traits[$(CRATE_ID)]::Test3::test3), kind: Inherent(Impure), pres: Inherent([DefId(0:27 ~ traits[$(CRATE_ID)]::Test3::prusti_pre_item_test3_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:12 ~ traits[$(CRATE_ID)]::Test1::test2), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:11 ~ traits[$(CRATE_ID)]::Test1::prusti_post_item_test2_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:16 ~ traits[$(CRATE_ID)]::Test1::test4), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:15 ~ traits[$(CRATE_ID)]::Test1::prusti_post_item_test4_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:26 ~ traits[$(CRATE_ID)]::Test3::test2), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:25 ~ traits[$(CRATE_ID)]::Test3::prusti_post_item_test2_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:30 ~ traits[$(CRATE_ID)]::Test3::test4), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:29 ~ traits[$(CRATE_ID)]::Test3::prusti_post_item_test4_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:19 ~ traits[$(CRATE_ID)]::Test2::test1), kind: Inherent(Impure), pres: Inherent([DefId(0:17 ~ traits[$(CRATE_ID)]::Test2::prusti_pre_item_test1_$(NUM_UUID))]), posts: Inherent([DefId(0:18 ~ traits[$(CRATE_ID)]::Test2::prusti_post_item_test1_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:22 ~ traits[$(CRATE_ID)]::Test2::test2), kind: Inherent(Impure), pres: Inherent([DefId(0:20 ~ traits[$(CRATE_ID)]::Test2::prusti_pre_item_test2_$(NUM_UUID))]), posts: Inherent([DefId(0:21 ~ traits[$(CRATE_ID)]::Test2::prusti_post_item_test2_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:33 ~ traits[$(CRATE_ID)]::Test4::test1), kind: Inherent(Impure), pres: Inherent([DefId(0:31 ~ traits[$(CRATE_ID)]::Test4::prusti_pre_item_test1_$(NUM_UUID))]), posts: Inherent([DefId(0:32 ~ traits[$(CRATE_ID)]::Test4::prusti_post_item_test1_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:36 ~ traits[$(CRATE_ID)]::Test4::test2), kind: Inherent(Impure), pres: Inherent([DefId(0:34 ~ traits[$(CRATE_ID)]::Test4::prusti_pre_item_test2_$(NUM_UUID))]), posts: Inherent([DefId(0:35 ~ traits[$(CRATE_ID)]::Test4::prusti_post_item_test2_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } +ProcedureSpecification { source: DefId(0:10 ~ traits[$(CRATE_ID)]::Test1::test1), kind: Inherent(Impure), pres: Inherent([DefId(0:9 ~ traits[$(CRATE_ID)]::Test1::prusti_pre_item_test1_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:14 ~ traits[$(CRATE_ID)]::Test1::test3), kind: Inherent(Impure), pres: Inherent([DefId(0:13 ~ traits[$(CRATE_ID)]::Test1::prusti_pre_item_test3_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:24 ~ traits[$(CRATE_ID)]::Test3::test1), kind: Inherent(Impure), pres: Inherent([DefId(0:23 ~ traits[$(CRATE_ID)]::Test3::prusti_pre_item_test1_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:28 ~ traits[$(CRATE_ID)]::Test3::test3), kind: Inherent(Impure), pres: Inherent([DefId(0:27 ~ traits[$(CRATE_ID)]::Test3::prusti_pre_item_test3_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:12 ~ traits[$(CRATE_ID)]::Test1::test2), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:11 ~ traits[$(CRATE_ID)]::Test1::prusti_post_item_test2_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:16 ~ traits[$(CRATE_ID)]::Test1::test4), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:15 ~ traits[$(CRATE_ID)]::Test1::prusti_post_item_test4_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:26 ~ traits[$(CRATE_ID)]::Test3::test2), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:25 ~ traits[$(CRATE_ID)]::Test3::prusti_post_item_test2_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:30 ~ traits[$(CRATE_ID)]::Test3::test4), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:29 ~ traits[$(CRATE_ID)]::Test3::prusti_post_item_test4_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:19 ~ traits[$(CRATE_ID)]::Test2::test1), kind: Inherent(Impure), pres: Inherent([DefId(0:17 ~ traits[$(CRATE_ID)]::Test2::prusti_pre_item_test1_$(NUM_UUID))]), posts: Inherent([DefId(0:18 ~ traits[$(CRATE_ID)]::Test2::prusti_post_item_test1_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:22 ~ traits[$(CRATE_ID)]::Test2::test2), kind: Inherent(Impure), pres: Inherent([DefId(0:20 ~ traits[$(CRATE_ID)]::Test2::prusti_pre_item_test2_$(NUM_UUID))]), posts: Inherent([DefId(0:21 ~ traits[$(CRATE_ID)]::Test2::prusti_post_item_test2_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:33 ~ traits[$(CRATE_ID)]::Test4::test1), kind: Inherent(Impure), pres: Inherent([DefId(0:31 ~ traits[$(CRATE_ID)]::Test4::prusti_pre_item_test1_$(NUM_UUID))]), posts: Inherent([DefId(0:32 ~ traits[$(CRATE_ID)]::Test4::prusti_post_item_test1_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:36 ~ traits[$(CRATE_ID)]::Test4::test2), kind: Inherent(Impure), pres: Inherent([DefId(0:34 ~ traits[$(CRATE_ID)]::Test4::prusti_pre_item_test2_$(NUM_UUID))]), posts: Inherent([DefId(0:35 ~ traits[$(CRATE_ID)]::Test4::prusti_post_item_test2_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } diff --git a/prusti-tests/tests/parse/ui/true.stdout b/prusti-tests/tests/parse/ui/true.stdout index 0f138130841..9cd34c2cf72 100644 --- a/prusti-tests/tests/parse/ui/true.stdout +++ b/prusti-tests/tests/parse/ui/true.stdout @@ -90,6 +90,6 @@ fn test4() { fn main() {} Invariant(DefId(0:10 ~ true[$(CRATE_ID)]::test3::{closure#0})) Invariant(DefId(0:14 ~ true[$(CRATE_ID)]::test4::{closure#0})) -ProcedureSpecification { source: DefId(0:7 ~ true[$(CRATE_ID)]::test1), kind: Inherent(Impure), pres: Inherent([DefId(0:6 ~ true[$(CRATE_ID)]::prusti_pre_item_test1_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:9 ~ true[$(CRATE_ID)]::test2), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:8 ~ true[$(CRATE_ID)]::prusti_post_item_test2_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:13 ~ true[$(CRATE_ID)]::test4), kind: Inherent(Impure), pres: Inherent([DefId(0:11 ~ true[$(CRATE_ID)]::prusti_pre_item_test4_$(NUM_UUID))]), posts: Inherent([DefId(0:12 ~ true[$(CRATE_ID)]::prusti_post_item_test4_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } +ProcedureSpecification { source: DefId(0:7 ~ true[$(CRATE_ID)]::test1), kind: Inherent(Impure), pres: Inherent([DefId(0:6 ~ true[$(CRATE_ID)]::prusti_pre_item_test1_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:9 ~ true[$(CRATE_ID)]::test2), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:8 ~ true[$(CRATE_ID)]::prusti_post_item_test2_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:13 ~ true[$(CRATE_ID)]::test4), kind: Inherent(Impure), pres: Inherent([DefId(0:11 ~ true[$(CRATE_ID)]::prusti_pre_item_test4_$(NUM_UUID))]), posts: Inherent([DefId(0:12 ~ true[$(CRATE_ID)]::prusti_post_item_test4_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } diff --git a/prusti-tests/tests/parse/ui/trusted.stdout b/prusti-tests/tests/parse/ui/trusted.stdout index 71129ed2063..ee4abe3abf6 100644 --- a/prusti-tests/tests/parse/ui/trusted.stdout +++ b/prusti-tests/tests/parse/ui/trusted.stdout @@ -32,4 +32,4 @@ impl Test2<> { } fn main() {} TypeSpecification { source: DefId(0:7 ~ trusted[$(CRATE_ID)]::Test2), invariant: Inherent([]), trusted: Inherent(true), model: None, counterexample_print: [] } -ProcedureSpecification { source: DefId(0:5 ~ trusted[$(CRATE_ID)]::test1), kind: Inherent(Impure), pres: Empty, posts: Empty, pledges: Empty, trusted: Inherent(true), terminates: Inherent(None) } +ProcedureSpecification { source: DefId(0:5 ~ trusted[$(CRATE_ID)]::test1), kind: Inherent(Impure), pres: Empty, posts: Empty, pledges: Empty, trusted: Inherent(true), terminates: Inherent(None), purity: Inherent(None) } diff --git a/prusti-tests/tests/typecheck/ui/forall_encode_typeck.stdout b/prusti-tests/tests/typecheck/ui/forall_encode_typeck.stdout index e054ba1532b..1103e6022f8 100644 --- a/prusti-tests/tests/typecheck/ui/forall_encode_typeck.stdout +++ b/prusti-tests/tests/typecheck/ui/forall_encode_typeck.stdout @@ -43,5 +43,5 @@ fn prusti_pre_item_test2_$(NUM_UUID)() -> bool { #[prusti::specs_version = $(SPECS_VERSION)] fn test2() {} fn main() {} -ProcedureSpecification { source: DefId(0:10 ~ forall_encode_typeck[$(CRATE_ID)]::test1), kind: Inherent(Impure), pres: Inherent([DefId(0:5 ~ forall_encode_typeck[$(CRATE_ID)]::prusti_pre_item_test1_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:16 ~ forall_encode_typeck[$(CRATE_ID)]::test2), kind: Inherent(Impure), pres: Inherent([DefId(0:11 ~ forall_encode_typeck[$(CRATE_ID)]::prusti_pre_item_test2_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } +ProcedureSpecification { source: DefId(0:10 ~ forall_encode_typeck[$(CRATE_ID)]::test1), kind: Inherent(Impure), pres: Inherent([DefId(0:5 ~ forall_encode_typeck[$(CRATE_ID)]::prusti_pre_item_test1_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:16 ~ forall_encode_typeck[$(CRATE_ID)]::test2), kind: Inherent(Impure), pres: Inherent([DefId(0:11 ~ forall_encode_typeck[$(CRATE_ID)]::prusti_pre_item_test2_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } diff --git a/prusti-tests/tests/typecheck/ui/forall_triggers.stdout b/prusti-tests/tests/typecheck/ui/forall_triggers.stdout index cec8dc058de..d35799822a6 100644 --- a/prusti-tests/tests/typecheck/ui/forall_triggers.stdout +++ b/prusti-tests/tests/typecheck/ui/forall_triggers.stdout @@ -37,7 +37,7 @@ fn test1() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test2_$(NUM_UUID)() -> bool { - !!((forall(((#[prusti::spec_only] |a: i32| (a == a && true),),), + !!((forall(((#[prusti::spec_only] |a: i32| ((a == a) && (true)),),), #[prusti::spec_only] |a: i32| -> bool { ((forall((), @@ -67,7 +67,7 @@ fn test3() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test4_$(NUM_UUID)() -> bool { - !!((forall(((#[prusti::spec_only] |a: i32| (a == a && true),),), + !!((forall(((#[prusti::spec_only] |a: i32| ((a == a) && (true)),),), #[prusti::spec_only] |a: i32| -> bool { ((forall(((#[prusti::spec_only] |b: i32| (a == b),),), @@ -93,7 +93,7 @@ fn test5() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test6_$(NUM_UUID)() -> bool { - !!((exists(((#[prusti::spec_only] |a: i32| (a == a && true),),), + !!((exists(((#[prusti::spec_only] |a: i32| ((a == a) && (true)),),), #[prusti::spec_only] |a: i32| -> bool { ((exists((), @@ -123,7 +123,7 @@ fn test7() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test8_$(NUM_UUID)() -> bool { - !!((exists(((#[prusti::spec_only] |a: i32| (a == a && true),),), + !!((exists(((#[prusti::spec_only] |a: i32| ((a == a) && (true)),),), #[prusti::spec_only] |a: i32| -> bool { ((exists(((#[prusti::spec_only] |b: i32| (a == b),),), @@ -135,11 +135,11 @@ fn prusti_pre_item_test8_$(NUM_UUID)() -> bool { #[prusti::specs_version = $(SPECS_VERSION)] fn test8() {} fn main() {} -ProcedureSpecification { source: DefId(0:8 ~ forall_triggers[$(CRATE_ID)]::test1), kind: Inherent(Impure), pres: Inherent([DefId(0:5 ~ forall_triggers[$(CRATE_ID)]::prusti_pre_item_test1_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:13 ~ forall_triggers[$(CRATE_ID)]::test2), kind: Inherent(Impure), pres: Inherent([DefId(0:9 ~ forall_triggers[$(CRATE_ID)]::prusti_pre_item_test2_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:19 ~ forall_triggers[$(CRATE_ID)]::test3), kind: Inherent(Impure), pres: Inherent([DefId(0:14 ~ forall_triggers[$(CRATE_ID)]::prusti_pre_item_test3_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:25 ~ forall_triggers[$(CRATE_ID)]::test4), kind: Inherent(Impure), pres: Inherent([DefId(0:20 ~ forall_triggers[$(CRATE_ID)]::prusti_pre_item_test4_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:29 ~ forall_triggers[$(CRATE_ID)]::test5), kind: Inherent(Impure), pres: Inherent([DefId(0:26 ~ forall_triggers[$(CRATE_ID)]::prusti_pre_item_test5_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:34 ~ forall_triggers[$(CRATE_ID)]::test6), kind: Inherent(Impure), pres: Inherent([DefId(0:30 ~ forall_triggers[$(CRATE_ID)]::prusti_pre_item_test6_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:40 ~ forall_triggers[$(CRATE_ID)]::test7), kind: Inherent(Impure), pres: Inherent([DefId(0:35 ~ forall_triggers[$(CRATE_ID)]::prusti_pre_item_test7_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:46 ~ forall_triggers[$(CRATE_ID)]::test8), kind: Inherent(Impure), pres: Inherent([DefId(0:41 ~ forall_triggers[$(CRATE_ID)]::prusti_pre_item_test8_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } +ProcedureSpecification { source: DefId(0:8 ~ forall_triggers[$(CRATE_ID)]::test1), kind: Inherent(Impure), pres: Inherent([DefId(0:5 ~ forall_triggers[$(CRATE_ID)]::prusti_pre_item_test1_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:13 ~ forall_triggers[$(CRATE_ID)]::test2), kind: Inherent(Impure), pres: Inherent([DefId(0:9 ~ forall_triggers[$(CRATE_ID)]::prusti_pre_item_test2_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:19 ~ forall_triggers[$(CRATE_ID)]::test3), kind: Inherent(Impure), pres: Inherent([DefId(0:14 ~ forall_triggers[$(CRATE_ID)]::prusti_pre_item_test3_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:25 ~ forall_triggers[$(CRATE_ID)]::test4), kind: Inherent(Impure), pres: Inherent([DefId(0:20 ~ forall_triggers[$(CRATE_ID)]::prusti_pre_item_test4_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:29 ~ forall_triggers[$(CRATE_ID)]::test5), kind: Inherent(Impure), pres: Inherent([DefId(0:26 ~ forall_triggers[$(CRATE_ID)]::prusti_pre_item_test5_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:34 ~ forall_triggers[$(CRATE_ID)]::test6), kind: Inherent(Impure), pres: Inherent([DefId(0:30 ~ forall_triggers[$(CRATE_ID)]::prusti_pre_item_test6_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:40 ~ forall_triggers[$(CRATE_ID)]::test7), kind: Inherent(Impure), pres: Inherent([DefId(0:35 ~ forall_triggers[$(CRATE_ID)]::prusti_pre_item_test7_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:46 ~ forall_triggers[$(CRATE_ID)]::test8), kind: Inherent(Impure), pres: Inherent([DefId(0:41 ~ forall_triggers[$(CRATE_ID)]::prusti_pre_item_test8_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } diff --git a/prusti-tests/tests/typecheck/ui/nested_forall.stdout b/prusti-tests/tests/typecheck/ui/nested_forall.stdout index 99392d62a86..a2fc02dba9a 100644 --- a/prusti-tests/tests/typecheck/ui/nested_forall.stdout +++ b/prusti-tests/tests/typecheck/ui/nested_forall.stdout @@ -63,7 +63,7 @@ fn prusti_pre_item_test3_$(NUM_UUID)() -> bool { { ((forall((), #[prusti::spec_only] |c: i32| -> bool - { ((a == a && b == b): bool) })): bool) + { (((a == a) && (b == b)): bool) })): bool) })): bool) })): bool) } @@ -112,7 +112,7 @@ fn prusti_pre_item_test6_$(NUM_UUID)() -> bool { { ((exists((), #[prusti::spec_only] |c: i32| -> bool - { ((a == a && b == b): bool) })): bool) + { (((a == a) && (b == b)): bool) })): bool) })): bool) })): bool) } @@ -120,9 +120,9 @@ fn prusti_pre_item_test6_$(NUM_UUID)() -> bool { #[prusti::specs_version = $(SPECS_VERSION)] fn test6() {} fn main() {} -ProcedureSpecification { source: DefId(0:8 ~ nested_forall[$(CRATE_ID)]::test1), kind: Inherent(Impure), pres: Inherent([DefId(0:5 ~ nested_forall[$(CRATE_ID)]::prusti_pre_item_test1_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:12 ~ nested_forall[$(CRATE_ID)]::test2), kind: Inherent(Impure), pres: Inherent([DefId(0:9 ~ nested_forall[$(CRATE_ID)]::prusti_pre_item_test2_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:17 ~ nested_forall[$(CRATE_ID)]::test3), kind: Inherent(Impure), pres: Inherent([DefId(0:13 ~ nested_forall[$(CRATE_ID)]::prusti_pre_item_test3_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:21 ~ nested_forall[$(CRATE_ID)]::test4), kind: Inherent(Impure), pres: Inherent([DefId(0:18 ~ nested_forall[$(CRATE_ID)]::prusti_pre_item_test4_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:25 ~ nested_forall[$(CRATE_ID)]::test5), kind: Inherent(Impure), pres: Inherent([DefId(0:22 ~ nested_forall[$(CRATE_ID)]::prusti_pre_item_test5_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:30 ~ nested_forall[$(CRATE_ID)]::test6), kind: Inherent(Impure), pres: Inherent([DefId(0:26 ~ nested_forall[$(CRATE_ID)]::prusti_pre_item_test6_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } +ProcedureSpecification { source: DefId(0:8 ~ nested_forall[$(CRATE_ID)]::test1), kind: Inherent(Impure), pres: Inherent([DefId(0:5 ~ nested_forall[$(CRATE_ID)]::prusti_pre_item_test1_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:12 ~ nested_forall[$(CRATE_ID)]::test2), kind: Inherent(Impure), pres: Inherent([DefId(0:9 ~ nested_forall[$(CRATE_ID)]::prusti_pre_item_test2_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:17 ~ nested_forall[$(CRATE_ID)]::test3), kind: Inherent(Impure), pres: Inherent([DefId(0:13 ~ nested_forall[$(CRATE_ID)]::prusti_pre_item_test3_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:21 ~ nested_forall[$(CRATE_ID)]::test4), kind: Inherent(Impure), pres: Inherent([DefId(0:18 ~ nested_forall[$(CRATE_ID)]::prusti_pre_item_test4_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:25 ~ nested_forall[$(CRATE_ID)]::test5), kind: Inherent(Impure), pres: Inherent([DefId(0:22 ~ nested_forall[$(CRATE_ID)]::prusti_pre_item_test5_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:30 ~ nested_forall[$(CRATE_ID)]::test6), kind: Inherent(Impure), pres: Inherent([DefId(0:26 ~ nested_forall[$(CRATE_ID)]::prusti_pre_item_test6_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } diff --git a/prusti-tests/tests/verify/ui/calls.stdout b/prusti-tests/tests/verify/ui/calls.stdout index ee2ab8338df..31eb59cd5fc 100644 --- a/prusti-tests/tests/verify/ui/calls.stdout +++ b/prusti-tests/tests/verify/ui/calls.stdout @@ -29,14 +29,14 @@ use prusti_contracts::*; #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_post_item_max_$(NUM_UUID)(a: i32, b: i32, result: i32) -> bool { - !!((result == a || result == b): bool) + !!(((result == a) || (result == b)): bool) } #[allow(unused_must_use, unused_parens, unused_variables, dead_code)] #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_post_item_max_$(NUM_UUID)(a: i32, b: i32, result: i32) -> bool { - !!((result >= a && result >= b): bool) + !!(((result >= a) && (result >= b)): bool) } #[prusti::post_spec_id_ref = "$(NUM_UUID)"] #[prusti::post_spec_id_ref = "$(NUM_UUID)"] @@ -59,11 +59,12 @@ fn test_max2() { #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_post_item_test_max3_$(NUM_UUID)(result: i32) -> bool { - !!((true && ((!(true) || (result == 3))) && (true || false)): bool) + !!((((true) && (((!(true) || (result == 3))))) && (((true) || (false)))): + bool) } #[prusti::post_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] fn test_max3() -> i32 { let a = 4; let b = 3; max(a, b) } fn main() {} -ProcedureSpecification { source: DefId(0:11 ~ calls[$(CRATE_ID)]::test_max3), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:10 ~ calls[$(CRATE_ID)]::prusti_post_item_test_max3_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:9 ~ calls[$(CRATE_ID)]::max), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:7 ~ calls[$(CRATE_ID)]::prusti_post_item_max_$(NUM_UUID)), DefId(0:8 ~ calls[$(CRATE_ID)]::prusti_post_item_max_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } +ProcedureSpecification { source: DefId(0:11 ~ calls[$(CRATE_ID)]::test_max3), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:10 ~ calls[$(CRATE_ID)]::prusti_post_item_test_max3_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:9 ~ calls[$(CRATE_ID)]::max), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:7 ~ calls[$(CRATE_ID)]::prusti_post_item_max_$(NUM_UUID)), DefId(0:8 ~ calls[$(CRATE_ID)]::prusti_post_item_max_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } diff --git a/prusti-tests/tests/verify/ui/failing-postcondition.stderr b/prusti-tests/tests/verify/ui/failing-postcondition.stderr index a250b4a4545..8b0671f40fe 100644 --- a/prusti-tests/tests/verify/ui/failing-postcondition.stderr +++ b/prusti-tests/tests/verify/ui/failing-postcondition.stderr @@ -1,8 +1,8 @@ error: [Prusti: verification error] postcondition might not hold. - --> $DIR/failing-postcondition.rs:8:11 + --> $DIR/failing-postcondition.rs:8:28 | 8 | #[ensures(something_true() && false)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ | note: the error originates here --> $DIR/failing-postcondition.rs:9:1 diff --git a/prusti-tests/tests/verify/ui/false.stdout b/prusti-tests/tests/verify/ui/false.stdout index 17315b84015..64565180056 100644 --- a/prusti-tests/tests/verify/ui/false.stdout +++ b/prusti-tests/tests/verify/ui/false.stdout @@ -30,4 +30,4 @@ fn test2() { if !false { ::core::panicking::panic("assertion failed: false") }; } fn main() {} -ProcedureSpecification { source: DefId(0:7 ~ false[$(CRATE_ID)]::test1), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:6 ~ false[$(CRATE_ID)]::prusti_post_item_test1_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } +ProcedureSpecification { source: DefId(0:7 ~ false[$(CRATE_ID)]::test1), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:6 ~ false[$(CRATE_ID)]::prusti_post_item_test1_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } diff --git a/prusti-tests/tests/verify/ui/forall_verify.stdout b/prusti-tests/tests/verify/ui/forall_verify.stdout index 3046dea9192..3ba23dab2b1 100644 --- a/prusti-tests/tests/verify/ui/forall_verify.stdout +++ b/prusti-tests/tests/verify/ui/forall_verify.stdout @@ -107,10 +107,10 @@ fn prusti_post_item_test6_$(NUM_UUID)(result: ()) #[prusti::specs_version = $(SPECS_VERSION)] fn test6() {} fn main() {} -ProcedureSpecification { source: DefId(0:5 ~ forall_verify[$(CRATE_ID)]::identity), kind: Inherent(Pure), pres: Empty, posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:8 ~ forall_verify[$(CRATE_ID)]::test1), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:6 ~ forall_verify[$(CRATE_ID)]::prusti_post_item_test1_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:11 ~ forall_verify[$(CRATE_ID)]::test2), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:9 ~ forall_verify[$(CRATE_ID)]::prusti_post_item_test2_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:14 ~ forall_verify[$(CRATE_ID)]::test3), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:12 ~ forall_verify[$(CRATE_ID)]::prusti_post_item_test3_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:17 ~ forall_verify[$(CRATE_ID)]::test4), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:15 ~ forall_verify[$(CRATE_ID)]::prusti_post_item_test4_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:24 ~ forall_verify[$(CRATE_ID)]::test6), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:22 ~ forall_verify[$(CRATE_ID)]::prusti_post_item_test6_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:21 ~ forall_verify[$(CRATE_ID)]::test5), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:18 ~ forall_verify[$(CRATE_ID)]::prusti_post_item_test5_$(NUM_UUID)), DefId(0:19 ~ forall_verify[$(CRATE_ID)]::prusti_post_item_test5_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } +ProcedureSpecification { source: DefId(0:5 ~ forall_verify[$(CRATE_ID)]::identity), kind: Inherent(Pure), pres: Empty, posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:8 ~ forall_verify[$(CRATE_ID)]::test1), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:6 ~ forall_verify[$(CRATE_ID)]::prusti_post_item_test1_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:11 ~ forall_verify[$(CRATE_ID)]::test2), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:9 ~ forall_verify[$(CRATE_ID)]::prusti_post_item_test2_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:14 ~ forall_verify[$(CRATE_ID)]::test3), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:12 ~ forall_verify[$(CRATE_ID)]::prusti_post_item_test3_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:17 ~ forall_verify[$(CRATE_ID)]::test4), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:15 ~ forall_verify[$(CRATE_ID)]::prusti_post_item_test4_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:24 ~ forall_verify[$(CRATE_ID)]::test6), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:22 ~ forall_verify[$(CRATE_ID)]::prusti_post_item_test6_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:21 ~ forall_verify[$(CRATE_ID)]::test5), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:18 ~ forall_verify[$(CRATE_ID)]::prusti_post_item_test5_$(NUM_UUID)), DefId(0:19 ~ forall_verify[$(CRATE_ID)]::prusti_post_item_test5_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } diff --git a/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-1.stderr b/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-1.stderr index b38e9f5088f..d0770a95a9f 100644 --- a/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-1.stderr +++ b/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-1.stderr @@ -1,7 +1,7 @@ error: [Prusti: verification error] the method's precondition may not be a valid weakening of the trait's precondition. --> $DIR/invalid-trait-refinement-1.rs:16:31 | -16 | #[refine_spec(where Self: HasContract [ +16 | #[refine_spec(where Self: HasContract, [ | _______________________________^ 17 | | requires(self.pre()), ensures(self.post()) | |___________________________^ diff --git a/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-2.stderr b/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-2.stderr index bb5de7d704e..7218d1af1ad 100644 --- a/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-2.stderr +++ b/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-2.stderr @@ -1,7 +1,7 @@ error: [Prusti: verification error] the method's postcondition may not be a valid strengthening of the trait's postcondition. --> $DIR/invalid-trait-refinement-2.rs:16:31 | -16 | #[refine_spec(where Self: HasContract [ +16 | #[refine_spec(where Self: HasContract, [ | _______________________________^ 17 | | requires(self.pre()), ensures(self.post()) | |_________________________________________________^ diff --git a/prusti-tests/tests/verify/ui/pledges.stdout b/prusti-tests/tests/verify/ui/pledges.stdout index 152d63eaf78..9af80aaa9d8 100644 --- a/prusti-tests/tests/verify/ui/pledges.stdout +++ b/prusti-tests/tests/verify/ui/pledges.stdout @@ -65,4 +65,4 @@ fn reborrow_caller(a: T) { if !(a.f == 5) { ::core::panicking::panic("assertion failed: a.f == 5") }; } fn main() {} -ProcedureSpecification { source: DefId(0:14 ~ pledges[$(CRATE_ID)]::reborrow), kind: Inherent(Impure), pres: Empty, posts: Empty, pledges: Inherent([Pledge { reference: None, lhs: None, rhs: DefId(0:12 ~ pledges[$(CRATE_ID)]::prusti_pledge_item_reborrow_$(NUM_UUID)) }]), trusted: Inherent(false), terminates: Inherent(None) } +ProcedureSpecification { source: DefId(0:14 ~ pledges[$(CRATE_ID)]::reborrow), kind: Inherent(Impure), pres: Empty, posts: Empty, pledges: Inherent([Pledge { reference: None, lhs: None, rhs: DefId(0:12 ~ pledges[$(CRATE_ID)]::prusti_pledge_item_reborrow_$(NUM_UUID)) }]), trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } diff --git a/prusti-tests/tests/verify/ui/predicate.stdout b/prusti-tests/tests/verify/ui/predicate.stdout index 57bd6df3e00..202969b769f 100644 --- a/prusti-tests/tests/verify/ui/predicate.stdout +++ b/prusti-tests/tests/verify/ui/predicate.stdout @@ -149,7 +149,7 @@ fn false_p() -> bool { #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_precond_or_correctly_$(NUM_UUID)() -> bool { - !!((false_p() || true): bool) + !!(((false_p()) || (true)): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -162,12 +162,12 @@ fn main() { test_identity_2(); precond_or_correctly(); } -ProcedureSpecification { source: DefId(0:5 ~ predicate[$(CRATE_ID)]::identity), kind: Inherent(Pure), pres: Empty, posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:8 ~ predicate[$(CRATE_ID)]::true_p1), kind: Inherent(Predicate(Some(DefId(0:6 ~ predicate[$(CRATE_ID)]::prusti_pred_item_true_p1_$(NUM_UUID))))), pres: Empty, posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:11 ~ predicate[$(CRATE_ID)]::true_p2), kind: Inherent(Predicate(Some(DefId(0:9 ~ predicate[$(CRATE_ID)]::prusti_pred_item_true_p2_$(NUM_UUID))))), pres: Empty, posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:26 ~ predicate[$(CRATE_ID)]::false_p), kind: Inherent(Predicate(Some(DefId(0:25 ~ predicate[$(CRATE_ID)]::prusti_pred_item_false_p_$(NUM_UUID))))), pres: Empty, posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:14 ~ predicate[$(CRATE_ID)]::forall_identity), kind: Inherent(Predicate(Some(DefId(0:12 ~ predicate[$(CRATE_ID)]::prusti_pred_item_forall_identity_$(NUM_UUID))))), pres: Empty, posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:18 ~ predicate[$(CRATE_ID)]::exists_identity), kind: Inherent(Predicate(Some(DefId(0:15 ~ predicate[$(CRATE_ID)]::prusti_pred_item_exists_identity_$(NUM_UUID))))), pres: Empty, posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:28 ~ predicate[$(CRATE_ID)]::precond_or_correctly), kind: Inherent(Impure), pres: Inherent([DefId(0:27 ~ predicate[$(CRATE_ID)]::prusti_pre_item_precond_or_correctly_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:21 ~ predicate[$(CRATE_ID)]::test_identity_1), kind: Inherent(Impure), pres: Inherent([DefId(0:19 ~ predicate[$(CRATE_ID)]::prusti_pre_item_test_identity_1_$(NUM_UUID)), DefId(0:20 ~ predicate[$(CRATE_ID)]::prusti_pre_item_test_identity_1_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:24 ~ predicate[$(CRATE_ID)]::test_identity_2), kind: Inherent(Impure), pres: Inherent([DefId(0:22 ~ predicate[$(CRATE_ID)]::prusti_pre_item_test_identity_2_$(NUM_UUID)), DefId(0:23 ~ predicate[$(CRATE_ID)]::prusti_pre_item_test_identity_2_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } +ProcedureSpecification { source: DefId(0:5 ~ predicate[$(CRATE_ID)]::identity), kind: Inherent(Pure), pres: Empty, posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:8 ~ predicate[$(CRATE_ID)]::true_p1), kind: Inherent(Predicate(Some(DefId(0:6 ~ predicate[$(CRATE_ID)]::prusti_pred_item_true_p1_$(NUM_UUID))))), pres: Empty, posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:11 ~ predicate[$(CRATE_ID)]::true_p2), kind: Inherent(Predicate(Some(DefId(0:9 ~ predicate[$(CRATE_ID)]::prusti_pred_item_true_p2_$(NUM_UUID))))), pres: Empty, posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:26 ~ predicate[$(CRATE_ID)]::false_p), kind: Inherent(Predicate(Some(DefId(0:25 ~ predicate[$(CRATE_ID)]::prusti_pred_item_false_p_$(NUM_UUID))))), pres: Empty, posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:14 ~ predicate[$(CRATE_ID)]::forall_identity), kind: Inherent(Predicate(Some(DefId(0:12 ~ predicate[$(CRATE_ID)]::prusti_pred_item_forall_identity_$(NUM_UUID))))), pres: Empty, posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:18 ~ predicate[$(CRATE_ID)]::exists_identity), kind: Inherent(Predicate(Some(DefId(0:15 ~ predicate[$(CRATE_ID)]::prusti_pred_item_exists_identity_$(NUM_UUID))))), pres: Empty, posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:28 ~ predicate[$(CRATE_ID)]::precond_or_correctly), kind: Inherent(Impure), pres: Inherent([DefId(0:27 ~ predicate[$(CRATE_ID)]::prusti_pre_item_precond_or_correctly_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:21 ~ predicate[$(CRATE_ID)]::test_identity_1), kind: Inherent(Impure), pres: Inherent([DefId(0:19 ~ predicate[$(CRATE_ID)]::prusti_pre_item_test_identity_1_$(NUM_UUID)), DefId(0:20 ~ predicate[$(CRATE_ID)]::prusti_pre_item_test_identity_1_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:24 ~ predicate[$(CRATE_ID)]::test_identity_2), kind: Inherent(Impure), pres: Inherent([DefId(0:22 ~ predicate[$(CRATE_ID)]::prusti_pre_item_test_identity_2_$(NUM_UUID)), DefId(0:23 ~ predicate[$(CRATE_ID)]::prusti_pre_item_test_identity_2_$(NUM_UUID))]), posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } diff --git a/prusti-tests/tests/verify/ui/pure.stdout b/prusti-tests/tests/verify/ui/pure.stdout index 93c841350f5..bb513935b86 100644 --- a/prusti-tests/tests/verify/ui/pure.stdout +++ b/prusti-tests/tests/verify/ui/pure.stdout @@ -67,7 +67,8 @@ fn test_max2() { #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_post_item_test_max3_$(NUM_UUID)(result: i32) -> bool { - !!((true && ((!(true) || (result == 3))) && (true || false)): bool) + !!((((true) && (((!(true) || (result == 3))))) && (((true) || (false)))): + bool) } #[prusti::post_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -109,9 +110,9 @@ fn prusti_post_item_test_max5_$(NUM_UUID)(a: i32, b: i32, #[prusti::specs_version = $(SPECS_VERSION)] fn test_max5(a: i32, b: i32) -> i32 { a } fn main() {} -ProcedureSpecification { source: DefId(0:11 ~ pure[$(CRATE_ID)]::max), kind: Inherent(Pure), pres: Empty, posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:8 ~ pure[$(CRATE_ID)]::identity), kind: Inherent(Pure), pres: Empty, posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:13 ~ pure[$(CRATE_ID)]::test_max3), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:12 ~ pure[$(CRATE_ID)]::prusti_post_item_test_max3_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:10 ~ pure[$(CRATE_ID)]::test_identity2), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:9 ~ pure[$(CRATE_ID)]::prusti_post_item_test_identity2_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:16 ~ pure[$(CRATE_ID)]::test_max4), kind: Inherent(Impure), pres: Inherent([DefId(0:14 ~ pure[$(CRATE_ID)]::prusti_pre_item_test_max4_$(NUM_UUID))]), posts: Inherent([DefId(0:15 ~ pure[$(CRATE_ID)]::prusti_post_item_test_max4_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } -ProcedureSpecification { source: DefId(0:19 ~ pure[$(CRATE_ID)]::test_max5), kind: Inherent(Impure), pres: Inherent([DefId(0:17 ~ pure[$(CRATE_ID)]::prusti_pre_item_test_max5_$(NUM_UUID))]), posts: Inherent([DefId(0:18 ~ pure[$(CRATE_ID)]::prusti_post_item_test_max5_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None) } +ProcedureSpecification { source: DefId(0:11 ~ pure[$(CRATE_ID)]::max), kind: Inherent(Pure), pres: Empty, posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:8 ~ pure[$(CRATE_ID)]::identity), kind: Inherent(Pure), pres: Empty, posts: Empty, pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:13 ~ pure[$(CRATE_ID)]::test_max3), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:12 ~ pure[$(CRATE_ID)]::prusti_post_item_test_max3_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:10 ~ pure[$(CRATE_ID)]::test_identity2), kind: Inherent(Impure), pres: Empty, posts: Inherent([DefId(0:9 ~ pure[$(CRATE_ID)]::prusti_post_item_test_identity2_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:16 ~ pure[$(CRATE_ID)]::test_max4), kind: Inherent(Impure), pres: Inherent([DefId(0:14 ~ pure[$(CRATE_ID)]::prusti_pre_item_test_max4_$(NUM_UUID))]), posts: Inherent([DefId(0:15 ~ pure[$(CRATE_ID)]::prusti_post_item_test_max4_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } +ProcedureSpecification { source: DefId(0:19 ~ pure[$(CRATE_ID)]::test_max5), kind: Inherent(Impure), pres: Inherent([DefId(0:17 ~ pure[$(CRATE_ID)]::prusti_pre_item_test_max5_$(NUM_UUID))]), posts: Inherent([DefId(0:18 ~ pure[$(CRATE_ID)]::prusti_post_item_test_max5_$(NUM_UUID))]), pledges: Empty, trusted: Inherent(false), terminates: Inherent(None), purity: Inherent(None) } From f4dfa7ee1fe562c62ecacc7c696629aad8103f44 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Sat, 17 Dec 2022 05:26:17 +0100 Subject: [PATCH 33/64] update more compiletests --- .../parse/fail/extern-spec/traits/default-methods-invalid.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/prusti-tests/tests/parse/fail/extern-spec/traits/default-methods-invalid.rs b/prusti-tests/tests/parse/fail/extern-spec/traits/default-methods-invalid.rs index baa521b4356..9d7b4d5763c 100644 --- a/prusti-tests/tests/parse/fail/extern-spec/traits/default-methods-invalid.rs +++ b/prusti-tests/tests/parse/fail/extern-spec/traits/default-methods-invalid.rs @@ -10,10 +10,10 @@ trait MyTrait { #[extern_spec] trait MyTrait { #[ensures(result == 42)] - fn foo(&self) -> i32 { //~ ERROR: Default methods in external trait specs are invalid + fn foo(&self) -> i32 { //~ ERROR: Unexpected method body. (Extern specs only define specifications.) 43 } } fn main() { -} \ No newline at end of file +} From 13e8fb250eba7b154842de385b46bb8485ae3794 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Mon, 19 Dec 2022 03:02:52 +0100 Subject: [PATCH 34/64] allow merge clauses for extern trait specs implemented by simply tacking on our bound to the existing clause --- .../src/extern_spec_rewriter/traits.rs | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs index 5718efe16e0..4bc605257da 100644 --- a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs +++ b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs @@ -71,15 +71,17 @@ fn generate_new_struct(item_trait: &syn::ItemTrait) -> syn::Result Date: Mon, 19 Dec 2022 03:07:14 +0100 Subject: [PATCH 35/64] allow extern_spec to take a module argument & apply to free functions the module argument is not valid on impls, since those already work with qualified type paths --- .../src/extern_spec_rewriter/functions.rs | 52 ++++++++++++++++ .../src/extern_spec_rewriter/mod.rs | 1 + .../src/extern_spec_rewriter/mods.rs | 61 +++++-------------- .../src/extern_spec_rewriter/traits.rs | 21 +++++-- prusti-contracts/prusti-specs/src/lib.rs | 60 ++++++++++++------ 5 files changed, 125 insertions(+), 70 deletions(-) create mode 100644 prusti-contracts/prusti-specs/src/extern_spec_rewriter/functions.rs diff --git a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/functions.rs b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/functions.rs new file mode 100644 index 00000000000..e0b251bbbc5 --- /dev/null +++ b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/functions.rs @@ -0,0 +1,52 @@ +//! Process external specifications on free functions. +//! In practice, these will be combined with a module argument to extern_spec +//! e.g. `#[extern_spec(core::mem)] fn swap` + +use super::common::generate_extern_spec_function_stub; +use crate::ExternSpecKind; +use proc_macro2::{Group, TokenStream, TokenTree}; +use quote::{quote, ToTokens}; +use syn::{parse_quote_spanned, spanned::Spanned}; + +pub fn rewrite_stub(stub_tokens: &mut TokenStream, path: &syn::Path) -> syn::Result<()> { + // Transforms function stubs (functions with a `;` after the + // signature instead of the body) into functions, then + // processes them. + let mut new_tokens = TokenStream::new(); + for mut token in stub_tokens.clone().into_iter() { + if let TokenTree::Punct(punct) = &mut token { + if punct.as_char() == ';' { + new_tokens.extend( + Group::new(proc_macro2::Delimiter::Brace, TokenStream::new()).to_token_stream(), + ); + continue; + } + } + new_tokens.extend(token.to_token_stream()); + } + let res: Result = syn::parse2(new_tokens); + if res.is_err() { + return Err(syn::Error::new( + stub_tokens.span(), + "invalid function signature", + )); + } + + let mut item = res.unwrap(); + if let syn::Item::Fn(item_fn) = &mut item { + rewrite_fn(item_fn, path); + } + *stub_tokens = quote!(#item); + + Ok(()) +} + +/// Rewrite a specification function to a call to the specified function. +/// The result of this rewriting is then parsed in `ExternSpecResolver`. +pub fn rewrite_fn(item_fn: &mut syn::ItemFn, path: &syn::Path) { + let ident = &item_fn.sig.ident; + let path_span = item_fn.sig.ident.span(); + let path = parse_quote_spanned!(path_span=> #path :: #ident); + + *item_fn = generate_extern_spec_function_stub(item_fn, &path, ExternSpecKind::Method); +} diff --git a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/mod.rs b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/mod.rs index d8e8d432d56..119ce3f9dfc 100644 --- a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/mod.rs +++ b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/mod.rs @@ -3,6 +3,7 @@ pub mod impls; pub mod mods; pub mod traits; +pub mod functions; mod common; #[derive(Debug, Clone, Copy)] diff --git a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/mods.rs b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/mods.rs index 7e84dbe9187..2b80e7e7d9c 100644 --- a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/mods.rs +++ b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/mods.rs @@ -5,17 +5,19 @@ //! Modules are rewritten so that their name does not clash with the module //! they are specifying. -use super::common::{check_is_stub, generate_extern_spec_function_stub}; -use crate::{specifications::common::generate_mod_name, ExternSpecKind}; -use proc_macro2::{Group, TokenStream, TokenTree}; -use quote::{quote, ToTokens}; -use syn::{parse_quote_spanned, spanned::Spanned}; - -pub fn rewrite_extern_spec(item_mod: &mut syn::ItemMod) -> syn::Result { - let path = syn::Path { - leading_colon: None, - segments: syn::punctuated::Punctuated::new(), - }; +use super::{ + common::check_is_stub, + functions::{rewrite_fn, rewrite_stub}, +}; +use crate::specifications::common::generate_mod_name; +use proc_macro2::TokenStream; +use quote::quote; +use syn::spanned::Spanned; + +pub fn rewrite_extern_spec( + item_mod: &mut syn::ItemMod, + path: syn::Path, +) -> syn::Result { rewrite_mod(item_mod, &path)?; Ok(quote!(#item_mod)) } @@ -42,32 +44,7 @@ fn rewrite_mod(item_mod: &mut syn::ItemMod, path: &syn::Path) -> syn::Result<()> rewrite_mod(inner_mod, &path)?; } syn::Item::Verbatim(tokens) => { - // Transforms function stubs (functions with a `;` after the - // signature instead of the body) into functions, then - // processes them. - let mut new_tokens = TokenStream::new(); - for mut token in tokens.clone().into_iter() { - if let TokenTree::Punct(punct) = &mut token { - if punct.as_char() == ';' { - new_tokens.extend( - Group::new(proc_macro2::Delimiter::Brace, TokenStream::new()) - .to_token_stream(), - ); - continue; - } - } - new_tokens.extend(token.to_token_stream()); - } - let res: Result = syn::parse2(new_tokens); - if res.is_err() { - return Err(syn::Error::new(item.span(), "invalid function signature")); - } - - let mut item = res.unwrap(); - if let syn::Item::Fn(item_fn) = &mut item { - rewrite_fn(item_fn, &path); - } - *tokens = quote!(#item) + rewrite_stub(tokens, &path)?; } syn::Item::Use(_) => {} _ => return Err(syn::Error::new(item.span(), "unexpected item")), @@ -75,13 +52,3 @@ fn rewrite_mod(item_mod: &mut syn::ItemMod, path: &syn::Path) -> syn::Result<()> } Ok(()) } - -/// Rewrite a specification function to a call to the specified function. -/// The result of this rewriting is then parsed in `ExternSpecResolver`. -fn rewrite_fn(item_fn: &mut syn::ItemFn, path: &syn::Path) { - let ident = &item_fn.sig.ident; - let path_span = item_fn.sig.ident.span(); - let path = parse_quote_spanned!(path_span=> #path :: #ident); - - *item_fn = generate_extern_spec_function_stub(item_fn, &path, ExternSpecKind::Method); -} diff --git a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs index 4bc605257da..709d9a8beda 100644 --- a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs +++ b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs @@ -26,8 +26,16 @@ use syn::{parse_quote, spanned::Spanned}; /// ``` /// and a corresponding impl block with methods of `SomeTrait`. /// -pub fn rewrite_extern_spec(item_trait: &syn::ItemTrait) -> syn::Result { - let generated_struct = generate_new_struct(item_trait)?; +pub fn rewrite_extern_spec( + item_trait: &syn::ItemTrait, + mod_path: syn::Path, +) -> syn::Result { + let mut trait_path = mod_path; + trait_path.segments.push(syn::PathSegment { + ident: item_trait.ident.clone(), + arguments: syn::PathArguments::None, + }); + let generated_struct = generate_new_struct(item_trait, trait_path)?; let trait_impl = generated_struct.generate_impl()?; let new_struct = generated_struct.generated_struct; @@ -38,9 +46,10 @@ pub fn rewrite_extern_spec(item_trait: &syn::ItemTrait) -> syn::Result syn::Result { - let trait_ident = &item_trait.ident; - +fn generate_new_struct( + item_trait: &syn::ItemTrait, + trait_path: syn::Path, +) -> syn::Result { let struct_name = generate_struct_name_for_trait(item_trait); let struct_ident = syn::Ident::new(&struct_name, item_trait.span()); @@ -67,7 +76,7 @@ fn generate_new_struct(item_trait: &syn::ItemTrait) -> syn::Result - #trait_ident :: <#(#parsed_generics),*> + #trait_path :: <#(#parsed_generics),*> }; // Add a where clause which restricts this self type parameter to the trait diff --git a/prusti-contracts/prusti-specs/src/lib.rs b/prusti-contracts/prusti-specs/src/lib.rs index 8d3e57bfc39..2229b8d5f57 100644 --- a/prusti-contracts/prusti-specs/src/lib.rs +++ b/prusti-contracts/prusti-specs/src/lib.rs @@ -50,6 +50,13 @@ macro_rules! handle_result { }; } +macro_rules! result_to_tokens { + ($body:block) => {{ + let body = || $body; + handle_result!(body()) + }}; +} + fn extract_prusti_attributes( item: &mut untyped::AnyFnItem, ) -> Vec<(SpecAttributeKind, TokenStream)> { @@ -726,24 +733,43 @@ pub fn invariant(attr: TokenStream, tokens: TokenStream) -> TokenStream { } pub fn extern_spec(attr: TokenStream, tokens: TokenStream) -> TokenStream { - let item: syn::Item = handle_result!(syn::parse2(tokens)); - match item { - syn::Item::Impl(item_impl) => { - handle_result!(extern_spec_rewriter::impls::rewrite_extern_spec(&item_impl)) - } - syn::Item::Trait(item_trait) => { - handle_result!(extern_spec_rewriter::traits::rewrite_extern_spec( - &item_trait - )) - } - syn::Item::Mod(mut item_mod) => { - handle_result!(extern_spec_rewriter::mods::rewrite_extern_spec( - &mut item_mod - )) + result_to_tokens!({ + let item: syn::Item = syn::parse2(tokens)?; + let mod_path: syn::Path = Some(attr) + .filter(|attr| !attr.is_empty()) + .map(syn::parse2) + .transpose()? + .unwrap_or_else(|| syn::Path { + leading_colon: None, + segments: syn::punctuated::Punctuated::new(), + }); + match item { + syn::Item::Impl(item_impl) => { + if !mod_path.segments.is_empty() { + return Err(syn::Error::new( + mod_path.span(), + "extern_spec does not take a path argument for impls--you can qualify the involved types directly", + )); + } + extern_spec_rewriter::impls::rewrite_extern_spec(&item_impl) + } + syn::Item::Trait(item_trait) => { + extern_spec_rewriter::traits::rewrite_extern_spec(&item_trait, mod_path) + } + syn::Item::Mod(mut item_mod) => { + extern_spec_rewriter::mods::rewrite_extern_spec(&mut item_mod, mod_path) + } + // we're expecting function stubs, so they aren't represented as Item::Fn + syn::Item::Verbatim(mut stub_tokens) => { + extern_spec_rewriter::functions::rewrite_stub(&mut stub_tokens, &mod_path)?; + Ok(stub_tokens) + } + _ => Err(syn::Error::new( + Span::call_site(), // this covers the entire macro invocation, unlike attr.span() which changes to only cover arguments if possible + "Extern specs cannot be attached to this item", + )), } - _ => syn::Error::new(attr.span(), "Extern specs cannot be attached to this item") - .to_compile_error(), - } + }) } pub fn predicate(tokens: TokenStream) -> TokenStream { From b60dae2876309ca61e9056ba4f335e10fed9b15c Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Mon, 19 Dec 2022 03:45:49 +0100 Subject: [PATCH 36/64] update tests --- .../traits/where-clause-disallowed.rs | 18 ----- .../verify/pass/extern-spec/module-arg.rs | 77 +++++++++++++++++++ 2 files changed, 77 insertions(+), 18 deletions(-) delete mode 100644 prusti-tests/tests/parse/fail/extern-spec/traits/where-clause-disallowed.rs create mode 100644 prusti-tests/tests/verify/pass/extern-spec/module-arg.rs diff --git a/prusti-tests/tests/parse/fail/extern-spec/traits/where-clause-disallowed.rs b/prusti-tests/tests/parse/fail/extern-spec/traits/where-clause-disallowed.rs deleted file mode 100644 index 7da9ec3f102..00000000000 --- a/prusti-tests/tests/parse/fail/extern-spec/traits/where-clause-disallowed.rs +++ /dev/null @@ -1,18 +0,0 @@ -use prusti_contracts::*; - -/// External traits -trait MyTrait { - fn foo(&self); -} -/// External traits - -trait A {} -trait B {} -trait C {} - -#[extern_spec] -trait MyTrait where Self: A + B, Self: C { //~ ERROR: Where clauses for extern traits specs are not supported - fn foo(&self); -} - -fn main() {} \ No newline at end of file diff --git a/prusti-tests/tests/verify/pass/extern-spec/module-arg.rs b/prusti-tests/tests/verify/pass/extern-spec/module-arg.rs new file mode 100644 index 00000000000..6ca07c40450 --- /dev/null +++ b/prusti-tests/tests/verify/pass/extern-spec/module-arg.rs @@ -0,0 +1,77 @@ +use prusti_contracts::*; + +fn main() { + use module::inner::*; + + fn _trait_test_1() { + assert!(T::example() == 42) + } + + fn _trait_test_2, U: Copy>() { + prusti_assert!(T::example() === T::example()) + } + + assert!(free_1() == 1); + assert!(free_2() == 2); + + let s = Struct; + assert!(s.method() == 42); +} + +#[extern_spec(module::inner)] +trait Example { + #[ensures(result == 42)] + fn example() -> i32; +} + +#[extern_spec(module::inner)] +trait Advanced<#[generic] T> where T: Copy { + #[pure] + fn example() -> T; +} + +#[extern_spec(module)] +mod inner { + use crate::*; + + #[ensures(result == 1)] + fn free_1() -> i32; +} + +#[extern_spec(module::inner)] +#[ensures(result == 2)] +fn free_2() -> i32; + +#[extern_spec] +impl module::inner::Struct { + #[ensures(result == 42)] + fn method(&self) -> i32; +} + +mod module { + pub mod inner { + pub trait Example { + fn example() -> i32; + } + + pub trait Advanced { + fn example() -> T; + } + + pub fn free_1() -> i32 { + 1 + } + + pub fn free_2() -> i32 { + 2 + } + + pub struct Struct; + + impl Struct { + pub fn method(&self) -> i32 { + 42 + } + } + } +} From 94f8d4cc11c806d4d21898447e0d503edbd32900 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Mon, 19 Dec 2022 16:38:33 +0100 Subject: [PATCH 37/64] allow trailing commas in where clauses on extern specs on traits --- .../prusti-specs/src/extern_spec_rewriter/traits.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs index 709d9a8beda..44c749e1c55 100644 --- a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs +++ b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs @@ -82,6 +82,10 @@ fn generate_new_struct( // Add a where clause which restricts this self type parameter to the trait let self_where_clause: syn::WhereClause = if let Some(where_clause) = &item_trait.generics.where_clause { + let mut where_clause = where_clause.clone(); + // remove trailing comma + let p = where_clause.predicates.pop().unwrap(); + where_clause.predicates.push(p.into_value()); // merge into existing where clause parse_quote! { #where_clause, #self_type_ident: #self_type_trait From c243fc5febd321e86ed0f3a94e794f98b4f7730c Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Tue, 20 Dec 2022 21:24:32 +0100 Subject: [PATCH 38/64] ignore lifetimes in pure function substs --- prusti-interface/src/environment/query.rs | 2 ++ .../src/encoder/mir/pure/pure_functions/interface.rs | 4 +++- .../encoder/mir/pure/specifications/encoder_poly.rs | 10 ++++++++-- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/prusti-interface/src/environment/query.rs b/prusti-interface/src/environment/query.rs index 16bb1e0d950..f67ae5aa1a5 100644 --- a/prusti-interface/src/environment/query.rs +++ b/prusti-interface/src/environment/query.rs @@ -324,6 +324,8 @@ impl<'tcx> EnvQuery<'tcx> { use prusti_rustc_interface::middle::ty::TypeVisitable; let called_def_id = called_def_id.into_param(); + let call_substs = self.tcx.erase_regions(call_substs); + // avoids a compiler-internal panic if call_substs.needs_infer() { return (called_def_id, call_substs); diff --git a/prusti-viper/src/encoder/mir/pure/pure_functions/interface.rs b/prusti-viper/src/encoder/mir/pure/pure_functions/interface.rs index 63a0aa206a4..1f6240a0374 100644 --- a/prusti-viper/src/encoder/mir/pure/pure_functions/interface.rs +++ b/prusti-viper/src/encoder/mir/pure/pure_functions/interface.rs @@ -23,6 +23,7 @@ use vir_crate::{common::identifier::WithIdentifier, high as vir_high, polymorphi /// to account for different monomorphisations resulting from the function /// being called from callers (with different parameter environments). Each /// variant of a pure function will be encoded as a separate Viper function. +/// Lifetimes/regions are erased. type Key<'tcx> = (ProcedureDefId, SubstsRef<'tcx>, ty::PolyFnSig<'tcx>); /// Compute the key for the given call. @@ -32,9 +33,10 @@ fn compute_key<'v, 'tcx: 'v>( caller_def_id: ProcedureDefId, substs: SubstsRef<'tcx>, ) -> SpannedEncodingResult> { + let tcx = encoder.env().tcx(); Ok(( proc_def_id, - substs, + tcx.erase_regions(substs), encoder .env() .query diff --git a/prusti-viper/src/encoder/mir/pure/specifications/encoder_poly.rs b/prusti-viper/src/encoder/mir/pure/specifications/encoder_poly.rs index a6b676a90df..ce794c51fca 100644 --- a/prusti-viper/src/encoder/mir/pure/specifications/encoder_poly.rs +++ b/prusti-viper/src/encoder/mir/pure/specifications/encoder_poly.rs @@ -80,9 +80,15 @@ pub(super) fn inline_spec_item<'tcx>( parent_def_id: DefId, substs: SubstsRef<'tcx>, ) -> SpannedEncodingResult { + // each non-lifetime parameter should be matched with a subst assert_eq!( - substs.len(), - encoder.env().query.identity_substs(def_id).len() + substs.non_erasable_generics().count(), + encoder + .env() + .query + .identity_substs(def_id) + .non_erasable_generics() + .count() ); let mir = encoder From 501a737a961d51df15a1a0802f82f38f6c7115c3 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Tue, 20 Dec 2022 21:33:22 +0100 Subject: [PATCH 39/64] ignore lifetimes in extern spec sanity check too --- prusti-interface/src/specs/external.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/prusti-interface/src/specs/external.rs b/prusti-interface/src/specs/external.rs index 96163ea6855..960ba33d9ce 100644 --- a/prusti-interface/src/specs/external.rs +++ b/prusti-interface/src/specs/external.rs @@ -178,8 +178,14 @@ impl<'tcx> ExternSpecResolver<'tcx> { // TODO: there is more that we could check, e.g. that trait // constraints are the same (otherwise specs might not make sense) let (resolved_gens, current_gens) = ( - self.env_query.identity_substs(resolved_def_id).len(), - self.env_query.identity_substs(current_def_id).len(), + self.env_query + .identity_substs(resolved_def_id) + .non_erasable_generics() + .count(), + self.env_query + .identity_substs(current_def_id) + .non_erasable_generics() + .count(), ); if resolved_gens != current_gens { let diff = resolved_gens as isize - current_gens as isize; From b3be7e81ed2cfb16eaa007f7431b5a65b1b38318 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Thu, 29 Dec 2022 07:16:56 +0100 Subject: [PATCH 40/64] always use lifetimes from args instead of generics generic lifetimes are erased during trait impl resolution --- .../src/encoder/mir/procedures/encoder/mod.rs | 38 +++++++------------ 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/prusti-viper/src/encoder/mir/procedures/encoder/mod.rs b/prusti-viper/src/encoder/mir/procedures/encoder/mod.rs index 39917ea3c41..e65fd78918b 100644 --- a/prusti-viper/src/encoder/mir/procedures/encoder/mod.rs +++ b/prusti-viper/src/encoder/mir/procedures/encoder/mod.rs @@ -1488,11 +1488,11 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { // The called method might be a trait method. // We try to resolve it to the concrete implementation // and type substitutions. - let (called_def_id, call_substs) = - self.encoder - .env() - .query - .resolve_method_call(self.def_id, called_def_id, call_substs); + let (called_def_id, call_substs) = self.encoder.env().query.resolve_method_call( + self.def_id, + called_def_id, + self.encoder.env().tcx().erase_regions(call_substs), + ); // find static lifetime to exhale let mut lifetimes_to_exhale_inhale: Vec = Vec::new(); @@ -1505,29 +1505,19 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { } assert_eq!(lifetimes_to_exhale_inhale.len(), 1); // there must be exactly one static lifetime - // find generic argument lifetimes - let mut subst_lifetimes: Vec = call_substs - .iter() - .filter_map(|generic| match generic.unpack() { - ty::subst::GenericArgKind::Lifetime(region) => Some(region.to_text()), - _ => None, - }) - .collect(); - if subst_lifetimes.is_empty() { - // If subst_lifetimes is empty, check args for a lifetime - for arg in args { - if let &mir::Operand::Move(place) = arg { - let place_high = self.encode_place(place, None)?; - let lifetimes = place_high.get_lifetimes(); - for lifetime in lifetimes { - subst_lifetimes.push(lifetime.name.clone()); + // find lifetimes for function args + for arg in args { + match arg { + &mir::Operand::Move(place) => { + let encoded_place = self.encode_place(place, None)?; + let place_lifetimes = encoded_place.get_lifetimes(); + for lifetime in place_lifetimes { + lifetimes_to_exhale_inhale.push(lifetime.name.clone()); } } + _ => {} } } - for lifetime in subst_lifetimes { - lifetimes_to_exhale_inhale.push(lifetime); - } // construct function lifetime self.function_call_ctr += 1; From 8d2d8bc6edd269836b45a7490b16c89dfe403be1 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Thu, 29 Dec 2022 07:55:13 +0100 Subject: [PATCH 41/64] clippy --- .../src/encoder/mir/procedures/encoder/mod.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/prusti-viper/src/encoder/mir/procedures/encoder/mod.rs b/prusti-viper/src/encoder/mir/procedures/encoder/mod.rs index e65fd78918b..4edeb75dac0 100644 --- a/prusti-viper/src/encoder/mir/procedures/encoder/mod.rs +++ b/prusti-viper/src/encoder/mir/procedures/encoder/mod.rs @@ -1507,15 +1507,12 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { // find lifetimes for function args for arg in args { - match arg { - &mir::Operand::Move(place) => { - let encoded_place = self.encode_place(place, None)?; - let place_lifetimes = encoded_place.get_lifetimes(); - for lifetime in place_lifetimes { - lifetimes_to_exhale_inhale.push(lifetime.name.clone()); - } + if let &mir::Operand::Move(place) = arg { + let encoded_place = self.encode_place(place, None)?; + let place_lifetimes = encoded_place.get_lifetimes(); + for lifetime in place_lifetimes { + lifetimes_to_exhale_inhale.push(lifetime.name.clone()); } - _ => {} } } From 379e2da433987e401c1aedcc41c97803c055d908 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Wed, 4 Jan 2023 07:33:51 +0100 Subject: [PATCH 42/64] update user guide with new typecondspec syntax --- docs/user-guide/src/SUMMARY.md | 2 +- docs/user-guide/src/verify/traits.md | 19 ---------- docs/user-guide/src/verify/type_cond_spec.md | 37 ++++++++++++++++++++ 3 files changed, 38 insertions(+), 20 deletions(-) delete mode 100644 docs/user-guide/src/verify/traits.md create mode 100644 docs/user-guide/src/verify/type_cond_spec.md diff --git a/docs/user-guide/src/SUMMARY.md b/docs/user-guide/src/SUMMARY.md index 7f6270fee66..baf9cde630d 100644 --- a/docs/user-guide/src/SUMMARY.md +++ b/docs/user-guide/src/SUMMARY.md @@ -26,7 +26,7 @@ - [External specifications](verify/external.md) - [Loop body invariants](verify/loop.md) - [Pledges](verify/pledge.md) - - [Trait contract refinement](verify/traits.md) + - [Type-conditional spec refinements](verify/type_cond_spec.md) - [Closures](verify/closure.md) - [Specification entailments](verify/spec_ent.md) - [Type models](verify/type-models.md) diff --git a/docs/user-guide/src/verify/traits.md b/docs/user-guide/src/verify/traits.md deleted file mode 100644 index 3fac5a91f98..00000000000 --- a/docs/user-guide/src/verify/traits.md +++ /dev/null @@ -1,19 +0,0 @@ -# Trait contract refinement - -> **NOT YET SUPPORTED:** This feature is not yet supported in the new version of Prusti. - -In some cases, marker traits simply modify the behavior of methods in their super-traits. For instance consider the `PartialEq` and `Eq` traits. In order to consider this additional behavior for verification, traits support contract refinement on trait level: - -```rust -pub trait PartialEq { - #[ensures(/* partial equivalence formulas */)] - fn eq(&self, other: &Rhs) -> bool; -} - -#[refine_ensures(PartialEq::eq = "self.eq(&self)")] -pub trait Eq: PartialEq {} -``` - -Thus, any client implementing `Eq` on a custom type can take advantage of the additional semantics of the total equivalence. Similarly `#[refine_requires]` can be used to refine the precondition of a super-trait. - -> Such trait refinement is not scoped. Therefore, considering the previous example, implementing `Eq` on a type implies that the total equivalence contract is always considered on the type, irrespective of whether `Eq` is in scope or not. diff --git a/docs/user-guide/src/verify/type_cond_spec.md b/docs/user-guide/src/verify/type_cond_spec.md new file mode 100644 index 00000000000..ad2d4c8e4f4 --- /dev/null +++ b/docs/user-guide/src/verify/type_cond_spec.md @@ -0,0 +1,37 @@ +# Type-Conditional Spec Refinement + +When specifying trait methods or generic functions, there is often a special case that allows for more complete specification. In these cases, you can attach a type-conditional spec refinement attribute to the function in question, spelled e.g. `#[refine_spec(where T: A + B, U: C, [requires(true), pure])]` + +For example, one could use this to specify a function like `core::mem::size_of` by defining a trait for types whose size we'd like to specify: + +```rust +#[pure] +#[refine_spec(where T: KnownSize, [ + ensures(result == T::size()), +])] +fn size_of() -> usize; + +pub trait KnownSize { + #[pure] + fn size() -> usize; +} +``` + +> Note that the involved functions are marked as `pure`, allowing them to be used within specifications. This is another common use case, because functions can only be `pure` if their parameters and result are `Copy`, so it is often useful to specify something like `#[refine_spec(where T: Copy, [pure])]`. + +There are some marker traits which simply modify the behavior of methods in their super-traits. For instance, consider the `PartialEq` and `Eq` traits. In order to consider this additional behavior for verification, we can refine the contract of `PartialEq::eq` when the type is known to be marked `Eq`: + +```rust +pub trait PartialEq { + #[refine_spec(where Self: Eq, [ + ensures(self == self), // reflexive + // we could write more specs here + ])] + #[ensures(/* partial equivalence formulas */)] + fn eq(&self, other: &Rhs) -> bool; +} +``` + +Thus, any client implementing `Eq` on a custom type can take advantage of the additional semantics of the total equivalence. + +> Refinements like these are not scoped. Therefore, considering the previous example, implementing `Eq` on a type implies that the total equivalence contract is always considered on the type, irrespective of whether `Eq` is in scope or not. From 811ac31ea292833c23dc910c74f0d5c3ed808748 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Wed, 4 Jan 2023 07:48:58 +0100 Subject: [PATCH 43/64] add regression test for trait resolution with references --- .../pass/trait-resolution/references.rs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 prusti-tests/tests/verify/pass/trait-resolution/references.rs diff --git a/prusti-tests/tests/verify/pass/trait-resolution/references.rs b/prusti-tests/tests/verify/pass/trait-resolution/references.rs new file mode 100644 index 00000000000..d9b6c06d4e7 --- /dev/null +++ b/prusti-tests/tests/verify/pass/trait-resolution/references.rs @@ -0,0 +1,37 @@ +use prusti_contracts::*; + +trait Trait { + fn foo(value: T) -> i32 { + 1 + } +} + +struct Example; + +#[refine_trait_spec] +impl Trait<&i32> for Example { + #[ensures(result == *value)] + fn foo(value: &i32) -> i32 { + *value + } +} + +struct PureExample; + +#[refine_trait_spec] +impl Trait<&i32> for PureExample { + #[pure] + #[ensures(result == *value)] + fn foo(value: &i32) -> i32 { + *value + } +} + +fn main() { + let x = 5; + let y = 6; + assert!(Example::foo(&x) == x); + assert!(Example::foo(&y) == y); + assert!(PureExample::foo(&x) == x); + prusti_assert!(PureExample::foo(&x) == x); +} From 23dbd7d337b3ce195d7ae86ba4d97f9cd4cbdc6b Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Wed, 4 Jan 2023 07:58:02 +0100 Subject: [PATCH 44/64] update broken link --- docs/user-guide/src/verify/summary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/user-guide/src/verify/summary.md b/docs/user-guide/src/verify/summary.md index c4d9cb1e905..7bf7be4a336 100644 --- a/docs/user-guide/src/verify/summary.md +++ b/docs/user-guide/src/verify/summary.md @@ -17,7 +17,7 @@ The following features are either currently supported or planned to be supported - [External specifications](external.md) - [Loop body invariants](loop.md) - [Pledges](pledge.md) -- [Trait contract refinement](traits.md) +- [Type-conditional spec refinements](type_cond_spec.md) - [Closures](closure.md) - [Specification entailments](spec_ent.md) - [Type models](type-models.md) From be6cee0c121f9954dfcad3a9bcdef0f21cc41978 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Thu, 5 Jan 2023 07:47:48 +0100 Subject: [PATCH 45/64] use lifetimes from substs when possible --- .../src/encoder/mir/procedures/encoder/mod.rs | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/prusti-viper/src/encoder/mir/procedures/encoder/mod.rs b/prusti-viper/src/encoder/mir/procedures/encoder/mod.rs index 4edeb75dac0..c294e3aa216 100644 --- a/prusti-viper/src/encoder/mir/procedures/encoder/mod.rs +++ b/prusti-viper/src/encoder/mir/procedures/encoder/mod.rs @@ -1488,11 +1488,9 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { // The called method might be a trait method. // We try to resolve it to the concrete implementation // and type substitutions. - let (called_def_id, call_substs) = self.encoder.env().query.resolve_method_call( - self.def_id, - called_def_id, - self.encoder.env().tcx().erase_regions(call_substs), - ); + let query = self.encoder.env().query; + let (called_def_id, call_substs) = + query.resolve_method_call(self.def_id, called_def_id, call_substs); // find static lifetime to exhale let mut lifetimes_to_exhale_inhale: Vec = Vec::new(); @@ -1506,12 +1504,21 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { assert_eq!(lifetimes_to_exhale_inhale.len(), 1); // there must be exactly one static lifetime // find lifetimes for function args - for arg in args { - if let &mir::Operand::Move(place) = arg { - let encoded_place = self.encode_place(place, None)?; - let place_lifetimes = encoded_place.get_lifetimes(); - for lifetime in place_lifetimes { - lifetimes_to_exhale_inhale.push(lifetime.name.clone()); + let has_erased_regions = call_substs.regions().any(|r| r.is_erased()); + let mut subst_regions = call_substs.regions().peekable(); + if !has_erased_regions && subst_regions.peek().is_some() { + // use generic argument lifetimes + lifetimes_to_exhale_inhale.extend(subst_regions.map(|r| r.to_string())); + } else { + // if we find any erased regions, cancel everything and fall back on resolving lifetimes from args directly + // this happens e.g. when working with the result of trait method resolution, which erases lifetimes + for arg in args { + if let &mir::Operand::Move(place) = arg { + let encoded_place = self.encode_place(place, None)?; + let place_lifetimes = encoded_place.get_lifetimes(); + for lifetime in place_lifetimes { + lifetimes_to_exhale_inhale.push(lifetime.name.clone()); + } } } } From 317ab083ac399397adf1051aa52c27564a50d4de Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Thu, 5 Jan 2023 07:48:21 +0100 Subject: [PATCH 46/64] erase lifetimes only when resolved method differs --- prusti-interface/src/environment/query.rs | 37 ++++++++++++----------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/prusti-interface/src/environment/query.rs b/prusti-interface/src/environment/query.rs index f67ae5aa1a5..51addde1275 100644 --- a/prusti-interface/src/environment/query.rs +++ b/prusti-interface/src/environment/query.rs @@ -321,25 +321,28 @@ impl<'tcx> EnvQuery<'tcx> { called_def_id: impl IntoParam, // what are we calling? call_substs: SubstsRef<'tcx>, ) -> (ProcedureDefId, SubstsRef<'tcx>) { - use prusti_rustc_interface::middle::ty::TypeVisitable; let called_def_id = called_def_id.into_param(); - let call_substs = self.tcx.erase_regions(call_substs); - - // avoids a compiler-internal panic - if call_substs.needs_infer() { - return (called_def_id, call_substs); - } - - let param_env = self.tcx.param_env(caller_def_id.into_param()); - self.tcx - .resolve_instance(param_env.and((called_def_id, call_substs))) - .map(|opt_instance| { - opt_instance - .map(|instance| (instance.def_id(), instance.substs)) - .unwrap_or((called_def_id, call_substs)) - }) - .unwrap_or((called_def_id, call_substs)) + (|| { + // trait resolution does not depend on lifetimes, and in fact fails in the presence of uninferred regions + let clean_substs = self.tcx.erase_regions(call_substs); + + let param_env = self.tcx.param_env(caller_def_id.into_param()); + let instance = self + .tcx + .resolve_instance(param_env.and((called_def_id, clean_substs))) + .ok()??; + let resolved_def_id = instance.def_id(); + let resolved_substs = if resolved_def_id == called_def_id { + // if no trait resolution occurred, we can keep the non-erased substs + call_substs + } else { + instance.substs + }; + + Some((resolved_def_id, resolved_substs)) + })() + .unwrap_or((called_def_id, call_substs)) } /// Checks whether `ty` is copy. From 9897e5580fe3894879f0de6f5887935c5ac95e45 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Fri, 6 Jan 2023 05:31:11 +0100 Subject: [PATCH 47/64] tiny fix got lost in the refactor; i blame copilot lol --- prusti-viper/src/encoder/mir/procedures/encoder/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prusti-viper/src/encoder/mir/procedures/encoder/mod.rs b/prusti-viper/src/encoder/mir/procedures/encoder/mod.rs index c294e3aa216..036ec0626b5 100644 --- a/prusti-viper/src/encoder/mir/procedures/encoder/mod.rs +++ b/prusti-viper/src/encoder/mir/procedures/encoder/mod.rs @@ -1508,7 +1508,7 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> { let mut subst_regions = call_substs.regions().peekable(); if !has_erased_regions && subst_regions.peek().is_some() { // use generic argument lifetimes - lifetimes_to_exhale_inhale.extend(subst_regions.map(|r| r.to_string())); + lifetimes_to_exhale_inhale.extend(subst_regions.map(|r| r.to_text())); } else { // if we find any erased regions, cancel everything and fall back on resolving lifetimes from args directly // this happens e.g. when working with the result of trait method resolution, which erases lifetimes From b00c10375a815b290176f4c1f0db1d71547beb2d Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Fri, 6 Jan 2023 05:55:29 +0100 Subject: [PATCH 48/64] fix some test indentation --- .../tests/parse/fail/extern-spec/no-bodies.rs | 24 +++++++++---------- .../verify/fail/ghost-constraints/purity.rs | 6 +++-- .../verify/pass/type-cond-specs/purity.rs | 6 +++-- .../in-non-trusted-function.rs | 5 ++-- 4 files changed, 22 insertions(+), 19 deletions(-) diff --git a/prusti-tests/tests/parse/fail/extern-spec/no-bodies.rs b/prusti-tests/tests/parse/fail/extern-spec/no-bodies.rs index 5080759c6a4..9fd6e630f14 100644 --- a/prusti-tests/tests/parse/fail/extern-spec/no-bodies.rs +++ b/prusti-tests/tests/parse/fail/extern-spec/no-bodies.rs @@ -2,28 +2,28 @@ use prusti_contracts::*; #[extern_spec] impl Option { - #[pure] - fn is_some(&self) -> bool {} //~ ERROR: Unexpected method body. (Extern specs only define specifications.) + #[pure] + fn is_some(&self) -> bool {} //~ ERROR: Unexpected method body. (Extern specs only define specifications.) } #[extern_spec] trait Clone { - #[pure] - fn clone(&self) -> Self {} //~ ERROR: Unexpected method body. (Extern specs only define specifications.) + #[pure] + fn clone(&self) -> Self {} //~ ERROR: Unexpected method body. (Extern specs only define specifications.) } #[extern_spec] impl Clone for i32 { - #[pure] - fn clone(&self) -> Self {} //~ ERROR: Unexpected method body. (Extern specs only define specifications.) + #[pure] + fn clone(&self) -> Self {} //~ ERROR: Unexpected method body. (Extern specs only define specifications.) } #[extern_spec] mod core { - mod mem { - use crate::*; - - #[pure] - pub fn size_of() -> usize {} //~ ERROR: Unexpected method body. (Extern specs only define specifications.) - } + mod mem { + use crate::*; + + #[pure] + pub fn size_of() -> usize {} //~ ERROR: Unexpected method body. (Extern specs only define specifications.) + } } diff --git a/prusti-tests/tests/verify/fail/ghost-constraints/purity.rs b/prusti-tests/tests/verify/fail/ghost-constraints/purity.rs index 9efccf23f24..b037ac57272 100644 --- a/prusti-tests/tests/verify/fail/ghost-constraints/purity.rs +++ b/prusti-tests/tests/verify/fail/ghost-constraints/purity.rs @@ -2,11 +2,13 @@ use prusti_contracts::*; #[refine_spec(where T: Copy, [pure])] #[trusted] -fn test(_t: T) -> bool { true } +fn test(_t: T) -> bool { + true +} #[derive(Clone, PartialEq, Eq)] struct Copyrighted; // not Copy fn main() { - prusti_assert!(test(Copyrighted) == test(Copyrighted)); //~ ERROR: [Prusti: invalid specification] use of impure function "test" in pure code is not allowed + prusti_assert!(test(Copyrighted) == test(Copyrighted)); //~ ERROR: [Prusti: invalid specification] use of impure function "test" in pure code is not allowed } diff --git a/prusti-tests/tests/verify/pass/type-cond-specs/purity.rs b/prusti-tests/tests/verify/pass/type-cond-specs/purity.rs index d62fb59320d..02d9831d636 100644 --- a/prusti-tests/tests/verify/pass/type-cond-specs/purity.rs +++ b/prusti-tests/tests/verify/pass/type-cond-specs/purity.rs @@ -2,8 +2,10 @@ use prusti_contracts::*; #[refine_spec(where T: Copy, [pure])] #[trusted] -fn test(_t: T) -> bool { true } +fn test(_t: T) -> bool { + true +} fn main() { - assert!(test(5) == test(5)); + assert!(test(5) == test(5)); } diff --git a/prusti-tests/tests/verify_overflow/fail/type-cond-specs/in-non-trusted-function.rs b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/in-non-trusted-function.rs index f34479dcab0..88d3df95e32 100644 --- a/prusti-tests/tests/verify_overflow/fail/type-cond-specs/in-non-trusted-function.rs +++ b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/in-non-trusted-function.rs @@ -3,9 +3,8 @@ use prusti_contracts::*; trait A {} #[refine_spec(where T: A, [ - ensures(true) + ensures(true) ])] fn foo() {} //~ ERROR: Type-conditional spec refinements can only be applied to trusted functions -fn main() { -} +fn main() {} From 26347865452897681f6e39733ebf75304474d8e2 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Fri, 6 Jan 2023 05:55:43 +0100 Subject: [PATCH 49/64] remove unnecessary derive --- prusti-tests/tests/verify/fail/ghost-constraints/purity.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prusti-tests/tests/verify/fail/ghost-constraints/purity.rs b/prusti-tests/tests/verify/fail/ghost-constraints/purity.rs index b037ac57272..3243593734c 100644 --- a/prusti-tests/tests/verify/fail/ghost-constraints/purity.rs +++ b/prusti-tests/tests/verify/fail/ghost-constraints/purity.rs @@ -6,7 +6,7 @@ fn test(_t: T) -> bool { true } -#[derive(Clone, PartialEq, Eq)] +#[derive(PartialEq, Eq)] struct Copyrighted; // not Copy fn main() { From 6ff4c4a5555d8f9020547bbf1d2d5e3068bd6807 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Fri, 6 Jan 2023 06:01:10 +0100 Subject: [PATCH 50/64] rename missed test folders --- .../verify/fail/{ghost-constraints => type-cond-specs}/purity.rs | 0 .../fail/{ghost-constraints => type-cond-specs}/traits-1.rs | 0 .../invalid-trait-refinement-1.rs | 0 .../invalid-trait-refinement-1.stderr | 0 .../invalid-trait-refinement-2.rs | 0 .../invalid-trait-refinement-2.stderr | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename prusti-tests/tests/verify/fail/{ghost-constraints => type-cond-specs}/purity.rs (100%) rename prusti-tests/tests/verify/fail/{ghost-constraints => type-cond-specs}/traits-1.rs (100%) rename prusti-tests/tests/verify/ui/{ghost-constraints => type-cond-specs}/invalid-trait-refinement-1.rs (100%) rename prusti-tests/tests/verify/ui/{ghost-constraints => type-cond-specs}/invalid-trait-refinement-1.stderr (100%) rename prusti-tests/tests/verify/ui/{ghost-constraints => type-cond-specs}/invalid-trait-refinement-2.rs (100%) rename prusti-tests/tests/verify/ui/{ghost-constraints => type-cond-specs}/invalid-trait-refinement-2.stderr (100%) diff --git a/prusti-tests/tests/verify/fail/ghost-constraints/purity.rs b/prusti-tests/tests/verify/fail/type-cond-specs/purity.rs similarity index 100% rename from prusti-tests/tests/verify/fail/ghost-constraints/purity.rs rename to prusti-tests/tests/verify/fail/type-cond-specs/purity.rs diff --git a/prusti-tests/tests/verify/fail/ghost-constraints/traits-1.rs b/prusti-tests/tests/verify/fail/type-cond-specs/traits-1.rs similarity index 100% rename from prusti-tests/tests/verify/fail/ghost-constraints/traits-1.rs rename to prusti-tests/tests/verify/fail/type-cond-specs/traits-1.rs diff --git a/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-1.rs b/prusti-tests/tests/verify/ui/type-cond-specs/invalid-trait-refinement-1.rs similarity index 100% rename from prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-1.rs rename to prusti-tests/tests/verify/ui/type-cond-specs/invalid-trait-refinement-1.rs diff --git a/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-1.stderr b/prusti-tests/tests/verify/ui/type-cond-specs/invalid-trait-refinement-1.stderr similarity index 100% rename from prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-1.stderr rename to prusti-tests/tests/verify/ui/type-cond-specs/invalid-trait-refinement-1.stderr diff --git a/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-2.rs b/prusti-tests/tests/verify/ui/type-cond-specs/invalid-trait-refinement-2.rs similarity index 100% rename from prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-2.rs rename to prusti-tests/tests/verify/ui/type-cond-specs/invalid-trait-refinement-2.rs diff --git a/prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-2.stderr b/prusti-tests/tests/verify/ui/type-cond-specs/invalid-trait-refinement-2.stderr similarity index 100% rename from prusti-tests/tests/verify/ui/ghost-constraints/invalid-trait-refinement-2.stderr rename to prusti-tests/tests/verify/ui/type-cond-specs/invalid-trait-refinement-2.stderr From 333c869ff4d11bbe4d132f039d4365cfb21e1602 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Fri, 6 Jan 2023 06:14:53 +0100 Subject: [PATCH 51/64] improve generic trait tests --- .../src/extern_spec_rewriter/impls.rs | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs index 1bca1fd74cf..9515be76f18 100644 --- a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs +++ b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/impls.rs @@ -329,10 +329,10 @@ mod tests { } #[test] - fn generics_supported() { + fn generic_trait() { let mut inp_impl: syn::ItemImpl = parse_quote!( - impl MyTrait for MyStruct { - fn foo(&mut self, arg1: I); + impl MyTrait for MyStruct { + fn foo(&mut self, arg1: Foo); } ); @@ -341,6 +341,31 @@ mod tests { let newtype_ident = &rewritten.generated_struct.ident; let expected_impl: syn::ItemImpl = parse_quote! { impl #newtype_ident <> { + #[prusti::extern_spec = "trait_impl"] + #[allow(unused, dead_code)] + #[prusti::trusted] + fn foo(_self: &mut MyStruct, arg1: Foo) { + > :: foo :: <>(_self, arg1) + } + } + }; + + assert_eq_tokenizable(rewritten.generated_impl.clone(), expected_impl); + } + + #[test] + fn generic_blanket_impl() { + let mut inp_impl: syn::ItemImpl = parse_quote!( + impl MyTrait for MyStruct { + fn foo(&mut self, arg1: I); + } + ); + + let rewritten = rewrite_extern_spec_internal(&mut inp_impl).unwrap(); + + let newtype_ident = &rewritten.generated_struct.ident; + let expected_impl: syn::ItemImpl = parse_quote! { + impl #newtype_ident { #[prusti::extern_spec = "trait_impl"] #[allow(unused, dead_code)] #[prusti::trusted] From 6433cd9e66bfd0512a1eb3b3764d7dc691d90d85 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Fri, 6 Jan 2023 07:32:38 +0100 Subject: [PATCH 52/64] update comment --- prusti-contracts/prusti-specs/src/rewriter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prusti-contracts/prusti-specs/src/rewriter.rs b/prusti-contracts/prusti-specs/src/rewriter.rs index 9795fcefb1c..09821d6ebaa 100644 --- a/prusti-contracts/prusti-specs/src/rewriter.rs +++ b/prusti-contracts/prusti-specs/src/rewriter.rs @@ -186,7 +186,7 @@ impl AstRewriter { #[allow(unused_must_use, unused_parens, unused_variables, dead_code)] #[prusti::spec_only] #[prusti::spec_id = #spec_id_str] - fn #item_name() {} // we only care about this for evaluating + fn #item_name() {} // we only need this for attaching constraints to (to evaluate when the function is pure) }; spec_item.sig.generics = item.sig().generics.clone(); From 3943e37563fd7e5a3e66bd60ff94a270e8110552 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Sat, 7 Jan 2023 01:54:56 +0100 Subject: [PATCH 53/64] drop unhelpful comment --- docs/user-guide/src/verify/type_cond_spec.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/user-guide/src/verify/type_cond_spec.md b/docs/user-guide/src/verify/type_cond_spec.md index ad2d4c8e4f4..ff8a9c0e198 100644 --- a/docs/user-guide/src/verify/type_cond_spec.md +++ b/docs/user-guide/src/verify/type_cond_spec.md @@ -33,5 +33,3 @@ pub trait PartialEq { ``` Thus, any client implementing `Eq` on a custom type can take advantage of the additional semantics of the total equivalence. - -> Refinements like these are not scoped. Therefore, considering the previous example, implementing `Eq` on a type implies that the total equivalence contract is always considered on the type, irrespective of whether `Eq` is in scope or not. From 021f88f25a8e11752cfdcf6beacaba79518229b9 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Sat, 7 Jan 2023 01:57:17 +0100 Subject: [PATCH 54/64] remove outdated comment better no information than inaccurate information! --- .../prusti-specs/src/specifications/mod.rs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/prusti-contracts/prusti-specs/src/specifications/mod.rs b/prusti-contracts/prusti-specs/src/specifications/mod.rs index 07e766175bd..62b27210064 100644 --- a/prusti-contracts/prusti-specs/src/specifications/mod.rs +++ b/prusti-contracts/prusti-specs/src/specifications/mod.rs @@ -1,19 +1,3 @@ -/// The following grammar defines Prusti expressions (this is an LL(finite) grammar): -/// assertion ::= prusti_expr ; -/// pledge ::= pledge_lhs, ",", prusti_expr ; -/// pledge_lhs ::= [ ? actual rust expression ?, "=>" ], prusti_expr ; -/// -/// prusti_expr ::= conjunction, [ "==>", prusti_expr ] ; -/// conjunction ::= entailment, { "&&", entailment } ; -/// entailment ::= primary | ? actual rust expression ?, [ "|=", [ "|", ? args as parsed by syn2 ?, "|" ], "[", [ ( requires | ensures ), { ",", ( requires | ensures ) } ], "]" ] ; -/// primary ::= "(", prusti_expr, ")" -/// | "forall", "(", "|", ? one or more args as parsed by syn2 ?, "|", prusti_expr, [ ",", "triggers", "=", ? array as parsed by syn2 ? ] ")" -/// ; -/// requires ::= "requires", "(", prusti_expr, ")" ; -/// ensures ::= "ensures", "(", prusti_expr, ")" ; -/// -/// This grammar doesn't yet handle the unintuitive precedence difference between `&&` and `||` operators. - pub mod common; pub mod preparser; pub mod untyped; From 2d523ebe94f68b0940a5d5b738b096213def26c0 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Sat, 7 Jan 2023 07:57:42 +0100 Subject: [PATCH 55/64] fix spans for binary ops while preserving the safety of parenthesizing incoming LHS/RHS --- .../src/specifications/preparser.rs | 19 ++-- prusti-tests/tests/parse/ui/composite.stdout | 98 +++++++++---------- prusti-tests/tests/parse/ui/exists.stdout | 6 +- prusti-tests/tests/parse/ui/forall.stdout | 6 +- prusti-tests/tests/parse/ui/implies.stdout | 20 ++-- prusti-tests/tests/parse/ui/predicates.stdout | 4 +- .../tests/typecheck/ui/nested_forall.stdout | 4 +- prusti-tests/tests/verify/ui/calls.stdout | 2 +- .../tests/verify/ui/failing-postcondition.rs | 11 ++- .../verify/ui/failing-postcondition.stderr | 36 +++++-- .../abstract-predicate-with-body.stderr | 0 prusti-tests/tests/verify/ui/pure.stdout | 2 +- 12 files changed, 116 insertions(+), 92 deletions(-) delete mode 100644 prusti-tests/tests/verify/ui/predicates/abstract-predicate-with-body.stderr diff --git a/prusti-contracts/prusti-specs/src/specifications/preparser.rs b/prusti-contracts/prusti-specs/src/specifications/preparser.rs index afbe05c0c55..171785912d7 100644 --- a/prusti-contracts/prusti-specs/src/specifications/preparser.rs +++ b/prusti-contracts/prusti-specs/src/specifications/preparser.rs @@ -878,20 +878,25 @@ impl PrustiBinaryOp { } } - fn translate(&self, span: Span, lhs: TokenStream, rhs: TokenStream) -> TokenStream { + fn translate(&self, span: Span, raw_lhs: TokenStream, raw_rhs: TokenStream) -> TokenStream { + let lhs = quote_spanned! { raw_lhs.span() => (#raw_lhs) }; + let rhs = quote_spanned! { raw_rhs.span() => (#raw_rhs) }; match self { - Self::Rust(op) => op.translate(span, lhs, rhs), + Self::Rust(op) => op.translate(span, raw_lhs, raw_rhs), // implication is desugared into this form to avoid evaluation // order issues: `f(a, b)` makes Rust evaluate both `a` and `b` // before the `f` call Self::Implies => { // preserve span of LHS - let not_lhs = quote_spanned! { lhs.span() => !(#lhs) }; - quote_spanned! { span => (#not_lhs || (#rhs)) } + let not_lhs = quote_spanned! { lhs.span() => !#lhs }; + quote_spanned! { span => #not_lhs || #rhs } + } + Self::Or => quote_spanned! { span => #lhs || #rhs }, + Self::And => quote_spanned! { span => #lhs && #rhs }, + Self::SnapEq => { + let joined_span = join_spans(lhs.span(), rhs.span()); + quote_spanned! { joined_span => snapshot_equality(&#lhs, &#rhs) } } - Self::Or => quote_spanned! { span => (#lhs) || (#rhs) }, - Self::And => quote_spanned! { span => (#lhs) && (#rhs) }, - Self::SnapEq => quote_spanned! { span => snapshot_equality(&(#lhs), &(#rhs)) }, } } } diff --git a/prusti-tests/tests/parse/ui/composite.stdout b/prusti-tests/tests/parse/ui/composite.stdout index 7647d4db054..be327541e13 100644 --- a/prusti-tests/tests/parse/ui/composite.stdout +++ b/prusti-tests/tests/parse/ui/composite.stdout @@ -42,7 +42,7 @@ use prusti_contracts::*; #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test1_$(NUM_UUID)() -> bool { - !!(((!((true) && (true)) || ((true) && (true)))): bool) + !!((!((true) && (true)) || ((true) && (true))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -51,7 +51,7 @@ fn test1() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test2_$(NUM_UUID)() -> bool { - !!(((((true) && (((!(true) || (true))))) && (((true) || (true)))) && + !!(((((true) && ((!(true) || (true)))) && (((true) || (true)))) && (true)): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] @@ -61,7 +61,7 @@ fn test2() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test3_$(NUM_UUID)() -> bool { - !!(((!(((true) && (true))) || (true))): bool) + !!((!(((true) && (true))) || (true)): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -70,7 +70,7 @@ fn test3() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test4_$(NUM_UUID)() -> bool { - !!(((!((((!(true) || (true)))) && (true)) || (true))): bool) + !!((!(((!(true) || (true))) && (true)) || (true)): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -79,8 +79,8 @@ fn test4() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test5_$(NUM_UUID)() -> bool { - !!(((((!(true) || (true)))) && - (((!(true) || ((true) && (((true) || (true)))))))): bool) + !!((((!(true) || (true))) && + ((!(true) || ((true) && (((true) || (true))))))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -89,8 +89,8 @@ fn test5() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test6_$(NUM_UUID)() -> bool { - !!(((!(((true) && (true))) || - ((!(true) || ((!(true) || ((!(true) || (true))))))))): bool) + !!((!(((true) && (true))) || + (!(true) || (!(true) || (!(true) || (true))))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -99,8 +99,8 @@ fn test6() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test7_$(NUM_UUID)() -> bool { - !!(((!(((true) && (true))) || - ((!(((true) && (true))) || (((true) && (true))))))): bool) + !!((!(((true) && (true))) || + (!(((true) && (true))) || (((true) && (true))))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -109,7 +109,7 @@ fn test7() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test8_$(NUM_UUID)() -> bool { - !!(((!(((true) || (true))) || (((true) || (true))))): bool) + !!((!(((true) || (true))) || (((true) || (true)))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -118,8 +118,8 @@ fn test8() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test9_$(NUM_UUID)() -> bool { - !!(((!(((true) || (true))) || - (((true) || (((true) && (((true) || (true))))))))): bool) + !!((!(((true) || (true))) || + (((true) || (((true) && (((true) || (true)))))))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -151,10 +151,10 @@ fn test12() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test13_$(NUM_UUID)() -> bool { - !!(((!(true) || - ((!(forall((), - #[prusti::spec_only] |a: i32, b: i32| -> bool - { ((a == 5): bool) })) || (true))))): bool) + !!((!(true) || + (!(forall((), + #[prusti::spec_only] |a: i32, b: i32| -> bool + { ((a == 5): bool) })) || (true))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -163,10 +163,10 @@ fn test13() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test14_$(NUM_UUID)() -> bool { - !!(((!(true) || - (forall((), - #[prusti::spec_only] |a: i32| -> bool - { ((a == 5): bool) })))): bool) + !!((!(true) || + (forall((), + #[prusti::spec_only] |a: i32| -> bool + { ((a == 5): bool) }))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -175,9 +175,9 @@ fn test14() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test15_$(NUM_UUID)() -> bool { - !!(((!(forall((), - #[prusti::spec_only] |a: i32| -> bool { ((a == 5): bool) })) - || (true))): bool) + !!((!(forall((), + #[prusti::spec_only] |a: i32| -> bool { ((a == 5): bool) })) + || (true)): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -186,13 +186,13 @@ fn test15() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test16_$(NUM_UUID)() -> bool { - !!(((!(forall((), - #[prusti::spec_only] |b: i32| -> bool - { ((b == 10): bool) })) || - ((!(true) || - (forall((), - #[prusti::spec_only] |a: u32, b: u32| -> bool - { ((a == 5): bool) })))))): bool) + !!((!(forall((), + #[prusti::spec_only] |b: i32| -> bool + { ((b == 10): bool) })) || + (!(true) || + (forall((), + #[prusti::spec_only] |a: u32, b: u32| -> bool + { ((a == 5): bool) })))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -224,10 +224,10 @@ fn test19() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test20_$(NUM_UUID)() -> bool { - !!(((!(true) || - ((!(exists((), - #[prusti::spec_only] |a: i32, b: i32| -> bool - { ((a == 5): bool) })) || (true))))): bool) + !!((!(true) || + (!(exists((), + #[prusti::spec_only] |a: i32, b: i32| -> bool + { ((a == 5): bool) })) || (true))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -236,10 +236,10 @@ fn test20() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test21_$(NUM_UUID)() -> bool { - !!(((!(true) || - (exists((), - #[prusti::spec_only] |a: i32| -> bool - { ((a == 5): bool) })))): bool) + !!((!(true) || + (exists((), + #[prusti::spec_only] |a: i32| -> bool + { ((a == 5): bool) }))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -248,9 +248,9 @@ fn test21() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test22_$(NUM_UUID)() -> bool { - !!(((!(exists((), - #[prusti::spec_only] |a: i32| -> bool { ((a == 5): bool) })) - || (true))): bool) + !!((!(exists((), + #[prusti::spec_only] |a: i32| -> bool { ((a == 5): bool) })) + || (true)): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -259,13 +259,13 @@ fn test22() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test23_$(NUM_UUID)() -> bool { - !!(((!(exists((), - #[prusti::spec_only] |b: i32| -> bool - { ((b == 10): bool) })) || - ((!(true) || - (exists((), - #[prusti::spec_only] |a: u32, b: u32| -> bool - { ((a == 5): bool) })))))): bool) + !!((!(exists((), + #[prusti::spec_only] |b: i32| -> bool + { ((b == 10): bool) })) || + (!(true) || + (exists((), + #[prusti::spec_only] |a: u32, b: u32| -> bool + { ((a == 5): bool) })))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] diff --git a/prusti-tests/tests/parse/ui/exists.stdout b/prusti-tests/tests/parse/ui/exists.stdout index 65b45f7a091..3c3a7db3a33 100644 --- a/prusti-tests/tests/parse/ui/exists.stdout +++ b/prusti-tests/tests/parse/ui/exists.stdout @@ -50,8 +50,7 @@ fn test2() {} fn prusti_pre_item_test3_$(NUM_UUID)() -> bool { !!((exists((), #[prusti::spec_only] |a: i32, b: i32| -> bool - { (((!(a + b == a + b) || (a + b == a + b))): bool) })): - bool) + { ((!(a + b == a + b) || (a + b == a + b)): bool) })): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -92,8 +91,7 @@ fn prusti_pre_item_test6_$(NUM_UUID)() -> bool { #[prusti::spec_only] |a: i32, b: i32| (2)), (#[prusti::spec_only] |a: i32, b: i32| (1),)), #[prusti::spec_only] |a: i32, b: i32| -> bool - { (((!(a + b == a + b) || (a + b == a + b))): bool) })): - bool) + { ((!(a + b == a + b) || (a + b == a + b)): bool) })): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] diff --git a/prusti-tests/tests/parse/ui/forall.stdout b/prusti-tests/tests/parse/ui/forall.stdout index e1ecb7f4782..0a2a103053a 100644 --- a/prusti-tests/tests/parse/ui/forall.stdout +++ b/prusti-tests/tests/parse/ui/forall.stdout @@ -50,8 +50,7 @@ fn test2() {} fn prusti_pre_item_test3_$(NUM_UUID)() -> bool { !!((forall((), #[prusti::spec_only] |a: i32, b: i32| -> bool - { (((!(a + b == a + b) || (a + b == a + b))): bool) })): - bool) + { ((!(a + b == a + b) || (a + b == a + b)): bool) })): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -92,8 +91,7 @@ fn prusti_pre_item_test6_$(NUM_UUID)() -> bool { #[prusti::spec_only] |a: i32, b: i32| (2)), (#[prusti::spec_only] |a: i32, b: i32| (1),)), #[prusti::spec_only] |a: i32, b: i32| -> bool - { (((!(a + b == a + b) || (a + b == a + b))): bool) })): - bool) + { ((!(a + b == a + b) || (a + b == a + b)): bool) })): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] diff --git a/prusti-tests/tests/parse/ui/implies.stdout b/prusti-tests/tests/parse/ui/implies.stdout index 4caacc7707f..697e793846e 100644 --- a/prusti-tests/tests/parse/ui/implies.stdout +++ b/prusti-tests/tests/parse/ui/implies.stdout @@ -28,7 +28,7 @@ use prusti_contracts::*; #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test1_$(NUM_UUID)() -> bool { - !!(((!(true) || (true))): bool) + !!((!(true) || (true)): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -37,7 +37,7 @@ fn test1() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test2_$(NUM_UUID)() -> bool { - !!(((!(true) || ((!(true) || (true))))): bool) + !!((!(true) || (!(true) || (true))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -46,7 +46,7 @@ fn test2() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test3_$(NUM_UUID)() -> bool { - !!(((!(true) || (((!(true) || (true)))))): bool) + !!((!(true) || ((!(true) || (true)))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -55,7 +55,7 @@ fn test3() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test4_$(NUM_UUID)() -> bool { - !!(((!(((!(true) || (true)))) || (true))): bool) + !!((!((!(true) || (true))) || (true)): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -64,7 +64,7 @@ fn test4() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test5_$(NUM_UUID)() -> bool { - !!(((!(((!(true) || (true)))) || (((!(true) || (true)))))): bool) + !!((!((!(true) || (true))) || ((!(true) || (true)))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -73,7 +73,7 @@ fn test5() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test21_$(NUM_UUID)() -> bool { - !!(((!(true) || (true))): bool) + !!((!(true) || (true)): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -82,7 +82,7 @@ fn test21() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test22_$(NUM_UUID)() -> bool { - !!(((!(true) || ((!(true) || (true))))): bool) + !!((!(true) || (!(true) || (true))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -91,7 +91,7 @@ fn test22() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test23_$(NUM_UUID)() -> bool { - !!(((!(true) || (((!(true) || (true)))))): bool) + !!((!(true) || ((!(true) || (true)))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -100,7 +100,7 @@ fn test23() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test24_$(NUM_UUID)() -> bool { - !!(((!(((!(true) || (true)))) || (true))): bool) + !!((!((!(true) || (true))) || (true)): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] @@ -109,7 +109,7 @@ fn test24() {} #[prusti::spec_only] #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_pre_item_test25_$(NUM_UUID)() -> bool { - !!(((!(((!(true) || (true)))) || (((!(true) || (true)))))): bool) + !!((!((!(true) || (true))) || ((!(true) || (true)))): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] #[prusti::specs_version = $(SPECS_VERSION)] diff --git a/prusti-tests/tests/parse/ui/predicates.stdout b/prusti-tests/tests/parse/ui/predicates.stdout index 756b4bc5ad7..e4681fb552e 100644 --- a/prusti-tests/tests/parse/ui/predicates.stdout +++ b/prusti-tests/tests/parse/ui/predicates.stdout @@ -79,7 +79,7 @@ fn prusti_pred_item_forall_implication_$(NUM_UUID)() -> bool { !!((forall((), #[prusti::spec_only] |x: usize| -> bool - { (((!((x != 0)) || (x * 2 != 0))): bool) })): bool) + { ((!((x != 0)) || (x * 2 != 0)): bool) })): bool) } #[allow(unused_must_use, unused_variables, dead_code)] #[prusti::pred_spec_id_ref = "$(NUM_UUID)"] @@ -96,7 +96,7 @@ fn prusti_pred_item_exists_implication_$(NUM_UUID)() -> bool { !!((exists((), #[prusti::spec_only] |x: usize| -> bool - { (((!((x != 0)) || (x * 2 != 0))): bool) })): bool) + { ((!((x != 0)) || (x * 2 != 0)): bool) })): bool) } #[allow(unused_must_use, unused_variables, dead_code)] #[prusti::pred_spec_id_ref = "$(NUM_UUID)"] diff --git a/prusti-tests/tests/typecheck/ui/nested_forall.stdout b/prusti-tests/tests/typecheck/ui/nested_forall.stdout index a2fc02dba9a..992be64f226 100644 --- a/prusti-tests/tests/typecheck/ui/nested_forall.stdout +++ b/prusti-tests/tests/typecheck/ui/nested_forall.stdout @@ -45,7 +45,7 @@ fn prusti_pre_item_test2_$(NUM_UUID)() -> bool { { ((forall((), #[prusti::spec_only] |b: i32| -> bool - { (((!(a == a) || (b == b))): bool) })): bool) + { ((!(a == a) || (b == b)): bool) })): bool) })): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] @@ -94,7 +94,7 @@ fn prusti_pre_item_test5_$(NUM_UUID)() -> bool { { ((exists((), #[prusti::spec_only] |b: i32| -> bool - { (((!(a == a) || (b == b))): bool) })): bool) + { ((!(a == a) || (b == b)): bool) })): bool) })): bool) } #[prusti::pre_spec_id_ref = "$(NUM_UUID)"] diff --git a/prusti-tests/tests/verify/ui/calls.stdout b/prusti-tests/tests/verify/ui/calls.stdout index 31eb59cd5fc..413a40572c9 100644 --- a/prusti-tests/tests/verify/ui/calls.stdout +++ b/prusti-tests/tests/verify/ui/calls.stdout @@ -59,7 +59,7 @@ fn test_max2() { #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_post_item_test_max3_$(NUM_UUID)(result: i32) -> bool { - !!((((true) && (((!(true) || (result == 3))))) && (((true) || (false)))): + !!((((true) && ((!(true) || (result == 3)))) && (((true) || (false)))): bool) } #[prusti::post_spec_id_ref = "$(NUM_UUID)"] diff --git a/prusti-tests/tests/verify/ui/failing-postcondition.rs b/prusti-tests/tests/verify/ui/failing-postcondition.rs index 866eb1d5ae4..3eeff1ecce4 100644 --- a/prusti-tests/tests/verify/ui/failing-postcondition.rs +++ b/prusti-tests/tests/verify/ui/failing-postcondition.rs @@ -10,10 +10,17 @@ fn client(a: u32) {} #[pure] #[ensures(result)] -fn test1() -> bool { false } +fn test1() -> bool { + false +} #[pure] #[ensures(x)] -fn test2(x: bool) -> bool { x } +fn test2(x: bool) -> bool { + x +} + +#[ensures(a === b)] +fn test3(a: T, b: T) {} fn main() {} diff --git a/prusti-tests/tests/verify/ui/failing-postcondition.stderr b/prusti-tests/tests/verify/ui/failing-postcondition.stderr index 8b0671f40fe..54424aa4380 100644 --- a/prusti-tests/tests/verify/ui/failing-postcondition.stderr +++ b/prusti-tests/tests/verify/ui/failing-postcondition.stderr @@ -1,8 +1,8 @@ error: [Prusti: verification error] postcondition might not hold. - --> $DIR/failing-postcondition.rs:8:28 + --> $DIR/failing-postcondition.rs:8:11 | 8 | #[ensures(something_true() && false)] - | ^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the error originates here --> $DIR/failing-postcondition.rs:9:1 @@ -19,20 +19,36 @@ error: [Prusti: verification error] postcondition might not hold. note: the error originates here --> $DIR/failing-postcondition.rs:13:1 | -13 | fn test1() -> bool { false } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +13 | / fn test1() -> bool { +14 | | false +15 | | } + | |_^ error: [Prusti: verification error] postcondition might not hold. - --> $DIR/failing-postcondition.rs:16:11 + --> $DIR/failing-postcondition.rs:18:11 | -16 | #[ensures(x)] +18 | #[ensures(x)] | ^ | note: the error originates here - --> $DIR/failing-postcondition.rs:17:1 + --> $DIR/failing-postcondition.rs:19:1 | -17 | fn test2(x: bool) -> bool { x } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +19 | / fn test2(x: bool) -> bool { +20 | | x +21 | | } + | |_^ -error: aborting due to 3 previous errors +error: [Prusti: verification error] postcondition might not hold. + --> $DIR/failing-postcondition.rs:23:11 + | +23 | #[ensures(a === b)] + | ^^^^^^^ + | +note: the error originates here + --> $DIR/failing-postcondition.rs:24:1 + | +24 | fn test3(a: T, b: T) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors diff --git a/prusti-tests/tests/verify/ui/predicates/abstract-predicate-with-body.stderr b/prusti-tests/tests/verify/ui/predicates/abstract-predicate-with-body.stderr deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/prusti-tests/tests/verify/ui/pure.stdout b/prusti-tests/tests/verify/ui/pure.stdout index bb513935b86..ae0203eb800 100644 --- a/prusti-tests/tests/verify/ui/pure.stdout +++ b/prusti-tests/tests/verify/ui/pure.stdout @@ -67,7 +67,7 @@ fn test_max2() { #[prusti::spec_id = "$(NUM_UUID)"] fn prusti_post_item_test_max3_$(NUM_UUID)(result: i32) -> bool { - !!((((true) && (((!(true) || (result == 3))))) && (((true) || (false)))): + !!((((true) && ((!(true) || (result == 3)))) && (((true) || (false)))): bool) } #[prusti::post_spec_id_ref = "$(NUM_UUID)"] From 46a863dfc557f655d0b6f2a74b8f860518c829a3 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Sun, 8 Jan 2023 03:29:50 +0100 Subject: [PATCH 56/64] obsolete #[generic]/#[concrete] for traits the latter didn't work anyway, and now that we have type-cond-specs, we know we won't need it, so we can drop the annotations entirely. --- .../src/extern_spec_rewriter/traits.rs | 90 +++++-------------- 1 file changed, 22 insertions(+), 68 deletions(-) diff --git a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs index 44c749e1c55..125bcc3caf4 100644 --- a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs +++ b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs @@ -6,7 +6,7 @@ use crate::{ }; use proc_macro2::TokenStream; use quote::{quote_spanned, ToTokens}; -use syn::{parse_quote, spanned::Spanned}; +use syn::{parse_quote, spanned::Spanned, TypeParam}; /// Generates a struct for a `syn::ItemTrait` which is used for checking /// compilation of external specs on traits. @@ -57,28 +57,21 @@ fn generate_new_struct( #[allow(non_camel_case_types)] struct #struct_ident {} }; + let new_generics = &mut new_struct.generics.params; + // Add a new type parameter to struct which represents an implementation of the trait let self_type_ident = syn::Ident::new("Prusti_T_Self", item_trait.span()); - new_struct - .generics - .params - .push(syn::GenericParam::Type(parse_quote!(#self_type_ident))); + new_generics.push(syn::GenericParam::Type(parse_quote!(#self_type_ident))); let parsed_generics = parse_trait_type_params(item_trait)?; - // Generic type parameters are added as generics to the struct - for parsed_generic in parsed_generics.iter() { - if let ProvidedTypeParam::GenericType(type_param) = parsed_generic { - new_struct - .generics - .params - .push(syn::GenericParam::Type(type_param.clone())); - } - } let self_type_trait: syn::TypePath = parse_quote_spanned! {item_trait.span()=> #trait_path :: <#(#parsed_generics),*> }; + // Generic type parameters are added as generics to the struct + new_generics.extend(parsed_generics.into_iter().map(syn::GenericParam::Type)); + // Add a where clause which restricts this self type parameter to the trait let self_where_clause: syn::WhereClause = if let Some(where_clause) = &item_trait.generics.where_clause { @@ -107,20 +100,13 @@ fn generate_new_struct( }) } -fn parse_trait_type_params(item_trait: &syn::ItemTrait) -> syn::Result> { - let mut result = vec![]; - for generic_param in item_trait.generics.params.iter() { - if let syn::GenericParam::Type(type_param) = generic_param { - result.push( - ProvidedTypeParam::try_parse(type_param) - .ok_or_else(|| syn::Error::new( - type_param.span(), - "Type parameters in external trait specs must be annotated with exactly one of #[generic] or #[concrete]" - ))?, - ); - } - } - Ok(result) +fn parse_trait_type_params(item_trait: &syn::ItemTrait) -> syn::Result> { + item_trait + .generics + .type_params() + .cloned() + .map(check_for_legacy_attributes) + .collect() } struct GeneratedStruct<'a> { @@ -204,45 +190,13 @@ impl<'a> GeneratedStruct<'a> { } } -#[derive(Debug)] -enum ProvidedTypeParam { - /// Something non-concrete, i.e. `T` - ConcreteType(syn::TypeParam), - /// Something concrete, i.e. `i32` - GenericType(syn::TypeParam), -} - -impl ProvidedTypeParam { - fn try_parse(from: &syn::TypeParam) -> Option { - if from.attrs.len() != 1 { - return None; - } - - let path = &from.attrs[0].path; - if path.segments.len() != 1 { - return None; - } - - // Closure for cloning and removing the attrs - let clone_without_attrs = || { - let mut cloned = from.clone(); - cloned.attrs.clear(); - cloned - }; - - match path.segments[0].ident.to_string().as_str() { - "generic" => Some(ProvidedTypeParam::GenericType(clone_without_attrs())), - "concrete" => Some(ProvidedTypeParam::ConcreteType(clone_without_attrs())), - _ => None, - } - } -} - -impl ToTokens for ProvidedTypeParam { - fn to_tokens(&self, tokens: &mut TokenStream) { - match &self { - ProvidedTypeParam::ConcreteType(ty_param) - | ProvidedTypeParam::GenericType(ty_param) => ty_param.to_tokens(tokens), - } +fn check_for_legacy_attributes(param: TypeParam) -> syn::Result { + if let Some(attr) = param.attrs.first() { + Err(syn::Error::new( + attr.span(), + "The `#[concrete]` and `#[generic]` attributes are deprecated. To refine specs for specific concrete types, use type-conditional spec refinements instead.", + )) + } else { + Ok(param) } } From e5b96df1855c4ebdb1648e1739205bc5dd12878d Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Sun, 8 Jan 2023 03:45:13 +0100 Subject: [PATCH 57/64] update tests for trait parameter attribute removal --- .../traits/legacy-generic-attributes.rs | 23 ++++++++++++ .../verify/pass/extern-spec/module-arg.rs | 13 ++++--- .../fail/extern-spec/traits/generics-1.rs | 37 ------------------- .../type-cond-specs/associated-types-4.rs | 2 +- .../type-cond-specs/associated-types-7.rs | 17 ++++++--- .../pass/extern-spec/traits/generics-1.rs | 7 ++-- .../pass/extern-spec/traits/generics-2.rs | 26 ++++++++++--- .../verify_overflow/pass/issues/issue-286.rs | 2 +- .../type-cond-specs/associated-types-4.rs | 2 +- 9 files changed, 68 insertions(+), 61 deletions(-) create mode 100644 prusti-tests/tests/parse/fail/extern-spec/traits/legacy-generic-attributes.rs delete mode 100644 prusti-tests/tests/verify_overflow/fail/extern-spec/traits/generics-1.rs diff --git a/prusti-tests/tests/parse/fail/extern-spec/traits/legacy-generic-attributes.rs b/prusti-tests/tests/parse/fail/extern-spec/traits/legacy-generic-attributes.rs new file mode 100644 index 00000000000..744bd14e24a --- /dev/null +++ b/prusti-tests/tests/parse/fail/extern-spec/traits/legacy-generic-attributes.rs @@ -0,0 +1,23 @@ +use prusti_contracts::*; + +/// External traits +trait MyTrait { + fn get_value(&self) -> T; +} +/// External traits + +#[extern_spec] +trait MyTrait<#[concrete] i32> { + //~^ ERROR: The `#[concrete]` and `#[generic]` attributes are deprecated. To refine specs for specific concrete types, use type-conditional spec refinements instead. + #[ensures(result == 42)] + fn get_value(&self) -> i32; +} + +#[extern_spec] +trait MyTrait<#[generic] T> { + //~^ ERROR: The `#[concrete]` and `#[generic]` attributes are deprecated. To refine specs for specific concrete types, use type-conditional spec refinements instead. + #[ensures(true)] + fn get_value(&self) -> T; +} + +fn main() {} diff --git a/prusti-tests/tests/verify/pass/extern-spec/module-arg.rs b/prusti-tests/tests/verify/pass/extern-spec/module-arg.rs index 6ca07c40450..8a73b3f94c9 100644 --- a/prusti-tests/tests/verify/pass/extern-spec/module-arg.rs +++ b/prusti-tests/tests/verify/pass/extern-spec/module-arg.rs @@ -13,7 +13,7 @@ fn main() { assert!(free_1() == 1); assert!(free_2() == 2); - + let s = Struct; assert!(s.method() == 42); } @@ -25,7 +25,10 @@ trait Example { } #[extern_spec(module::inner)] -trait Advanced<#[generic] T> where T: Copy { +trait Advanced +where + T: Copy, +{ #[pure] fn example() -> T; } @@ -53,7 +56,7 @@ mod module { pub trait Example { fn example() -> i32; } - + pub trait Advanced { fn example() -> T; } @@ -65,9 +68,9 @@ mod module { pub fn free_2() -> i32 { 2 } - + pub struct Struct; - + impl Struct { pub fn method(&self) -> i32 { 42 diff --git a/prusti-tests/tests/verify_overflow/fail/extern-spec/traits/generics-1.rs b/prusti-tests/tests/verify_overflow/fail/extern-spec/traits/generics-1.rs deleted file mode 100644 index 66acae2c5e1..00000000000 --- a/prusti-tests/tests/verify_overflow/fail/extern-spec/traits/generics-1.rs +++ /dev/null @@ -1,37 +0,0 @@ -// ignore-test #[concrete] currently not supported - -use prusti_contracts::*; - -trait MyTrait { - fn get_value(&self) -> T; -} - -#[extern_spec] -trait MyTrait<#[concrete] i32> { - #[ensures(result == 42)] - fn get_value(&self) -> i32; -} - -#[extern_spec] -trait MyTrait<#[concrete] u32> { - #[ensures(result == 43)] //~ ERROR: duplicate specification for MyTrait::get_value - fn get_value(&self) -> u32; -} - -struct Impl; -impl MyTrait for Impl { - fn get_value(&self) -> i32 { - 42 - } -} -impl MyTrait for Impl { - fn get_value(&self) -> u32 { - 43 - } -} - -fn main() { - let s = Impl {}; - assert!(MyTrait::::get_value(&s) == 42); - assert!(MyTrait::::get_value(&s) == 43); -} diff --git a/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-4.rs b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-4.rs index 9e89dbf956f..cc3c9317e79 100644 --- a/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-4.rs +++ b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-4.rs @@ -22,7 +22,7 @@ impl SomeTrait for Foo { } #[extern_spec] -trait SomeTrait<#[generic] T> { +trait SomeTrait { #[refine_spec(where Self: A>::AssocType>, [ ensures(result > 0) ])] diff --git a/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-7.rs b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-7.rs index 85006e6017e..81d440ae13a 100644 --- a/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-7.rs +++ b/prusti-tests/tests/verify_overflow/fail/type-cond-specs/associated-types-7.rs @@ -15,7 +15,9 @@ impl A for FooMatch { } impl SomeTrait for FooMatch { type AssocType = i32; - fn foo(&self) -> i32 { 42 } + fn foo(&self) -> i32 { + 42 + } } struct FooNoMatch1; @@ -24,7 +26,9 @@ impl A for FooNoMatch1 { } impl SomeTrait for FooNoMatch1 { type AssocType = i32; - fn foo(&self) -> i32 { 42 } + fn foo(&self) -> i32 { + 42 + } } struct FooNoMatch2; @@ -33,11 +37,13 @@ impl A for FooNoMatch2 { } impl SomeTrait for FooNoMatch2 { type AssocType = i16; - fn foo(&self) -> i32 { 42 } + fn foo(&self) -> i32 { + 42 + } } #[extern_spec] -trait SomeTrait<#[generic] X, #[generic] Y> { +trait SomeTrait { #[refine_spec(where Self: A>::AssocType>, [ ensures(result > 0) ])] @@ -59,5 +65,4 @@ fn verify_no_match_2() { assert!(f.foo() > 0); //~ ERROR: [Prusti: verification error] the asserted expression might not hold } -fn main() { -} +fn main() {} diff --git a/prusti-tests/tests/verify_overflow/pass/extern-spec/traits/generics-1.rs b/prusti-tests/tests/verify_overflow/pass/extern-spec/traits/generics-1.rs index e3196427729..58b6b110c0e 100644 --- a/prusti-tests/tests/verify_overflow/pass/extern-spec/traits/generics-1.rs +++ b/prusti-tests/tests/verify_overflow/pass/extern-spec/traits/generics-1.rs @@ -6,7 +6,7 @@ trait MyTrait { } /// External traits #[extern_spec] -trait MyTrait<#[generic] T > { +trait MyTrait { #[ensures(true)] fn get_value(&self) -> T; } @@ -20,8 +20,7 @@ impl MyTrait for Impl { } } - fn main() { - let s = Impl{}; + let s = Impl {}; assert!(MyTrait::::get_value(&s) == 42 as i32); -} \ No newline at end of file +} diff --git a/prusti-tests/tests/verify_overflow/pass/extern-spec/traits/generics-2.rs b/prusti-tests/tests/verify_overflow/pass/extern-spec/traits/generics-2.rs index 6bf4a113f7b..c804586f1d8 100644 --- a/prusti-tests/tests/verify_overflow/pass/extern-spec/traits/generics-2.rs +++ b/prusti-tests/tests/verify_overflow/pass/extern-spec/traits/generics-2.rs @@ -1,5 +1,3 @@ -// ignore-test #[concrete] is troublesome - use prusti_contracts::*; /// External traits @@ -9,9 +7,12 @@ trait MyTrait { /// External traits #[extern_spec] -trait MyTrait<#[concrete] i32 > { - #[ensures(result == 42)] - fn get_value(&self) -> i32; +trait MyTrait { + // no equality constraints yet + #[refine_spec(where T: SpecifiedGeneric, [ + ensures(result === T::my_trait__get_value()), + ])] + fn get_value(&self) -> T; } struct Impl; @@ -22,7 +23,20 @@ impl MyTrait for Impl { } fn main() { - let s = Impl{}; + let s = Impl {}; assert!(MyTrait::::get_value(&s) == 42); assert!(s.get_value() == 42); } + +// equality constraint workaround (in the general case, this would take an `&impl MyTrait` as arg) +trait SpecifiedGeneric { + #[pure] + fn my_trait__get_value() -> Self; +} + +impl SpecifiedGeneric for i32 { + #[pure] + fn my_trait__get_value() -> Self { + 42 + } +} diff --git a/prusti-tests/tests/verify_overflow/pass/issues/issue-286.rs b/prusti-tests/tests/verify_overflow/pass/issues/issue-286.rs index 3caa76479e4..5422fd04ff5 100644 --- a/prusti-tests/tests/verify_overflow/pass/issues/issue-286.rs +++ b/prusti-tests/tests/verify_overflow/pass/issues/issue-286.rs @@ -6,7 +6,7 @@ struct A { } #[extern_spec] -trait PartialOrd<#[generic] Rhs> { +trait PartialOrd { #[pure] fn lt(&self, other: &Rhs) -> bool; } diff --git a/prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-4.rs b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-4.rs index 3e8822af9ff..c49a28fea98 100644 --- a/prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-4.rs +++ b/prusti-tests/tests/verify_overflow/pass/type-cond-specs/associated-types-4.rs @@ -22,7 +22,7 @@ impl SomeTrait for Foo { } #[extern_spec] -trait SomeTrait<#[generic] T> { +trait SomeTrait { #[refine_spec(where Self: A>::AssocType>, [ ensures(result > 0) ])] From 0684867cc8765c8cc1abee796882393dd5761603 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Sun, 8 Jan 2023 04:02:34 +0100 Subject: [PATCH 58/64] update preparser cfg tests --- .../prusti-specs/src/specifications/preparser.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/prusti-contracts/prusti-specs/src/specifications/preparser.rs b/prusti-contracts/prusti-specs/src/specifications/preparser.rs index 171785912d7..9b0b875042f 100644 --- a/prusti-contracts/prusti-specs/src/specifications/preparser.rs +++ b/prusti-contracts/prusti-specs/src/specifications/preparser.rs @@ -983,7 +983,7 @@ mod tests { parse_prusti("a ==> b".parse().unwrap()) .unwrap() .to_string(), - "(! (a) || (b))", + "! (a) || (b)", ); assert_eq!( parse_prusti("a === b + c".parse().unwrap()) @@ -995,17 +995,19 @@ mod tests { parse_prusti("a ==> b ==> c".parse().unwrap()) .unwrap() .to_string(), - "(! (a) || ((! (b) || (c))))", + "! (a) || (! (b) || (c))", ); assert_eq!( parse_prusti("(a ==> b && c) ==> d || e".parse().unwrap()) .unwrap() .to_string(), - "(! (((! (a) || ((b) && (c))))) || ((d) || (e)))", + "! ((! (a) || ((b) && (c)))) || ((d) || (e))", ); assert_eq!( - parse_prusti("forall(|x: i32| a ==> b)".parse().unwrap()).unwrap().to_string(), - "forall (() , # [prusti :: spec_only] | x : i32 | -> bool { (((! (a) || (b))) : bool) })", + parse_prusti("forall(|x: i32| a ==> b)".parse().unwrap()) + .unwrap() + .to_string(), + "forall (() , # [prusti :: spec_only] | x : i32 | -> bool { ((! (a) || (b)) : bool) })", ); assert_eq!( parse_prusti("exists(|x: i32| a === b)".parse().unwrap()).unwrap().to_string(), @@ -1013,13 +1015,13 @@ mod tests { ); 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) })", + "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) })", ); assert_eq!( parse_prusti("assert!(a === b ==> b)".parse().unwrap()) .unwrap() .to_string(), - "assert ! ((! (snapshot_equality (& (a) , & (b))) || (b)))", + "assert ! (! (snapshot_equality (& (a) , & (b))) || (b))", ); } From eb011784b4ea080f45df594d4bb4286c49d6377a Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Sun, 8 Jan 2023 07:19:10 +0100 Subject: [PATCH 59/64] rewrite self type in newly-allowed where clauses where clauses on traits --- prusti-contracts/prusti-specs/src/common.rs | 16 ++++++++- .../src/extern_spec_rewriter/traits.rs | 34 ++++++++++--------- 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/prusti-contracts/prusti-specs/src/common.rs b/prusti-contracts/prusti-specs/src/common.rs index 91ef613b99f..25cae0947f9 100644 --- a/prusti-contracts/prusti-specs/src/common.rs +++ b/prusti-contracts/prusti-specs/src/common.rs @@ -149,7 +149,7 @@ mod syn_extensions { mod self_type_rewriter { use syn::{ parse_quote_spanned, spanned::Spanned, visit_mut::VisitMut, ImplItemMethod, ItemFn, Type, - TypePath, + TypePath, WhereClause, }; /// Given a replacement for the `Self` type and the trait it should fulfill, @@ -193,6 +193,16 @@ mod self_type_rewriter { } } + impl SelfTypeRewriter for WhereClause { + fn rewrite_self_type(&mut self, self_type: &Type, self_type_trait: Option<&TypePath>) { + let mut rewriter = Rewriter { + self_type, + self_type_trait, + }; + rewriter.rewrite_where_clause(self); + } + } + struct Rewriter<'a> { self_type: &'a Type, self_type_trait: Option<&'a TypePath>, @@ -206,6 +216,10 @@ mod self_type_rewriter { pub fn rewrite_item_fn(&mut self, item: &mut syn::ItemFn) { syn::visit_mut::visit_item_fn_mut(self, item); } + + pub fn rewrite_where_clause(&mut self, where_clause: &mut WhereClause) { + syn::visit_mut::visit_where_clause_mut(self, where_clause); + } } impl<'a> VisitMut for Rewriter<'a> { diff --git a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs index 125bcc3caf4..da50ef0b751 100644 --- a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs +++ b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/traits.rs @@ -1,7 +1,7 @@ //! Encoding of external specs for traits use super::common::*; use crate::{ - is_predicate_macro, parse_quote_spanned, + common::SelfTypeRewriter, is_predicate_macro, parse_quote_spanned, specifications::common::generate_struct_name_for_trait, ExternSpecKind, }; use proc_macro2::TokenStream; @@ -73,21 +73,23 @@ fn generate_new_struct( new_generics.extend(parsed_generics.into_iter().map(syn::GenericParam::Type)); // Add a where clause which restricts this self type parameter to the trait - let self_where_clause: syn::WhereClause = - if let Some(where_clause) = &item_trait.generics.where_clause { - let mut where_clause = where_clause.clone(); - // remove trailing comma - let p = where_clause.predicates.pop().unwrap(); - where_clause.predicates.push(p.into_value()); - // merge into existing where clause - parse_quote! { - #where_clause, #self_type_ident: #self_type_trait - } - } else { - parse_quote! { - where #self_type_ident: #self_type_trait - } - }; + let self_where_clause: syn::WhereClause = if let Some(where_clause) = + &item_trait.generics.where_clause + { + let mut where_clause = where_clause.clone(); + where_clause.rewrite_self_type(&parse_quote! { #self_type_ident }, Some(&self_type_trait)); + // remove trailing comma + let p = where_clause.predicates.pop().unwrap(); + where_clause.predicates.push(p.into_value()); + // merge into existing where clause + parse_quote! { + #where_clause, #self_type_ident: #self_type_trait + } + } else { + parse_quote! { + where #self_type_ident: #self_type_trait + } + }; new_struct.generics.where_clause = Some(self_where_clause); add_phantom_data_for_generic_params(&mut new_struct); From 607293374c8d8ee240f967985265ba57245b5b17 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Thu, 12 Jan 2023 10:42:38 +0100 Subject: [PATCH 60/64] bump cache version we were getting spurious failures for the core proof tests from old data --- viper/src/cache.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/viper/src/cache.rs b/viper/src/cache.rs index 46d99aa6db2..6c60fa94540 100644 --- a/viper/src/cache.rs +++ b/viper/src/cache.rs @@ -27,7 +27,7 @@ pub struct PersistentCache { data: HashMap, } -const RESULT_CACHE_VERSION: u64 = 2; +const RESULT_CACHE_VERSION: u64 = 3; #[derive(Debug, serde::Serialize, serde::Deserialize)] struct ResultCache { From f8c39543d0b55c90b71e2edf8237786acf5b482a Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Thu, 12 Jan 2023 17:52:13 +0100 Subject: [PATCH 61/64] mangle function names for extern specs --- .../prusti-specs/src/extern_spec_rewriter/common.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/common.rs b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/common.rs index be43359dc7a..935280a459e 100644 --- a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/common.rs +++ b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/common.rs @@ -6,7 +6,7 @@ use crate::{ ExternSpecKind, RewritableReceiver, SelfTypeRewriter, }; use itertools::Itertools; -use quote::{quote, ToTokens}; +use quote::{format_ident, quote, ToTokens}; use syn::{ parse_quote_spanned, punctuated::Punctuated, spanned::Spanned, visit::Visit, visit_mut::VisitMut, Expr, FnArg, GenericArgument, GenericParam, Pat, PatType, Token, @@ -193,8 +193,9 @@ pub(crate) fn generate_extern_spec_function_stub< extern_spec_kind: ExternSpecKind, ) -> Output { let signature = function.sig(); + let mut signature = with_explicit_lifetimes(&signature).unwrap_or_else(|| signature.clone()); + signature.ident = format_ident!("prusti_extern_spec_{}", signature.ident); // Make elided lifetimes explicit, if necessary. - let signature = with_explicit_lifetimes(signature).unwrap_or_else(|| signature.clone()); let attrs = function.attrs().clone(); let generic_params = &signature.generic_params_as_call_args(); let args = &signature.params_as_call_args(); @@ -204,7 +205,7 @@ pub(crate) fn generate_extern_spec_function_stub< #[trusted] #[prusti::extern_spec = #extern_spec_kind_string] #(#attrs)* - #[allow(unused, dead_code)] + #[allow(unused, dead_code, non_snake_case)] #signature { #fn_path :: < #generic_params > ( #args ) } From d1e49e72816e940c3a33d7240262b397ea9efcb2 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Thu, 12 Jan 2023 19:08:27 +0100 Subject: [PATCH 62/64] flatten extern spec modules it's like they were never there! no more use crate::*; --- .../src/extern_spec_rewriter/common.rs | 18 ++++---- .../src/extern_spec_rewriter/functions.rs | 13 +++--- .../src/extern_spec_rewriter/mods.rs | 41 ++++++------------- prusti-contracts/prusti-specs/src/lib.rs | 9 ++-- .../prusti-specs/src/specifications/common.rs | 5 --- 5 files changed, 31 insertions(+), 55 deletions(-) diff --git a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/common.rs b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/common.rs index 935280a459e..6d2bf09d129 100644 --- a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/common.rs +++ b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/common.rs @@ -6,7 +6,8 @@ use crate::{ ExternSpecKind, RewritableReceiver, SelfTypeRewriter, }; use itertools::Itertools; -use quote::{format_ident, quote, ToTokens}; +use proc_macro2::TokenStream; +use quote::{format_ident, quote, quote_spanned, ToTokens}; use syn::{ parse_quote_spanned, punctuated::Punctuated, spanned::Spanned, visit::Visit, visit_mut::VisitMut, Expr, FnArg, GenericArgument, GenericParam, Pat, PatType, Token, @@ -143,8 +144,8 @@ pub(crate) fn generate_extern_spec_method_stub( +pub(crate) fn generate_extern_spec_function_stub( function: &Input, fn_path: &syn::ExprPath, extern_spec_kind: ExternSpecKind, -) -> Output { +) -> TokenStream { let signature = function.sig(); - let mut signature = with_explicit_lifetimes(&signature).unwrap_or_else(|| signature.clone()); + let mut signature = with_explicit_lifetimes(signature).unwrap_or_else(|| signature.clone()); signature.ident = format_ident!("prusti_extern_spec_{}", signature.ident); // Make elided lifetimes explicit, if necessary. let attrs = function.attrs().clone(); @@ -201,7 +199,7 @@ pub(crate) fn generate_extern_spec_function_stub< let args = &signature.params_as_call_args(); let extern_spec_kind_string: String = extern_spec_kind.into(); - parse_quote_spanned! {function.span()=> + quote_spanned! {function.span()=> #[trusted] #[prusti::extern_spec = #extern_spec_kind_string] #(#attrs)* diff --git a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/functions.rs b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/functions.rs index e0b251bbbc5..852718b4340 100644 --- a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/functions.rs +++ b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/functions.rs @@ -8,7 +8,7 @@ use proc_macro2::{Group, TokenStream, TokenTree}; use quote::{quote, ToTokens}; use syn::{parse_quote_spanned, spanned::Spanned}; -pub fn rewrite_stub(stub_tokens: &mut TokenStream, path: &syn::Path) -> syn::Result<()> { +pub fn rewrite_stub(stub_tokens: &TokenStream, path: &syn::Path) -> syn::Result { // Transforms function stubs (functions with a `;` after the // signature instead of the body) into functions, then // processes them. @@ -34,19 +34,18 @@ pub fn rewrite_stub(stub_tokens: &mut TokenStream, path: &syn::Path) -> syn::Res let mut item = res.unwrap(); if let syn::Item::Fn(item_fn) = &mut item { - rewrite_fn(item_fn, path); + Ok(rewrite_fn(item_fn, path)) + } else { + Ok(quote!(#item)) } - *stub_tokens = quote!(#item); - - Ok(()) } /// Rewrite a specification function to a call to the specified function. /// The result of this rewriting is then parsed in `ExternSpecResolver`. -pub fn rewrite_fn(item_fn: &mut syn::ItemFn, path: &syn::Path) { +pub fn rewrite_fn(item_fn: &syn::ItemFn, path: &syn::Path) -> TokenStream { let ident = &item_fn.sig.ident; let path_span = item_fn.sig.ident.span(); let path = parse_quote_spanned!(path_span=> #path :: #ident); - *item_fn = generate_extern_spec_function_stub(item_fn, &path, ExternSpecKind::Method); + generate_extern_spec_function_stub(item_fn, &path, ExternSpecKind::Method) } diff --git a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/mods.rs b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/mods.rs index 2b80e7e7d9c..b9c9ee3029c 100644 --- a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/mods.rs +++ b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/mods.rs @@ -9,46 +9,31 @@ use super::{ common::check_is_stub, functions::{rewrite_fn, rewrite_stub}, }; -use crate::specifications::common::generate_mod_name; use proc_macro2::TokenStream; -use quote::quote; use syn::spanned::Spanned; -pub fn rewrite_extern_spec( - item_mod: &mut syn::ItemMod, - path: syn::Path, -) -> syn::Result { - rewrite_mod(item_mod, &path)?; - Ok(quote!(#item_mod)) -} - -fn rewrite_mod(item_mod: &mut syn::ItemMod, path: &syn::Path) -> syn::Result<()> { - if item_mod.content.is_none() { - return Ok(()); - } - - let mut path = path.clone(); +pub fn rewrite_mod(item_mod: &syn::ItemMod, mut path: syn::Path) -> syn::Result { path.segments.push(syn::PathSegment { ident: item_mod.ident.clone(), arguments: syn::PathArguments::None, }); - item_mod.ident = syn::Ident::new(&generate_mod_name(&item_mod.ident), item_mod.span()); - for item in item_mod.content.as_mut().unwrap().1.iter_mut() { + let mut rewritten_fns = TokenStream::new(); + for item in item_mod.content.as_ref().iter().flat_map(|c| &c.1) { match item { - syn::Item::Fn(item_fn) => { + syn::Item::Fn(ref item_fn) => { check_is_stub(&item_fn.block)?; - rewrite_fn(item_fn, &path); + rewritten_fns.extend(rewrite_fn(item_fn, &path)); } - syn::Item::Mod(inner_mod) => { - rewrite_mod(inner_mod, &path)?; - } - syn::Item::Verbatim(tokens) => { - rewrite_stub(tokens, &path)?; - } - syn::Item::Use(_) => {} + syn::Item::Mod(ref inner_mod) => rewritten_fns.extend(rewrite_mod(inner_mod, path.clone())?), + syn::Item::Verbatim(ref tokens) => rewritten_fns.extend(rewrite_stub(tokens, &path)?), + syn::Item::Use(_) => rewritten_fns.extend(syn::Error::new( + item.span(), + "`use` statements have no effect in #[extern_spec] modules; module contents share the outer scope.", + ).to_compile_error()), _ => return Err(syn::Error::new(item.span(), "unexpected item")), } } - Ok(()) + + Ok(rewritten_fns) } diff --git a/prusti-contracts/prusti-specs/src/lib.rs b/prusti-contracts/prusti-specs/src/lib.rs index 2229b8d5f57..91d53564f11 100644 --- a/prusti-contracts/prusti-specs/src/lib.rs +++ b/prusti-contracts/prusti-specs/src/lib.rs @@ -756,13 +756,12 @@ pub fn extern_spec(attr: TokenStream, tokens: TokenStream) -> TokenStream { syn::Item::Trait(item_trait) => { extern_spec_rewriter::traits::rewrite_extern_spec(&item_trait, mod_path) } - syn::Item::Mod(mut item_mod) => { - extern_spec_rewriter::mods::rewrite_extern_spec(&mut item_mod, mod_path) + syn::Item::Mod(item_mod) => { + extern_spec_rewriter::mods::rewrite_mod(&item_mod, mod_path) } // we're expecting function stubs, so they aren't represented as Item::Fn - syn::Item::Verbatim(mut stub_tokens) => { - extern_spec_rewriter::functions::rewrite_stub(&mut stub_tokens, &mod_path)?; - Ok(stub_tokens) + syn::Item::Verbatim(stub_tokens) => { + extern_spec_rewriter::functions::rewrite_stub(&stub_tokens, &mod_path) } _ => Err(syn::Error::new( Span::call_site(), // this covers the entire macro invocation, unlike attr.span() which changes to only cover arguments if possible diff --git a/prusti-contracts/prusti-specs/src/specifications/common.rs b/prusti-contracts/prusti-specs/src/specifications/common.rs index 7e10a4161c7..bf949348049 100644 --- a/prusti-contracts/prusti-specs/src/specifications/common.rs +++ b/prusti-contracts/prusti-specs/src/specifications/common.rs @@ -122,11 +122,6 @@ pub(crate) fn generate_struct_name_for_trait(item: &syn::ItemTrait) -> String { format!("PrustiTrait{}_{}", item.ident, uuid) } -pub(crate) fn generate_mod_name(ident: &syn::Ident) -> String { - let uuid = Uuid::new_v4().simple(); - format!("{}_{}", ident, uuid) -} - fn generate_name_for_type(ty: &syn::Type) -> Option { match ty { syn::Type::Path(ty_path) => Some(String::from_iter( From e29553ce9b56bb830a220ccb8ceaf7a6b2aab8a3 Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Thu, 12 Jan 2023 19:35:20 +0100 Subject: [PATCH 63/64] update tests --- .../extern-spec/mods/legacy-use-statement.rs | 17 +++++++++++++++++ .../tests/parse/fail/extern-spec/no-bodies.rs | 2 -- .../tests/verify/pass/extern-spec/module-arg.rs | 2 -- .../verify_overflow/pass/extern-spec/swap.rs | 2 -- 4 files changed, 17 insertions(+), 6 deletions(-) create mode 100644 prusti-tests/tests/parse/fail/extern-spec/mods/legacy-use-statement.rs diff --git a/prusti-tests/tests/parse/fail/extern-spec/mods/legacy-use-statement.rs b/prusti-tests/tests/parse/fail/extern-spec/mods/legacy-use-statement.rs new file mode 100644 index 00000000000..cd0d3066a4c --- /dev/null +++ b/prusti-tests/tests/parse/fail/extern-spec/mods/legacy-use-statement.rs @@ -0,0 +1,17 @@ +use prusti_contracts::*; + +fn main() {} + +#[extern_spec] +mod example { + // parsing continues even after the first error + use crate::*; //~ ERROR: `use` statements have no effect in #[extern_spec] modules; module contents share the outer scope. + use crate::*; //~ ERROR: `use` statements have no effect in #[extern_spec] modules; module contents share the outer scope. + + #[pure] + fn foo(); +} + +mod example { + pub fn foo() {} +} diff --git a/prusti-tests/tests/parse/fail/extern-spec/no-bodies.rs b/prusti-tests/tests/parse/fail/extern-spec/no-bodies.rs index 9fd6e630f14..319d00f08a9 100644 --- a/prusti-tests/tests/parse/fail/extern-spec/no-bodies.rs +++ b/prusti-tests/tests/parse/fail/extern-spec/no-bodies.rs @@ -21,8 +21,6 @@ impl Clone for i32 { #[extern_spec] mod core { mod mem { - use crate::*; - #[pure] pub fn size_of() -> usize {} //~ ERROR: Unexpected method body. (Extern specs only define specifications.) } diff --git a/prusti-tests/tests/verify/pass/extern-spec/module-arg.rs b/prusti-tests/tests/verify/pass/extern-spec/module-arg.rs index 8a73b3f94c9..ed32fa1f210 100644 --- a/prusti-tests/tests/verify/pass/extern-spec/module-arg.rs +++ b/prusti-tests/tests/verify/pass/extern-spec/module-arg.rs @@ -35,8 +35,6 @@ where #[extern_spec(module)] mod inner { - use crate::*; - #[ensures(result == 1)] fn free_1() -> i32; } diff --git a/prusti-tests/tests/verify_overflow/pass/extern-spec/swap.rs b/prusti-tests/tests/verify_overflow/pass/extern-spec/swap.rs index 405cbc03da0..95098299184 100644 --- a/prusti-tests/tests/verify_overflow/pass/extern-spec/swap.rs +++ b/prusti-tests/tests/verify_overflow/pass/extern-spec/swap.rs @@ -7,8 +7,6 @@ use prusti_contracts::*; #[extern_spec] mod std { mod mem { - use prusti_contracts::*; - #[ensures(*a == old(*b) && *b == old(*a))] pub fn swap(a: &mut T, b: &mut T); } From c1743f73758c29feb89920a5202d97daf020fd3f Mon Sep 17 00:00:00 2001 From: Julian Dunskus Date: Thu, 12 Jan 2023 20:17:50 +0100 Subject: [PATCH 64/64] only mangle free functions keep the changes to a minimum --- .../prusti-specs/src/extern_spec_rewriter/common.rs | 10 +++++++--- .../prusti-specs/src/extern_spec_rewriter/functions.rs | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/common.rs b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/common.rs index 6d2bf09d129..69e00ba7ed5 100644 --- a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/common.rs +++ b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/common.rs @@ -144,7 +144,8 @@ pub(crate) fn generate_extern_spec_method_stub TokenStream { let signature = function.sig(); let mut signature = with_explicit_lifetimes(signature).unwrap_or_else(|| signature.clone()); - signature.ident = format_ident!("prusti_extern_spec_{}", signature.ident); + if mangle_name { + signature.ident = format_ident!("prusti_extern_spec_{}", signature.ident); + } // Make elided lifetimes explicit, if necessary. let attrs = function.attrs().clone(); let generic_params = &signature.generic_params_as_call_args(); @@ -203,7 +207,7 @@ pub(crate) fn generate_extern_spec_function_stub ( #args ) } diff --git a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/functions.rs b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/functions.rs index 852718b4340..0df7ef84aa3 100644 --- a/prusti-contracts/prusti-specs/src/extern_spec_rewriter/functions.rs +++ b/prusti-contracts/prusti-specs/src/extern_spec_rewriter/functions.rs @@ -47,5 +47,5 @@ pub fn rewrite_fn(item_fn: &syn::ItemFn, path: &syn::Path) -> TokenStream { let path_span = item_fn.sig.ident.span(); let path = parse_quote_spanned!(path_span=> #path :: #ident); - generate_extern_spec_function_stub(item_fn, &path, ExternSpecKind::Method) + generate_extern_spec_function_stub(item_fn, &path, ExternSpecKind::Method, true) }