Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Prusti-ish frontend to Creusot #932

Open
wants to merge 102 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
102 commits
Select commit Hold shift + click to select a range
a62f47c
Initial implementation of Prusti to Creusot conversion
dewert99 Oct 20, 2022
03312a2
Fixed handling of after_expiry
dewert99 Oct 20, 2022
5944625
Merge remote-tracking branch 'origin/master' into prusti
dewert99 Oct 21, 2022
9d02456
Fixed tests after merge
dewert99 Oct 21, 2022
128a82e
Merge remote-tracking branch 'origin/641' into prusti
dewert99 Oct 21, 2022
482418c
Added support for prusti logical functions (TODO treat them different…
dewert99 Oct 22, 2022
a54842a
Added support for calling logical functions with home signatures.
dewert99 Oct 29, 2022
f175b29
Switched logical calls to trait methods to use the implementors logic…
dewert99 Oct 29, 2022
a0bb4aa
Improved handling of associated types
dewert99 Oct 31, 2022
f4bb934
Fixed introduced issue with regular creusot functions
dewert99 Nov 1, 2022
0e4c737
Added `curr` and `expiry` stubs
dewert99 Nov 2, 2022
c36c45a
Merge remote-tracking branch 'origin/master' into prusti
dewert99 Nov 2, 2022
64728a5
Switched prusti import to prusti_prelude and added support for implic…
dewert99 Nov 4, 2022
332144e
Fixed some quantifiers and box dereferences and added work around for…
dewert99 Nov 7, 2022
dfc2bdc
Fixed issue with lifetimes bound in impl block and added prusti versi…
dewert99 Nov 7, 2022
23d39fe
Tricked at_expiry into using an early-bound lifetime
dewert99 Nov 17, 2022
92267df
Hacky patch to help avoid subtly wrong uses of <&mut T>::shallow_model()
dewert99 Nov 17, 2022
cecc51b
Merge branch 'master' into prusti
dewert99 Jun 6, 2023
7c28341
Switch translation to work with new rustc
dewert99 Jun 7, 2023
c99e72a
Mostly got tests passing again
dewert99 Jun 8, 2023
daecf8d
Switched to a more precise region tracking system and fixed remaining…
dewert99 Jun 9, 2023
8cecdaa
Extracted away pearlite
dewert99 Jun 9, 2023
a6d4a60
Improved support for constructors
dewert99 Jun 9, 2023
f595c95
Switched behaviour when calling function without a "home-signature" t…
dewert99 Jun 9, 2023
7c6ec37
Improve error messages
dewert99 Jun 9, 2023
e6e0dac
Refactor to support outlive based requirements
dewert99 Jun 13, 2023
1fe9ad4
Fixed handling of shared references and boxes.
dewert99 Jun 20, 2023
7910fbf
Prevented making references to invalid types
dewert99 Jun 20, 2023
0907116
Started copy types to be coerced into the current time slice if they …
dewert99 Jun 20, 2023
f683ec9
Allowed copy types to be coerced into the current time slice if they …
dewert99 Jun 21, 2023
89a6d29
Added smallvec dependency
dewert99 Jun 21, 2023
bbed4eb
Fixed issue where copy types could be coerced into a time slice in th…
dewert99 Jun 21, 2023
21b4e12
Made unspecified home signatures default to using 'curr everywhere
dewert99 Jun 21, 2023
dde9f05
Extracted constants
dewert99 Jun 21, 2023
373f03c
Added zombie lint to be more strict and prevent types with invalid ho…
dewert99 Jun 22, 2023
2d1994a
Improved lint handling
dewert99 Jun 22, 2023
63a8fe4
Fixed issue with at_expiry
dewert99 Jun 22, 2023
2e957f3
Switched zombie lint to used non type based information, this makes i…
dewert99 Jun 22, 2023
d948039
Added test
dewert99 Jun 22, 2023
0d19502
Merge branch 'master' into prusti
dewert99 Jun 27, 2023
6f63c56
Blessed changes to tests caused by merge
dewert99 Jun 27, 2023
75736f8
Allowed logic funtions to infer some outlive relations based on type …
dewert99 Jun 28, 2023
348dd5f
Fixed bug with when calling functions with 'curr in there signature
dewert99 Jun 28, 2023
55d326c
Fixed bug with at_expiry
dewert99 Jun 28, 2023
7ba49c4
Fixed bug with normalization
dewert99 Jun 29, 2023
6f7691e
Refactored, improved 'static support and added snapshot feature
dewert99 Jul 2, 2023
1345678
Fixed bug with quantifiers
dewert99 Jul 4, 2023
45986a8
Made equality require types to be valid
dewert99 Jul 4, 2023
31a28be
Fixed bug with tuples
dewert99 Jul 4, 2023
9a8c29a
Allowed de-referencing an &'a &mut T to an &'a T
dewert99 Jul 12, 2023
af857cc
Merge branch 'master' into prusti
dewert99 Sep 16, 2023
55d3b8e
Update to support newer rustc (Note: failing tests)
dewert99 Sep 23, 2023
518c7ec
Switch to translation that follows design from thesis
dewert99 Oct 7, 2023
813d483
Added more lints
dewert99 Oct 10, 2023
d1d4620
Added missing test files
dewert99 Oct 10, 2023
3a4e224
Prevented using at_expiry with a state_set parameter in a logic function
dewert99 Oct 11, 2023
f78dfea
Prevented using after_expiry with a state_set parameter in a logic fu…
dewert99 Oct 11, 2023
09309f5
Fixed test
dewert99 Oct 11, 2023
7deef66
Added support for ghost functions
dewert99 Oct 11, 2023
b0d9367
Fixed bug with implicit outlives constraints and added explicit const…
dewert99 Oct 13, 2023
20c0399
Refactored out type for states
dewert99 Oct 14, 2023
c5feeb8
Refactor
dewert99 Oct 15, 2023
cf35a14
Switch to using more SSO types
dewert99 Oct 16, 2023
5b303f0
Added "Plain" (todo derive)
dewert99 Oct 16, 2023
5f21aa8
Merge branch 'master' into prusti
dewert99 Oct 16, 2023
2acf68d
fixed merge
dewert99 Oct 16, 2023
4e1cef9
Merge remote-tracking branch 'origin/master' into prusti
dewert99 Oct 18, 2023
fbc9e18
Removed old WithStatic feature
dewert99 Nov 1, 2023
711c57b
Started refactor to avoid using rustc_infer, and allowed joining zombies
dewert99 Nov 2, 2023
2235ec6
Continued the refactor to avoid using rustc_infer
dewert99 Nov 9, 2023
88f10ab
Revert Cargo.toml IDE hack
dewert99 Nov 9, 2023
d969deb
Merge remote-tracking branch 'origin/master' into prusti
dewert99 Jan 13, 2024
373f9ef
Started trying to allow type parameters to be instantiated with Zombie
dewert99 Nov 21, 2023
ee6afd8
Added failing tests and stubs to prepare for `SnapEq`
dewert99 Jan 15, 2024
e4c60fe
Improved handling for instantiating type param with zombie
dewert99 Jan 18, 2024
fdd8e7d
Added `SnapEq` handling
dewert99 Jan 18, 2024
16fa4fd
Improved types produced by when converting to zombie
dewert99 Jan 19, 2024
7810615
Clean-up and rename at_expiry->at
dewert99 Jan 24, 2024
9670325
Renamed and improved handling of global states
dewert99 Jan 25, 2024
78e99e8
Merge remote-tracking branch 'origin/master' into prusti
dewert99 Jan 25, 2024
3e273cb
bless
dewert99 Jan 25, 2024
d69fa0d
Clean up
dewert99 Jan 25, 2024
41bbc35
Rustfmt and re-bless tests
dewert99 Jan 25, 2024
0355cc0
Merge remote-tracking branch 'origin/master' into prusti
dewert99 Jan 29, 2024
732f8f8
Merge remote-tracking branch 'origin/master' into prusti
dewert99 Feb 7, 2024
aa44a8a
Handle rustc update
dewert99 Feb 8, 2024
471dc66
Merge remote-tracking branch 'origin/master' into prusti
dewert99 Mar 14, 2024
573b92a
Handle rustc update
dewert99 Mar 15, 2024
14ef4fd
Merge remote-tracking branch 'origin/master' into prusti
dewert99 Mar 15, 2024
8a15dfc
Merge branch 'creusot-rs:master' into prusti
dewert99 Mar 20, 2024
cf52904
Merge tag 'refs/tags/v0.1' into prusti
dewert99 May 24, 2024
93c696a
Handed rustc update
dewert99 May 24, 2024
d7cb970
Fix tests
dewert99 May 24, 2024
6e9a7c7
Add description to creusot-contracts
xldenis May 20, 2024
e80700d
Fix the `mlcfg` script
arnaudgolfouse May 22, 2024
390a1be
upgrade why3 and cleanup the session for the red_black_tree test
Armael May 18, 2024
92bb6a4
Fix metadata load path
xldenis May 30, 2024
277c9cb
Bump versions
Jun 25, 2024
428b5ec
It is better to use the repository field in Cargo.toml
szabgab Jun 25, 2024
d30d5f9
Merge tag 'refs/tags/v0.1.1' into prusti
dewert99 Jul 13, 2024
1e7bfd9
Merge tag 'v0.2.0' into prusti
dewert99 Sep 7, 2024
9fb4bac
Handle rustc update
dewert99 Sep 7, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 40 additions & 0 deletions creusot-contracts-dummy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,43 @@ pub fn derive_deep_model(_: TS1) -> TS1 {
pub fn derive_resolve(_: TS1) -> TS1 {
TS1::new()
}

#[proc_macro_attribute]
pub fn prusti_requires(_: TS1, tokens: TS1) -> TS1 {
tokens
}

#[proc_macro_attribute]
pub fn prusti_ensures(_: TS1, tokens: TS1) -> TS1 {
tokens
}

#[proc_macro_attribute]
pub fn prusti_ensures_expiry(_: TS1, tokens: TS1) -> TS1 {
tokens
}

#[proc_macro_attribute]
pub fn prusti_logic(_: TS1, _: TS1) -> TS1 {
TS1::new()
}

#[proc_macro_attribute]
pub fn prusti_logic_prophetic(_: TS1, _: TS1) -> TS1 {
TS1::new()
}

#[proc_macro_attribute]
pub fn prusti_predicate(_: TS1, _: TS1) -> TS1 {
TS1::new()
}

#[proc_macro_attribute]
pub fn prusti_predicate_prophetic(_: TS1, _: TS1) -> TS1 {
TS1::new()
}

#[proc_macro_attribute]
pub fn prusti_law(_: TS1, _: TS1) -> TS1 {
TS1::new()
}
135 changes: 118 additions & 17 deletions creusot-contracts-proc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use proc_macro2::{Span, TokenStream};
use quote::{quote, quote_spanned, ToTokens, TokenStreamExt};
use std::iter;
use syn::{
parse::{discouraged::Speculative, Parse, Result},
parse::{discouraged::Speculative, Parse, ParseStream, Parser, Result},
spanned::Spanned,
*,
};
Expand All @@ -19,6 +19,8 @@ mod pretyping;

mod derive;

const NONE: Option<Ident> = None; // Replace with Option<!> when it becomes available

trait FilterAttrs<'a> {
type Ret: Iterator<Item = &'a Attribute>;

Expand Down Expand Up @@ -164,21 +166,19 @@ fn req_body(p: &Term) -> TokenStream {
})
}

