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

Mutability translation with mutable cells #164

Closed
wants to merge 54 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
0674104
Make all params var, all tparams mutable, all functions pure.
yannbolliger May 10, 2021
20acaf5
Copy mutable params of tparam type.
yannbolliger May 10, 2021
65bea74
Adapt tests.
yannbolliger May 10, 2021
f85423f
Fresh copy on immutable/aliasable/safe borrow.
yannbolliger May 14, 2021
61e5bda
Fresh copy the return value.
yannbolliger May 14, 2021
e099413
Refactor to reduce unnecessary fresh copies.
yannbolliger May 14, 2021
61823a8
Remove mutable and var flag form user-facing side.
yannbolliger May 14, 2021
39a1a9a
Fix the map for mutable value types.
yannbolliger May 18, 2021
da0fb07
Improve documentation.
yannbolliger May 19, 2021
2fb5f06
Fresh copy let var initializer.
yannbolliger May 19, 2021
dbef2a3
Don't fresh copy matches/ifs.
yannbolliger May 20, 2021
67adab8
Add clone test case with fresh copy.
yannbolliger May 20, 2021
b12c594
Add negative test case.
yannbolliger May 20, 2021
d374f11
Be sure to fresh copy cloned objects.
yannbolliger May 21, 2021
9da10f8
Add cast correctness test case.
yannbolliger May 21, 2021
87b85cf
Improve comment.
yannbolliger May 26, 2021
4a67625
Add benchmarks for mutable references.
yannbolliger Jun 1, 2021
0c8a769
Extract mutable references (without drop/reassignment)
yannbolliger May 27, 2021
136a319
Detect function purity with signature.
yannbolliger May 28, 2021
c023032
Refactor ref/deref to own file.
yannbolliger May 28, 2021
6a69c14
Add is mut ref function.
yannbolliger May 31, 2021
df91384
Add Scala translation for mut-from-start approach.
yannbolliger Jun 1, 2021
97657c4
Lift entire var in MutRef if later mutably borrowed.
yannbolliger May 31, 2021
b176e0a
Add tests with self refs.
yannbolliger Jun 1, 2021
ee422ce
Support mutable references as method receiver.
yannbolliger Jun 1, 2021
c8b1f1a
Add test with mutable field borrowing.
yannbolliger Jun 2, 2021
890eb42
Rename to mut cell.
yannbolliger Jun 3, 2021
82bb074
Wrap all fields in MutCells.
yannbolliger Jun 3, 2021
a273631
Support mutably borrowing fields.
yannbolliger Jun 4, 2021
53c35d1
Add test with mutable pattern match.
yannbolliger Jun 4, 2021
5f409f7
Support pattern match on mutably borrowed fields.
yannbolliger Jun 4, 2021
43d5684
Make linter happy.
yannbolliger Jun 9, 2021
35420c4
Fix tuples to use mutcells.
yannbolliger Jun 9, 2021
de9f1d1
Add test (large) with tuples.
yannbolliger Jun 9, 2021
cd1101e
Fix pattern matching with mutable refs.
yannbolliger Jun 9, 2021
3b9b447
Check for deep mutability before fresh copy.
yannbolliger Jun 9, 2021
9d04ef8
Fix purity detection for nested mutable types.
yannbolliger Jun 11, 2021
b6238a3
Fix mutable by-value params containing mutable refs.
yannbolliger Jun 11, 2021
5009bf5
Fix mutable borrow of tuple field.
yannbolliger Jun 22, 2021
c004e7a
Add test with mutable tuples.
yannbolliger Jun 11, 2021
f240d19
Add test with by value type containing mut ref.
yannbolliger Jun 22, 2021
6705102
Adapt translation
yannbolliger Jun 24, 2021
cbcb0dc
Improve naming and docs.
yannbolliger Jun 24, 2021
5636145
Fix cloning for mutable cells.
yannbolliger Jun 25, 2021
050369b
Add support for mutating tuples.
yannbolliger Jun 25, 2021
db869c5
Update demo examples.
yannbolliger Jul 8, 2021
67b596d
Fix specs on mut self methods in implementations.
yannbolliger Jul 15, 2021
d08a1df
Add thesis example to demo folder.
yannbolliger Jul 15, 2021
ab6801c
Add test for nested mutable cells.
yannbolliger Jul 16, 2021
66c7658
Fix nesting of mutable cells.
yannbolliger Jul 16, 2021
6376e1a
Add old helper.
yannbolliger Jul 21, 2021
99840ff
Implement mem::replace and add test.
yannbolliger Jul 22, 2021
1df1d28
Disable two tests that time out due to Stainless bug
yannbolliger Jul 22, 2021
f650ff8
Add test and fix field deref.
yannbolliger Aug 16, 2021
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
15 changes: 13 additions & 2 deletions demo/examples/blocks.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
extern crate stainless;
use stainless::*;