fn spec_attrs(tag: &Ident) -> TokenStream {
let name_tag = format!("{}", quote! { #tag });
fn spec_attrs(name_tag: &str, prusti_info: impl ToTokens) -> TokenStream {
quote! {
#[creusot::no_translate]
#[creusot::item=#name_tag]
#[creusot::spec]
#[creusot::no_translate]
#[creusot::item=#name_tag]
#[creusot::spec]
#prusti_info
}
}

// Generate a token stream for the item representing a specific
// `requires` or `ensures`
fn fn_spec_item(tag: Ident, result: Option<FnArg>, p: Term) -> TokenStream {
fn fn_spec_item(attrs: TokenStream, result: Option<FnArg>, p: Term) -> TokenStream {
let req_body = req_body(&p);
let attrs = spec_attrs(&tag);

quote! {
#[allow(unused_must_use)]
let _ =
Expand All @@ -188,9 +188,8 @@ fn fn_spec_item(tag: Ident, result: Option<FnArg>, p: Term) -> TokenStream {
}
}

fn sig_spec_item(tag: Ident, mut sig: Signature, p: Term) -> TokenStream {
fn sig_spec_item(attrs: TokenStream, tag: Ident, mut sig: Signature, p: Term) -> TokenStream {
let req_body = req_body(&p);
let attrs = spec_attrs(&tag);
sig.ident = tag;
sig.output = parse_quote! { -> bool };

Expand All @@ -202,6 +201,10 @@ fn sig_spec_item(tag: Ident, mut sig: Signature, p: Term) -> TokenStream {

#[proc_macro_attribute]
pub fn requires(attr: TS1, tokens: TS1) -> TS1 {
requires_helper(attr, tokens, NONE)
}

fn requires_helper(attr: TS1, tokens: TS1, prusti_info: impl ToTokens) -> TS1 {
let mut item = parse_macro_input!(tokens as ContractSubject);
let term = parse_macro_input!(attr as Term);
item.mark_unused();
Expand All @@ -210,17 +213,19 @@ pub fn requires(attr: TS1, tokens: TS1) -> TS1 {

let name_tag = format!("{}", quote! { #req_name });

let attrs = spec_attrs(&name_tag, prusti_info);

match item {
ContractSubject::FnOrMethod(fn_or_meth) if fn_or_meth.is_trait_signature() => {
let requires_tokens = sig_spec_item(req_name, fn_or_meth.sig.clone(), term);
let requires_tokens = sig_spec_item(attrs, req_name, fn_or_meth.sig.clone(), term);
TS1::from(quote! {
#requires_tokens
#[creusot::clause::requires=#name_tag]
#fn_or_meth
})
}
ContractSubject::FnOrMethod(mut f) => {
let requires_tokens = fn_spec_item(req_name, None, term);
let requires_tokens = fn_spec_item(attrs, None, term);

f.body.as_mut().map(|b| b.stmts.insert(0, Stmt::Item(Item::Verbatim(requires_tokens))));
TS1::from(quote! {
Expand All @@ -229,7 +234,7 @@ pub fn requires(attr: TS1, tokens: TS1) -> TS1 {
})
}
ContractSubject::Closure(mut clos) => {
let requires_tokens = fn_spec_item(req_name, None, term);
let requires_tokens = fn_spec_item(attrs, None, term);
let body = &clos.body;
*clos.body = parse_quote!({let res = #body; #requires_tokens res});
TS1::from(quote! {
Expand All @@ -242,13 +247,19 @@ pub fn requires(attr: TS1, tokens: TS1) -> TS1 {

#[proc_macro_attribute]
pub fn ensures(attr: TS1, tokens: TS1) -> TS1 {
ensures_helper(attr, tokens, NONE)
}

fn ensures_helper(attr: TS1, tokens: TS1, prusti_info: impl ToTokens) -> TS1 {
let mut item = parse_macro_input!(tokens as ContractSubject);
let term = parse_macro_input!(attr as Term);
item.mark_unused();

let ens_name = generate_unique_ident(&item.name());
let name_tag = format!("{}", quote! { #ens_name });

let attrs = spec_attrs(&name_tag, prusti_info);

match item {
ContractSubject::FnOrMethod(s) if s.is_trait_signature() => {
let result = match s.sig.output {
Expand All @@ -258,7 +269,7 @@ pub fn ensures(attr: TS1, tokens: TS1) -> TS1 {

let mut sig = s.sig.clone();
sig.inputs.push(result);
let ensures_tokens = sig_spec_item(ens_name, sig, term);
let ensures_tokens = sig_spec_item(attrs, ens_name, sig, term);
TS1::from(quote! {
#ensures_tokens
#[creusot::clause::ensures=#name_tag]
Expand All @@ -270,7 +281,7 @@ pub fn ensures(attr: TS1, tokens: TS1) -> TS1 {
ReturnType::Default => parse_quote! { result : () },
ReturnType::Type(_, ref ty) => parse_quote! { result : #ty },
};
let ensures_tokens = fn_spec_item(ens_name, Some(result), term);
let ensures_tokens = fn_spec_item(attrs, Some(result), term);

f.body.as_mut().map(|b| b.stmts.insert(0, Stmt::Item(Item::Verbatim(ensures_tokens))));
TS1::from(quote! {
Expand All @@ -280,7 +291,6 @@ pub fn ensures(attr: TS1, tokens: TS1) -> TS1 {
}
ContractSubject::Closure(mut clos) => {
let req_body = req_body(&term);
let attrs = spec_attrs(&ens_name);
let body = &clos.body;
*clos.body = parse_quote!({
let res = #body;
Expand Down Expand Up @@ -732,3 +742,94 @@ pub fn derive_deep_model(tokens: TS1) -> TS1 {
pub fn derive_resolve(tokens: TS1) -> TS1 {
derive::derive_resolve(tokens)
}

// Prusti Macros
#[proc_macro_attribute]
pub fn prusti_requires(attr: TS1, tokens: TS1) -> TS1 {
let prusti_info = quote!(#[creusot::prusti::ts="old"]);
requires_helper(attr, tokens, prusti_info)
}

#[proc_macro_attribute]
pub fn prusti_ensures(attr: TS1, tokens: TS1) -> TS1 {
let prusti_info = quote!(#[creusot::prusti::ts="curr"]);
ensures_helper(attr, tokens, prusti_info)
}

#[proc_macro_attribute]
pub fn prusti_ensures_expiry(attr: TS1, tokens: TS1) -> TS1 {
let parser = |input: ParseStream| {
let lookahead = input.lookahead1();
if lookahead.peek(Lifetime) {
let lt: Lifetime = input.parse()?;
let _: Token![,] = input.parse()?;
let rest: TokenStream = input.parse()?;
Ok((Some(lt), rest))
} else {
Ok((None, input.parse()?))
}
};
let split = parser.parse(attr);
let (lifetime, rest) = match split {
Ok(split) => split,
Err(err) => return err.into_compile_error().into(),
};
let prusti_info = match lifetime {
Some(lifetime) => {
let lifetime_string = format!("{}", lifetime);
let lifetime = LitStr::new(&lifetime_string, lifetime.span());
quote!(#[creusot::prusti::ts=#lifetime])
}
None => quote!(#[creusot::prusti::ts="'_"]),
};
ensures_helper(rest.into(), tokens, prusti_info)
}

fn prusti_logic_gen(attr: TS1, tokens: TS1, creusot_macro: TokenStream, allow_final: bool) -> TS1 {
let attr = TokenStream::from(attr);
let tokens = TokenStream::from(tokens);
let sig = format!("{attr}");
let sig = LitStr::new(&sig, attr.span());
let forbid = if allow_final { None } else { Some(quote!(#[forbid(creusot::prusti_final)])) };
TS1::from(quote! {
#forbid
#[creusot::prusti::ts="curr"]
#[creusot::prusti::home_sig=#sig]
#[::creusot_contracts::#creusot_macro]
#tokens
})
}

#[proc_macro_attribute]
pub fn prusti_logic(attr: TS1, tokens: TS1) -> TS1 {
prusti_logic_gen(attr, tokens, quote!(logic), false)
}

#[proc_macro_attribute]
pub fn prusti_logic_prophetic(attr: TS1, tokens: TS1) -> TS1 {
prusti_logic_gen(attr, tokens, quote!(logic(prophectic)), true)
}

#[proc_macro_attribute]
pub fn prusti_predicate(attr: TS1, tokens: TS1) -> TS1 {
prusti_logic_gen(attr, tokens, quote!(predicate), false)
}

#[proc_macro_attribute]
pub fn prusti_predicate_prophetic(attr: TS1, tokens: TS1) -> TS1 {
prusti_logic_gen(attr, tokens, quote!(predicate(prophectic)), true)
}

#[proc_macro_attribute]
pub fn prusti_law(attr: TS1, tokens: TS1) -> TS1 {
let attr = TokenStream::from(attr);
let tokens = TokenStream::from(tokens);
let sig = format!("{attr}");
let sig = LitStr::new(&sig, attr.span());
TS1::from(quote! {
#[creusot::prusti::ts="curr"]
#[creusot::prusti::home_sig=#sig]
#[::creusot_contracts::law]
#tokens
})
}
16 changes: 16 additions & 0 deletions creusot-contracts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ pub mod snapshot {
pub mod ghost_ptr;
pub mod invariant;
pub mod model;
mod prusti;
pub mod resolve;
pub mod util;
pub mod well_founded;
Expand Down Expand Up @@ -224,10 +225,25 @@ mod base_prelude {
slice::SliceExt as _,
};
}

pub mod prusti_macros {
pub use base_macros::{
invariant, open, pearlite, proof_assert, prusti_ensures as ensures,
prusti_ensures_expiry as after_expiry, prusti_law as law, prusti_logic as logic,
prusti_logic_prophetic as logic_prophetic, prusti_predicate as predicate,
prusti_predicate_prophetic as predicate_prophetic, prusti_requires as requires, trusted,
variant,
};
}

pub mod prelude {
pub use crate::{base_prelude::*, macros::*};
}

pub mod prusti_prelude {
pub use crate::{base_prelude::*, prusti::*, prusti_macros::*};
}

pub use prelude::*;

// The std vec macro uses special magic to construct the array argument
Expand Down
Loading