fn foo(_n: i32) -> () {}

pub fn bar(x: i32) -> i32 {
foo(x);
let y = x * 2;
let y = x / 2;
foo(y);

if y <= 0 {
1
} else {
} else if x > 10 {
bar(x - 1) * x
} else {
y
}
}

#[pre(y != 123)]
pub fn sole_if(y: i32) {
if y == 123 {
panic!()
}
}

Expand Down
3 changes: 1 addition & 2 deletions demo/examples/external_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use stainless::*;

struct State(i32);

#[var(0)]
struct Printer(i32);

#[pure(state)]
Expand All @@ -18,6 +17,6 @@ fn work(state: State, printer: Printer) -> i32 {
do_sideeffectful_stuff(state, printer)
}

fn main() -> () {
pub fn main() -> () {
work(State(123), Printer(999));
}
2 changes: 1 addition & 1 deletion demo/examples/fact.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
extern crate stainless;
use stainless::*;

#[pre(x >= 0)]
#[pre(x >= 0 && x < 10)]
#[post(ret >= 0)]
pub fn fact(x: i32) -> i32 {
if x <= 0 {
Expand Down
4 changes: 2 additions & 2 deletions demo/examples/generic_id.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
extern crate stainless;

pub fn id<T>(x: T) -> T {
fn id<T>(x: T) -> T {
x
}

fn main() -> () {
pub fn main() -> () {
id(0);
}
13 changes: 4 additions & 9 deletions demo/examples/insertion_sort.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,6 @@ use stainless::*;
///
/// [1]: https://github.com/epfl-lara/stainless/blob/master/frontends/benchmarks/verification/valid/InsertionSort.scala

pub enum Option<T> {
None,
Some(T),
}

pub enum List<T> {
Nil,
Cons(T, Box<List<T>>),
Expand Down Expand Up @@ -53,11 +48,11 @@ impl List<i32> {
#[measure(self)]
pub fn min(&self) -> Option<i32> {
match self {
List::Nil => Option::None,
List::Nil => None,
List::Cons(x, xs) => match xs.min() {
Option::None => Option::Some(*x),
Option::Some(y) if *x < y => Option::Some(*x),
Option::Some(y) => Option::Some(y),
None => Some(*x),
Some(y) if *x < y => Some(*x),
Some(y) => Some(y),
},
}
}
Expand Down
16 changes: 12 additions & 4 deletions demo/examples/mut_local_fields.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
#![allow(dead_code, unused_assignments)]

extern crate stainless;
use stainless::*;

#[var(field)]
struct S {
field: i32,
}

#[pure]
fn set_field(mut s: S) -> S {
s.field = 456;
s
}

struct Outer(S);

#[pure]
fn set_inner_field(mut o: Outer) -> Outer {
o.0.field = 101112;
o
}

struct Gen<T>(T);

fn set_gen_field(mut g: Gen<S>) -> Gen<S> {
g = Gen(S { field: 161718 });
g
}

// As control, the same for a primitive type
fn set_int(mut s: i32) -> i32 {
s = 1000;
Expand All @@ -42,6 +45,11 @@ pub fn main() {
let o = set_inner_field(o);
assert!(o.0.field == 101112);

let s = S { field: 123 };
let g = Gen(s);
let g = set_gen_field(g);
assert!(g.0.field == 161718);

let i = set_int(12);
assert!(i == 1000);
}
65 changes: 65 additions & 0 deletions demo/examples/thesis_example.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
extern crate stainless;
use stainless::*;

trait Id {
/// Calculate ID for this object.
fn id(&self) -> isize;

#[law]
fn law_positive(&self) -> bool {
self.id() > 0
}
}

impl Id for String {
fn id(&self) -> isize {
123456
}
}

struct Container<K, V> {
pair: Option<(K, V)>,
}

impl<K, V> Container<K, V> {
#[post(ret.is_empty())]
pub fn new() -> Self {
Container { pair: None }
}

pub fn is_empty(&self) -> bool {
matches!(self.pair, None)
}

#[post(!self.is_empty())]
pub fn insert(&mut self, k: K, v: V) {
self.pair = Some((k, v))
}
}

impl<K: Id, V> Container<K, V> {
#[post((self.is_empty()).implies(matches!(ret, None)))]
pub fn get_mut_by_id(&mut self, id: isize) -> Option<&mut V> {
match &mut self.pair {
Some((k, v)) if k.id() == id => Some(v),
_ => None,
}
}
}

pub fn main() {
let mut cont = Container::new();
let id = 123456;
let key = "foo".to_string();

assert!(cont.is_empty());
assert!(matches!(cont.get_mut_by_id(id), None));

cont.insert(key.clone(), 0);
match cont.get_mut_by_id(id) {
Some(v) => *v = 1000,
_ => panic!("no value"),
};

assert!(matches!(cont, Container { pair: Some((k, 1000))} if k == key))
}
23 changes: 22 additions & 1 deletion demo/examples/tuples.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,25 @@ pub fn swap(t: (i32, i32)) -> (i32, i32) {
(t.1, t.0)
}

fn main() -> () {}
pub fn main() {
#[allow(unused_variables)]
let unit_tuple = ();

let unary_tuple = (123,);
assert!(unary_tuple.0 == 123);

let huge_tuple = (
0, "hello", 2, "world", -4, "!", 6, "how", 8, "are", 10, "you", 12, "?",
);

assert!(
huge_tuple.0
+ huge_tuple.2
+ huge_tuple.4
+ huge_tuple.6
+ huge_tuple.8
+ huge_tuple.10
+ huge_tuple.12
== 34
)
}
2 changes: 2 additions & 0 deletions demo/examples/type_class_specs.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![allow(unused_variables)]

extern crate stainless;
use stainless::*;

Expand Down
4 changes: 4 additions & 0 deletions libstainless/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ pub use set::*;
mod map;
pub use map::*;

pub fn old<T>(t: T) -> T {
t
}

pub trait Implies {
fn implies(self, b: Self) -> bool;
}
Expand Down
4 changes: 2 additions & 2 deletions libstainless/src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ where
self.map.contains_key(key)
}

pub fn insert(&self, key: K, val: V) -> Self {
pub fn insert(self, key: K, val: V) -> Self {
Self {
map: self.map.update(key, val),
}
}

pub fn remove(&self, key: &K) -> Self {
pub fn remove(self, key: &K) -> Self {
Self {
map: self.map.without(key),
}
Expand Down
20 changes: 6 additions & 14 deletions libstainless_macros/src/implementation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,27 +220,19 @@ fn replace_param(args: &Punctuated<FnArg, Token![,]>) -> Punctuated<FnArg, Token
let fn_arg_tys: Vec<_> = args.iter().cloned().collect();
(match &fn_arg_tys[..] {
[FnArg::Receiver(Receiver {
mutability: None,
mutability,
reference,
..
}), args @ ..] => {
let new_self: FnArg = if reference.is_some() {
parse_quote! { _self: &Self }
} else {
parse_quote! { _self: Self }
let new_self: FnArg = match (mutability, reference) {
(None, None) => parse_quote! { _self: Self },
(None, Some(_)) => parse_quote! { _self: &Self },
(Some(_), None) => parse_quote! { mut _self: Self },
(Some(_), Some(_)) => parse_quote! { _self: &mut Self },
};
[&[new_self], args].concat()
}

[FnArg::Receiver(Receiver {
mutability: Some(_),
reference: None,
..
}), args @ ..] => {
let new_self: FnArg = parse_quote! { mut _self: Self };
[&[new_self], args].concat()
}

args => args.to_vec(),
})
.into_iter()
Expand Down
2 changes: 1 addition & 1 deletion libstainless_macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ macro_rules! define_flags {
}
}

define_flags!(external, pure, mutable, var, law);
define_flags!(external, pure, law);
6 changes: 6 additions & 0 deletions stainless_data/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,12 @@ impl ValDef<'_> {
}
}

impl TypeParameter<'_> {
pub fn is_mutable(&self) -> bool {
self.flags.iter().any(|f| matches!(f, Flag::IsMutable(_)))
}
}

// Additional helpers that mirror those in Inox

pub fn Int32Literal(value: Int) -> BVLiteral {
Expand Down
Loading