]> git.lizzy.rs Git - rust.git/commitdiff
Continued sketching out code for checking states against preconditions.
authorTim Chevalier <chevalier@alum.wellesley.edu>
Thu, 7 Apr 2011 00:56:44 +0000 (17:56 -0700)
committerTim Chevalier <chevalier@alum.wellesley.edu>
Thu, 7 Apr 2011 00:58:18 +0000 (17:58 -0700)
It's still sketchy. I added a typestate annotation field to statements
tagged stmt_decl or stmt_expr, because a stmt_decl statement has a typestate
that's different from that of its child node. This necessitated trivial
changes to a bunch of other files all over to the compiler. I also added a
few small standard library functions, some of which I didn't actually end
up using but which I thought might be useful anyway.

16 files changed:
.gitignore
src/comp/front/ast.rs
src/comp/front/parser.rs
src/comp/middle/fold.rs
src/comp/middle/resolve.rs
src/comp/middle/trans.rs
src/comp/middle/ty.rs
src/comp/middle/typeck.rs
src/comp/middle/typestate_check.rs
src/comp/pretty/pprust.rs
src/comp/rustc.rc
src/comp/util/typestate_ann.rs
src/lib/_vec.rs
src/lib/bitv.rs
src/lib/option.rs
src/lib/util.rs

index dbfd7846a8e23c95b438a328176562ae6b2131d9..184f140273cfdfd321fecc958d213ec331a34934 100644 (file)
@@ -52,3 +52,4 @@ config.mk
 /test/
 /build/
 src/.DS_Store
+/stage0/
index d41e6d6068684cebf72698fb21e63458f7e19c1d..cf4145a5598060bf1bd56cb95ec36fc3d4a55f60 100644 (file)
@@ -215,8 +215,8 @@ fn unop_to_str(unop op) -> str {
 
 type stmt = spanned[stmt_];
 tag stmt_ {
-    stmt_decl(@decl);
-    stmt_expr(@expr);
+    stmt_decl(@decl, option.t[@ts_ann]);
+    stmt_expr(@expr, option.t[@ts_ann]);
     // These only exist in crate-level blocks.
     stmt_crate_directive(@crate_directive);
 }
@@ -495,7 +495,7 @@ fn index_native_view_item(native_mod_index index, @view_item it) {
 
 fn index_stmt(block_index index, @stmt s) {
     alt (s.node) {
-        case (ast.stmt_decl(?d)) {
+        case (ast.stmt_decl(?d,_)) {
             alt (d.node) {
                 case (ast.decl_local(?loc)) {
                     index.insert(loc.ident, ast.bie_local(loc));
index 27fdc7feb2d2f7320deaf1e0c79a1cc10074cb8f..7d1323cbafe5046899b2e065836d38e239a997e3 100644 (file)
@@ -11,6 +11,7 @@
 import util.common.filename;
 import util.common.span;
 import util.common.new_str_hash;
+import util.typestate_ann.ts_ann;
 
 tag restriction {
     UNRESTRICTED;
@@ -1555,13 +1556,13 @@ fn op_eq(token.token a, token.token b) -> bool {
         case (token.LET) {
             auto decl = parse_let(p);
             auto hi = p.get_span();
-            ret @spanned(lo, hi, ast.stmt_decl(decl));
+            ret @spanned(lo, hi, ast.stmt_decl(decl, none[@ts_ann]));
         }
 
         case (token.AUTO) {
             auto decl = parse_auto(p);
             auto hi = p.get_span();
-            ret @spanned(lo, hi, ast.stmt_decl(decl));
+            ret @spanned(lo, hi, ast.stmt_decl(decl, none[@ts_ann]));
         }
 
         case (_) {
@@ -1570,13 +1571,13 @@ fn op_eq(token.token a, token.token b) -> bool {
                 auto i = parse_item(p);
                 auto hi = i.span;
                 auto decl = @spanned(lo, hi, ast.decl_item(i));
-                ret @spanned(lo, hi, ast.stmt_decl(decl));
+                ret @spanned(lo, hi, ast.stmt_decl(decl, none[@ts_ann]));
 
             } else {
                 // Remainder are line-expr stmts.
                 auto e = parse_expr(p);
                 auto hi = p.get_span();
-                ret @spanned(lo, hi, ast.stmt_expr(e));
+                ret @spanned(lo, hi, ast.stmt_expr(e, none[@ts_ann]));
             }
         }
     }
@@ -1613,7 +1614,7 @@ fn do_index_arm(&hashmap[ast.ident,ast.def_id] index, @ast.pat pat) {
 
 fn stmt_to_expr(@ast.stmt stmt) -> option.t[@ast.expr] {
     alt (stmt.node) {
-        case (ast.stmt_expr(?e)) { ret some[@ast.expr](e); }
+        case (ast.stmt_expr(?e,_)) { ret some[@ast.expr](e); }
         case (_) { /* fall through */ }
     }
     ret none[@ast.expr];
@@ -1621,13 +1622,13 @@ fn stmt_to_expr(@ast.stmt stmt) -> option.t[@ast.expr] {
 
 fn stmt_ends_with_semi(@ast.stmt stmt) -> bool {
     alt (stmt.node) {
-        case (ast.stmt_decl(?d)) {
+        case (ast.stmt_decl(?d,_)) {
             alt (d.node) {
                 case (ast.decl_local(_)) { ret true; }
                 case (ast.decl_item(_)) { ret false; }
             }
         }
-        case (ast.stmt_expr(?e)) {
+        case (ast.stmt_expr(?e,_)) {
             alt (e.node) {
                 case (ast.expr_vec(_,_,_))      { ret true; }
                 case (ast.expr_tup(_,_))        { ret true; }
index 77c898366afdec172f778119fe04923ffbf396f1..fa85f791e762e45fb2da25efbdf3170c19edd8d7 100644 (file)
@@ -7,6 +7,7 @@
 import util.common.spanned;
 import util.common.span;
 import util.common.ty_mach;
+import util.typestate_ann.ts_ann;
 
 import front.ast;
 import front.ast.fn_decl;
 
      // Stmt folds.
      (fn(&ENV e, &span sp,
-         @decl decl) -> @stmt)                    fold_stmt_decl,
+         @decl decl, option.t[@ts_ann] a)
+      -> @stmt)                                   fold_stmt_decl,
 
      (fn(&ENV e, &span sp,
-         @expr e) -> @stmt)                       fold_stmt_expr,
+         @expr e, option.t[@ts_ann] a)
+      -> @stmt)                                   fold_stmt_expr,
 
      // Item folds.
      (fn(&ENV e, &span sp, ident ident,
@@ -788,14 +791,14 @@ fn fold_stmt[ENV](&ENV env, ast_fold[ENV] fld, &@stmt s) -> @stmt {
     }
 
     alt (s.node) {
-        case (ast.stmt_decl(?d)) {
+        case (ast.stmt_decl(?d, ?a)) {
             auto dd = fold_decl(env_, fld, d);
-            ret fld.fold_stmt_decl(env_, s.span, dd);
+            ret fld.fold_stmt_decl(env_, s.span, dd, a);
         }
 
-        case (ast.stmt_expr(?e)) {
+        case (ast.stmt_expr(?e, ?a)) {
             auto ee = fold_expr(env_, fld, e);
-            ret fld.fold_stmt_expr(env_, s.span, ee);
+            ret fld.fold_stmt_expr(env_, s.span, ee, a);
         }
     }
     fail;
@@ -1386,12 +1389,14 @@ fn identity_fold_pat_tag[ENV](&ENV e, &span sp, path p, vec[@pat] args,
 
 // Stmt identities.
 
-fn identity_fold_stmt_decl[ENV](&ENV env, &span sp, @decl d) -> @stmt {
-    ret @respan(sp, ast.stmt_decl(d));
+fn identity_fold_stmt_decl[ENV](&ENV env, &span sp, @decl d,
+                                option.t[@ts_ann] a) -> @stmt {
+    ret @respan(sp, ast.stmt_decl(d, a));
 }
 
-fn identity_fold_stmt_expr[ENV](&ENV e, &span sp, @expr x) -> @stmt {
-    ret @respan(sp, ast.stmt_expr(x));
+fn identity_fold_stmt_expr[ENV](&ENV e, &span sp, @expr x,
+                                option.t[@ts_ann] a) -> @stmt {
+    ret @respan(sp, ast.stmt_expr(x, a));
 }
 
 
@@ -1642,8 +1647,8 @@ fn new_identity_fold[ENV]() -> ast_fold[ENV] {
          fold_pat_bind    = bind identity_fold_pat_bind[ENV](_,_,_,_,_),
          fold_pat_tag     = bind identity_fold_pat_tag[ENV](_,_,_,_,_,_),
 
-         fold_stmt_decl   = bind identity_fold_stmt_decl[ENV](_,_,_),
-         fold_stmt_expr   = bind identity_fold_stmt_expr[ENV](_,_,_),
+         fold_stmt_decl   = bind identity_fold_stmt_decl[ENV](_,_,_,_),
+         fold_stmt_expr   = bind identity_fold_stmt_expr[ENV](_,_,_,_),
 
          fold_item_const= bind identity_fold_item_const[ENV](_,_,_,_,_,_,_),
          fold_item_fn   = bind identity_fold_item_fn[ENV](_,_,_,_,_,_,_),
index 20e60971dca77b80d8157459d903e7a86c6b71ae..28ae07dc85bba0773156c01029675ca48a166ada 100644 (file)
@@ -6,6 +6,7 @@
 import driver.session;
 import util.common.new_def_hash;
 import util.common.span;
+import util.typestate_ann.ts_ann;
 import std.map.hashmap;
 import std.list.list;
 import std.list.nil;
@@ -348,7 +349,7 @@ fn found_def_native_item(@ast.native_item i) -> def_wrap {
 
     fn found_decl_stmt(@ast.stmt s, namespace ns) -> def_wrap {
         alt (s.node) {
-            case (ast.stmt_decl(?d)) {
+            case (ast.stmt_decl(?d,_)) {
                 alt (d.node) {
                     case (ast.decl_local(?loc)) {
                         auto t = ast.def_local(loc.id);
index 980c88dbca52c7e4abefe0f17562f1af5c56c65b..fff3f126948d5978608083d607f949b220b9c3ed 100644 (file)
@@ -5208,11 +5208,11 @@ fn init_local(@block_ctxt cx, @ast.local local) -> result {
 fn trans_stmt(@block_ctxt cx, &ast.stmt s) -> result {
     auto bcx = cx;
     alt (s.node) {
-        case (ast.stmt_expr(?e)) {
+        case (ast.stmt_expr(?e,_)) {
             bcx = trans_expr(cx, e).bcx;
         }
 
-        case (ast.stmt_decl(?d)) {
+        case (ast.stmt_decl(?d,_)) {
             alt (d.node) {
                 case (ast.decl_local(?local)) {
                     bcx = init_local(bcx, local).bcx;
@@ -5302,7 +5302,7 @@ fn trans_block_cleanups(@block_ctxt cx,
     // use the index here.
     for (@ast.stmt s in b.node.stmts) {
         alt (s.node) {
-            case (ast.stmt_decl(?d)) {
+            case (ast.stmt_decl(?d,_)) {
                 alt (d.node) {
                     case (ast.decl_local(?local)) {
                         put local;
index f83bece7f20abce8deecbd0629971e94c58f1027..09c89fdfc28ce3ec2ee42145ecd316911b63f62f 100644 (file)
@@ -731,7 +731,7 @@ fn item_ty(@ast.item it) -> ty_params_and_ty {
 
 fn stmt_ty(@ast.stmt s) -> @t {
     alt (s.node) {
-        case (ast.stmt_expr(?e)) {
+        case (ast.stmt_expr(?e,_)) {
             ret expr_ty(e);
         }
         case (_) {
index ab0262f1753363b8c1fd3b599001d5e2d126a547..d969df5a25e4e425a971a5f586f304f68bae6159 100644 (file)
@@ -2479,12 +2479,12 @@ fn check_decl_local(&@fn_ctxt fcx, &@ast.decl decl) -> @ast.decl {
 
 fn check_stmt(&@fn_ctxt fcx, &@ast.stmt stmt) -> @ast.stmt {
     alt (stmt.node) {
-        case (ast.stmt_decl(?decl)) {
+        case (ast.stmt_decl(?decl,?a)) {
             alt (decl.node) {
                 case (ast.decl_local(_)) {
                     auto decl_1 = check_decl_local(fcx, decl);
                     ret @fold.respan[ast.stmt_](stmt.span,
-                                                ast.stmt_decl(decl_1));
+                                                ast.stmt_decl(decl_1, a));
                 }
 
                 case (ast.decl_item(_)) {
@@ -2495,9 +2495,9 @@ fn check_stmt(&@fn_ctxt fcx, &@ast.stmt stmt) -> @ast.stmt {
             ret stmt;
         }
 
-        case (ast.stmt_expr(?expr)) {
+        case (ast.stmt_expr(?expr,?a)) {
             auto expr_t = check_expr(fcx, expr);
-            ret @fold.respan[ast.stmt_](stmt.span, ast.stmt_expr(expr_t));
+            ret @fold.respan[ast.stmt_](stmt.span, ast.stmt_expr(expr_t, a));
         }
     }
 
index 64a17a7da0ca3db2812c0ab18998892330b45bcc..24bee1bd0348857e275eba283ed85771868e4d84 100644 (file)
@@ -11,6 +11,7 @@
 import front.ast.stmt_;
 import front.ast.stmt_decl;
 import front.ast.stmt_expr;
+import front.ast.stmt_crate_directive;
 import front.ast.decl_local;
 import front.ast.decl_item;
 import front.ast.ident;
 import util.typestate_ann.pre_and_post;
 import util.typestate_ann.get_pre;
 import util.typestate_ann.get_post;
+import util.typestate_ann.ann_precond;
+import util.typestate_ann.ann_prestate;
+import util.typestate_ann.set_precondition;
+import util.typestate_ann.set_postcondition;
+import util.typestate_ann.set_in_postcond;
 import util.typestate_ann.implies;
 import util.typestate_ann.pre_and_post_state;
 import util.typestate_ann.empty_states;
+import util.typestate_ann.empty_prestate;
+import util.typestate_ann.empty_ann;
+import util.typestate_ann.extend_prestate;
 
 import middle.ty;
 import middle.ty.ann_to_type;
 import std.option.t;
 import std.option.some;
 import std.option.none;
+import std.option.from_maybe;
 import std.map.hashmap;
 import std.list;
 import std.list.list;
 import std.list.find;
 import std._uint;
 import std.bitv;
+import std.util.fst;
+import std.util.snd;
 
 import util.typestate_ann;
 import util.typestate_ann.difference;
@@ -342,50 +354,41 @@ fn expr_ann(&expr e) -> ann {
   }
 }
 
-/* returns ann_none if this is the sort
- of statement where an ann doesn't make sense */
-fn stmt_ann(&stmt s) -> ann {
-  alt (s.node) {
-    case (stmt_decl(?d)) {
-      alt (d.node) {
-        case (decl_local(?l)) {
-          ret l.ann;
-        }
-        case (decl_item(?i)) {
-          ret ann_none; /* ????? */
-        }
+fn ann_to_ts_ann(ann a, uint nv) -> ts_ann {
+  alt (a) {
+    case (ann_none)         { ret empty_ann(nv); }
+    case (ann_type(_,_,?t)) {
+      alt (t) {
+        /* Kind of inconsistent. empty_ann()s everywhere
+         or an option of a ts_ann? */
+        case (none[@ts_ann])     { ret empty_ann(nv); }
+        case (some[@ts_ann](?t)) { ret *t; }
       }
     }
-    case (stmt_expr(?e)) {
-      ret expr_ann(*e);
-    }
-    case (_) {
-      ret ann_none;
-    }
   }
 }
 
-/* fails if e has no annotation */
-fn expr_pp(&expr e) -> pre_and_post {
-  alt (expr_ann(e)) {
-    case (ann_none) {
-      log "expr_pp: the impossible happened (no annotation)";
-      fail;
+fn stmt_ann(&stmt s) -> option.t[@ts_ann] {
+  alt (s.node) {
+    case (stmt_decl(_,?a)) {
+      ret a;
     }
-    case (ann_type(_, _, ?maybe_pp)) {
-      alt (maybe_pp) {
-        case (none[@ts_ann]) {
-          log "expr_pp: the impossible happened (no pre/post)";
-          fail;
-        }
-        case (some[@ts_ann](?p)) {
-          ret p.conditions;
-        }
-      }
+    case (stmt_expr(_,?a)) {
+      ret a;
+    }
+    case (stmt_crate_directive(_)) {
+      ret none[@ts_ann];
     }
   }
 }
 
+/*
+/* fails if no annotation */
+fn stmt_pp(&stmt s) -> pre_and_post {
+  ret (stmt_ann(s)).conditions;
+}
+*/
+
 /* fails if e has no annotation */
 fn expr_states(&expr e) -> pre_and_post_state {
   alt (expr_ann(e)) {
@@ -400,22 +403,24 @@ fn expr_states(&expr e) -> pre_and_post_state {
           fail;
         }
         case (some[@ts_ann](?p)) {
-          ret p.states;
+          // ret p.states;
         }
       }
     }
   }
 }
 
-/* fails if no annotation */
-fn stmt_pp(&stmt s) -> pre_and_post {
-  alt (stmt_ann(s)) {
+/* fails if e has no annotation */
+fn expr_pp(&expr e) -> pre_and_post {
+  alt (expr_ann(e)) {
     case (ann_none) {
+      log "expr_pp: the impossible happened (no annotation)";
       fail;
     }
     case (ann_type(_, _, ?maybe_pp)) {
       alt (maybe_pp) {
         case (none[@ts_ann]) {
+          log "expr_pp: the impossible happened (no pre/post)";
           fail;
         }
         case (some[@ts_ann](?p)) {
@@ -426,25 +431,18 @@ fn stmt_pp(&stmt s) -> pre_and_post {
   }
 }
 
-/* fails if no annotation */
-fn stmt_states(&stmt s) -> pre_and_post_state {
+fn stmt_states(&stmt s, uint nv) -> pre_and_post_state {
   alt (stmt_ann(s)) {
-    case (ann_none) {
-      fail;
+    case (none[@ts_ann]) {
+      ret empty_states(nv);
     }
-    case (ann_type(_, _, ?maybe_pp)) {
-      alt (maybe_pp) {
-        case (none[@ts_ann]) {
-          fail;
-        }
-        case (some[@ts_ann](?p)) {
-          ret p.states;
-        }
-      }
+    case (some[@ts_ann](?a)) {
+      ret a.states;
     }
   }
 }
 
+
 fn expr_precond(&expr e) -> precond {
   ret (expr_pp(e)).precondition;
 }
@@ -461,6 +459,7 @@ fn expr_poststate(&expr e) -> poststate {
   ret (expr_states(e)).poststate;
 }
 
+/*
 fn stmt_precond(&stmt s) -> precond {
   ret (stmt_pp(s)).precondition;
 }
@@ -468,13 +467,19 @@ fn stmt_precond(&stmt s) -> precond {
 fn stmt_postcond(&stmt s) -> postcond {
   ret (stmt_pp(s)).postcondition;
 }
+*/
+
+fn states_to_poststate(&pre_and_post_state ss) -> poststate {
+  ret ss.poststate;
+}
 
+/*
 fn stmt_prestate(&stmt s) -> prestate {
   ret (stmt_states(s)).prestate;
 }
-
-fn stmt_poststate(&stmt s) -> poststate {
-  ret (stmt_states(s)).poststate;
+*/
+fn stmt_poststate(&stmt s, uint nv) -> poststate {
+  ret (stmt_states(s, nv)).poststate;
 }
 
 /* returns a new annotation where the pre_and_post is p */
@@ -684,12 +689,19 @@ fn pp_one(&@expr e) -> pre_and_post {
   }
 }
 
-fn find_pre_post_for_each_stmt(_fn_info_map fm, &fn_info enclosing,
-                               &ast.stmt s) -> ast.stmt {
+impure fn gen(&fn_info enclosing, ts_ann a, def_id id) {
+  check(enclosing.contains_key(id));
+  let uint i = enclosing.get(id);
+
+  set_in_postcond(i, a.conditions);
+}
+
+fn find_pre_post_stmt(_fn_info_map fm, &fn_info enclosing, &ast.stmt s)
+  -> ast.stmt {
   auto num_local_vars = num_locals(enclosing);
 
   alt(s.node) {
-    case(ast.stmt_decl(?adecl)) {
+    case(ast.stmt_decl(?adecl, ?a)) {
       alt(adecl.node) {
         case(ast.decl_local(?alocal)) {
           alt(alocal.init) {
@@ -702,9 +714,25 @@ fn find_pre_post_for_each_stmt(_fn_info_map fm, &fn_info enclosing,
                 @rec(ty=alocal.ty, infer=alocal.infer,
                      ident=alocal.ident, init=some[initializer](a_i),
                      id=alocal.id, ann=res_ann);
+
+              let ts_ann stmt_ann;
+              alt (a) {
+                case (none[@ts_ann]) {
+                  stmt_ann = empty_ann(num_local_vars);
+                }
+                case (some[@ts_ann](?aa)) {
+                  stmt_ann = *aa;
+                }
+              }
+              /* Inherit ann from initializer, and add var being
+                 initialized to the postcondition */
+              set_precondition(stmt_ann, expr_precond(*r));
+              set_postcondition(stmt_ann, expr_postcond(*r));
+              gen(enclosing, stmt_ann, alocal.id); 
               let stmt_ res = stmt_decl(@respan(adecl.span,
-                                                decl_local(res_local)));
-              ret (respan(s.span, res));
+                                                decl_local(res_local)),
+                                        some[@ts_ann](@stmt_ann));
+              ret (respan(s.span, res)); 
             }
             case(none[ast.initializer]) {
               // log("pre/post for init of " + alocal.ident + ": none");
@@ -716,22 +744,30 @@ fn find_pre_post_for_each_stmt(_fn_info_map fm, &fn_info enclosing,
                      id=alocal.id, ann=res_ann);
               let stmt_ res =
                 stmt_decl
-                (@respan(adecl.span, decl_local(res_local)));
-              ret (respan (s.span, res));
+                (@respan(adecl.span, decl_local(res_local)),
+                 some[@ts_ann](@empty_ann(num_local_vars)));
+              ret respan(s.span, res); /* inherit ann from initializer */
             }
           }
         }
         case(decl_item(?anitem)) {
           auto res_item = find_pre_post_item(fm, enclosing, *anitem);
-          ret (respan(s.span, stmt_decl(@respan(adecl.span,
-                                               decl_item(@res_item))))); 
+          ret respan(s.span,
+                     stmt_decl(@respan(adecl.span,
+                                       decl_item(@res_item)),
+                               some[@ts_ann](@empty_ann(num_local_vars))));
         }
       }
     }
-    case(stmt_expr(?e)) {
+    case(stmt_expr(?e,_)) {
       log_expr(e);
       let @expr e_pp = find_pre_post_expr(enclosing, *e);
-      ret (respan(s.span, stmt_expr(e_pp)));
+      /* inherit ann from expr */
+      ret respan(s.span,
+                 stmt_expr(e_pp,
+                           some[@ts_ann]
+                           (@ann_to_ts_ann(expr_ann(*e_pp),
+                                           num_local_vars)))); 
     }    
   }
 }
@@ -739,7 +775,7 @@ fn find_pre_post_for_each_stmt(_fn_info_map fm, &fn_info enclosing,
 fn find_pre_post_block(&_fn_info_map fm, &fn_info enclosing, block b)
   -> block {
   fn do_one_(_fn_info_map fm, fn_info i, &@stmt s) -> @stmt {
-    ret (@find_pre_post_for_each_stmt(fm, i, *s));
+    ret (@find_pre_post_stmt(fm, i, *s));
   }
   auto do_one = bind do_one_(fm, enclosing, _);
  
@@ -767,22 +803,93 @@ fn check_item_fn(&_fn_info_map fm, &span sp, ident i, &ast._fn f,
   ret @respan(sp, ast.item_fn(i, res_f, ty_params, id, a));
 }
 
-/* Returns a pair of a new function, with possibly a changed pre- or
-   post-state, and a boolean flag saying whether the function's pre- or 
-   poststate changed */
-fn find_pre_post_state_fn(fn_info f_info, &ast._fn f) -> tup(bool, ast._fn) {
-  log ("Implement find_pre_post_state_fn!");
+/* FIXME */
+fn find_pre_post_state_expr(&_fn_info_map fm, &fn_info enclosing,
+                            &prestate pres, expr e)
+  -> tup(bool, @expr) {
+  log("Implement find_pre_post_state_expr!");
   fail;
 }
 
-fn fixed_point_states(fn_info f_info,
-                      fn (fn_info, &ast._fn) -> tup(bool, ast._fn) f,
+/* FIXME: This isn't done yet. */
+fn find_pre_post_state_stmt(&_fn_info_map fm, &fn_info enclosing,
+                            &prestate pres, @stmt s) -> bool {
+  auto changed = false;
+  alt (s.node) {
+    case (stmt_decl(?adecl, ?a)) {
+      alt (adecl.node) {
+        case (ast.decl_local(?alocal)) {
+          alt (alocal.init) {
+            case (some[ast.initializer](?an_init)) {
+              auto p = find_pre_post_state_expr(fm, enclosing,
+                                                pres, *an_init.expr);
+              fail; /* FIXME */
+              /* Next: copy pres into a's prestate;
+                 find the poststate by taking p's poststate
+                 and setting the bit for alocal.id */
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+/* Returns a pair of a new block, with possibly a changed pre- or
+   post-state, and a boolean flag saying whether the function's pre- or 
+   poststate changed */
+fn find_pre_post_state_block(&_fn_info_map fm, &fn_info enclosing, block b)
+  -> tup(bool, block) {
+  auto changed = false;
+  auto num_local_vars = num_locals(enclosing);
+
+  /* First, set the pre-states and post-states for every expression */
+  auto pres = empty_prestate(num_local_vars);
+  
+  /* Iterate over each stmt. The new prestate is <pres>. The poststate
+   consist of improving <pres> with whatever variables this stmt initializes.
+  Then <pres> becomes the new poststate. */ 
+  for (@stmt s in b.node.stmts) {
+    changed = changed || find_pre_post_state_stmt(fm, enclosing, pres, s);
+      /* Shouldn't need to rebuild the stmt.
+         This just updates bit-vectors
+         in a side-effecting way. */
+    extend_prestate(pres, stmt_poststate(*s, num_local_vars));
+  }
+
+  fn do_inner_(_fn_info_map fm, fn_info i, prestate p, &@expr e)
+    -> tup (bool, @expr) {
+    ret find_pre_post_state_expr(fm, i, p, *e);
+  }
+  auto do_inner = bind do_inner_(fm, enclosing, pres, _);
+  let option.t[tup(bool, @expr)] e_ =
+    option.map[@expr, tup(bool, @expr)](do_inner, b.node.expr);
+  auto s = snd[bool, @expr];
+  auto f = fst[bool, @expr];
+  changed = changed ||
+    from_maybe[bool](false,
+                     option.map[tup(bool, @expr), bool](f, e_));
+  let block_ b_res = rec(stmts=b.node.stmts,
+                         expr=option.map[tup(bool, @expr), @expr](s, e_),
+                         index=b.node.index);
+  ret tup(changed, respan(b.span, b_res));
+}
+
+fn find_pre_post_state_fn(_fn_info_map f_info, fn_info fi, &ast._fn f)
+  -> tup(bool, ast._fn) {
+  auto p = find_pre_post_state_block(f_info, fi, f.body);
+  ret tup(p._0, rec(decl=f.decl, proto=f.proto, body=p._1));
+}
+
+fn fixed_point_states(_fn_info_map fm, fn_info f_info,
+                      fn (_fn_info_map, fn_info, &ast._fn)
+                           -> tup(bool, ast._fn) f,
                       &ast._fn start) -> ast._fn {
-  auto next = f(f_info, start);
+  auto next = f(fm, f_info, start);
 
   if (next._0) {
     // something changed
-    be fixed_point_states(f_info, f, next._1);
+    be fixed_point_states(fm, f_info, f, next._1);
   }
   else {
     // we're done!
@@ -790,42 +897,29 @@ fn (fn_info, &ast._fn) -> tup(bool, ast._fn) f,
   }
 }
 
-fn check_states_expr(fn_info enclosing, &expr e) -> () {
+impure fn check_states_expr(fn_info enclosing, &expr e) -> () {
   let precond prec    = expr_precond(e);
-  let postcond postc  = expr_postcond(e);
   let prestate pres   = expr_prestate(e);
-  let poststate posts = expr_poststate(e);
 
   if (!implies(pres, prec)) {
     log("check_states_expr: unsatisfied precondition");
     fail;
   }
-  if (!implies(posts, postc)) {
-    log("check_states_expr: unsatisfied postcondition");
-    fail;
-  }
 }
 
 fn check_states_stmt(fn_info enclosing, &stmt s) -> () {
   alt (stmt_ann(s)) {
-    case (ann_none) {
-      // Statement doesn't require an annotation -- do nothing
+    case (none[@ts_ann]) {
       ret;
     }
-    case (ann_type(_,_,?m_pp)) {
-      let precond prec    = stmt_precond(s);
-      let postcond postc  = stmt_postcond(s);
-      let prestate pres   = stmt_prestate(s);
-      let poststate posts = stmt_poststate(s);
+    case (some[@ts_ann](?a)) {
+      let precond prec    = ann_precond(*a);
+      let prestate pres   = ann_prestate(*a);
 
       if (!implies(pres, prec)) {
         log("check_states_stmt: unsatisfied precondition");
         fail;
       }
-      if (!implies(posts, postc)) {
-        log("check_states_stmt: unsatisfied postcondition");
-        fail;
-      }
     }
   }
 }
@@ -855,7 +949,7 @@ fn check_item_fn_state(&_fn_info_map f_info_map, &span sp, ident i,
 
   /* Compute the pre- and post-states for this function */
   auto g = find_pre_post_state_fn;
-  auto res_f = fixed_point_states(f_info, g, f);
+  auto res_f = fixed_point_states(f_info_map, f_info, g, f);
 
   /* Now compare each expr's pre-state to its precondition
      and post-state to its postcondition */
index 7e0fb6cb7c94d664b4c3be83a536d4f8e83d3308..ee11a43ad20edeb87ec11aba05a9d3b52c868aed 100644 (file)
@@ -339,8 +339,8 @@ fn get_span(&ast.ty_field f) -> common.span {
         cur_line = st.span.hi.line;
         maybe_print_comment(s, st.span.lo);
         alt (st.node) {
-            case (ast.stmt_decl(?decl)) {print_decl(s, decl);}
-            case (ast.stmt_expr(?expr)) {print_expr(s, expr);}
+          case (ast.stmt_decl(?decl,_)) {print_decl(s, decl);}
+          case (ast.stmt_expr(?expr,_)) {print_expr(s, expr);}
         }
         if (front.parser.stmt_ends_with_semi(st)) {wrd(s.s, ";");}
         if (!maybe_print_line_comment(s, st.span)) {line(s.s);}
index 47a37f3325ff374c041b305fc8dc19ffcc427d77..e34d1faec4092d0f657f4786089171b50c5b97d0 100644 (file)
@@ -62,7 +62,11 @@ auth middle.typestate_check.log_expr = impure;
 auth lib.llvm = unsafe;
 auth pretty.pprust = impure;
 auth middle.typestate_check.find_pre_post_block = impure;
-auth middle.typestate_check.find_pre_post_expr = impure;
+auth middle.typestate_check.find_pre_post_state_block = impure;
+auth middle.typestate_check.find_pre_post_expr  = impure;
+auth middle.typestate_check.find_pre_post_stmt  = impure;
+auth middle.typestate_check.check_states_against_conditions = impure;
+auth middle.typestate_check.check_states_stmt   = impure;
 auth util.typestate_ann.implies = impure;
 
 mod lib {
index 071f55135f5a1ac39d7943a1724d1e454e4784b2..53f9a71cf22d86857df4131b7cc9b1554006dc56 100644 (file)
@@ -36,9 +36,17 @@ fn true_postcond(uint num_vars) -> postcond {
   be true_precond(num_vars);
 }
 
+fn empty_prestate(uint num_vars) -> prestate {
+  be true_precond(num_vars);
+}
+
+fn empty_poststate(uint num_vars) -> poststate {
+  be true_precond(num_vars);
+}
+
 fn empty_pre_post(uint num_vars) -> pre_and_post {
-  ret(rec(precondition=true_precond(num_vars),
-           postcondition=true_postcond(num_vars)));
+  ret(rec(precondition=empty_prestate(num_vars),
+          postcondition=empty_poststate(num_vars)));
 }
 
 fn empty_states(uint num_vars) -> pre_and_post_state {
@@ -46,6 +54,11 @@ fn empty_states(uint num_vars) -> pre_and_post_state {
            poststate=true_postcond(num_vars)));
 }
 
+fn empty_ann(uint num_vars) -> ts_ann {
+  ret(rec(conditions=empty_pre_post(num_vars),
+          states=empty_states(num_vars)));
+}
+
 fn get_pre(&pre_and_post p) -> precond {
   ret p.precondition;
 }
@@ -74,7 +87,37 @@ fn pps_len(&pre_and_post p) -> uint {
   bitv.set(p.postcondition, i, true);
 }
 
-fn implies(bitv.t a, bitv.t b) -> bool {
+impure fn set_in_postcond(uint i, &pre_and_post p) -> () {
+  // sets the ith bit in p's post
+  bitv.set(p.postcondition, i, true);
+}
+
+// Sets all the bits in a's precondition to equal the
+// corresponding bit in p's precondition.
+impure fn set_precondition(&ts_ann a, &precond p) -> () {
+  bitv.copy(p, a.conditions.precondition);
+}
+
+// Sets all the bits in a's postcondition to equal the
+// corresponding bit in p's postcondition.
+impure fn set_postcondition(&ts_ann a, &postcond p) -> () {
+  bitv.copy(p, a.conditions.postcondition);
+}
+
+// Set all the bits in p that are set in new
+impure fn extend_prestate(&prestate p, &poststate new) -> () {
+  bitv.union(p, new);
+}
+
+fn ann_precond(&ts_ann a) -> precond {
+  ret a.conditions.precondition;
+}
+
+fn ann_prestate(&ts_ann a) -> prestate {
+  ret a.states.prestate;
+}
+
+impure fn implies(bitv.t a, bitv.t b) -> bool {
   bitv.difference(b, a);
-  ret (bitv.equal(b, bitv.create(b.nbits, false)));
+  be bitv.is_false(b);
 }
index f2b169efb2c9532a1e98864d8e51493dff998e6e..916a8205f23e7a536704cde1720d016a1780cf77 100644 (file)
@@ -1,5 +1,6 @@
 import option.none;
 import option.some;
+import util.orb;
 
 type vbuf = rustrt.vbuf;
 
@@ -230,6 +231,26 @@ fn foldl[T, U](fn (&U, &T) -> U p, &U z, &vec[T] v) -> U {
     }
 }
 
+fn unzip[T, U](&vec[tup(T, U)] v) -> tup(vec[T], vec[U]) {
+    auto sz = len[tup(T, U)](v);
+
+    if (sz == 0u) {
+        ret tup(alloc[T](0u), alloc[U](0u));
+    }
+    else {
+        auto rest = slice[tup(T, U)](v, 1u, sz);
+        auto tl   = unzip[T, U](rest);
+        auto a    = vec(v.(0)._0);
+        auto b    = vec(v.(0)._1);
+        ret tup(a + tl._0, b + tl._1);
+    }
+}
+
+fn or(&vec[bool] v) -> bool {
+    auto f = orb;
+    be _vec.foldl[bool, bool](f, false, v);
+}
+
 // Local Variables:
 // mode: rust;
 // fill-column: 78;
index 2029ef5295274c3c4a4708777cac116de2a821c4..98e6c0401d6f1decac9588e0620441de25a2137a 100644 (file)
@@ -135,6 +135,28 @@ fn equal(&t v0, &t v1) -> bool {
     }
 }
 
+/* true if all bits are 1 */
+fn is_true(&t v) -> bool {
+    for(uint i in v.storage) {
+        if (i != 1u) {
+            ret false;
+        }
+    }
+
+    ret true;
+}
+
+/* true if all bits are non-1 */
+fn is_false(&t v) -> bool {
+    for(uint i in v.storage) {
+        if (i == 1u) {
+            ret false;
+        }
+    }
+
+    ret true;
+}
+
 fn init_to_vec(t v, uint i) -> uint {
     if (get(v, i)) {
         ret 1u;
index 29a6f6eb96ba644d24439ad2b347555324c6a6ef..66a41bcac68ea229b10a781da8239a674a48be7f 100644 (file)
@@ -38,6 +38,13 @@ fn is_none[T](&t[T] opt) -> bool {
     }
 }
 
+fn from_maybe[T](&T def, &t[T] opt) -> T {
+    alt(opt) {
+        case (none[T])     { ret def; }
+        case (some[T](?t)) { ret t; }
+    }
+}
+
 // Local Variables:
 // mode: rust;
 // fill-column: 78;
index 72844d5f830eff3a92923577468165ee20f30d68..2f797f69216f3634859c74784f5c58a234a8a5cc 100644 (file)
@@ -11,6 +11,18 @@ fn rational_leq(&rational x, &rational y) -> bool {
     ret x.num * y.den <= y.num * x.den;
 }
 
+fn fst[T, U](&tup(T, U) x) -> T {
+    ret x._0;
+}
+
+fn snd[T, U](&tup(T, U) x) -> U {
+    ret x._1;
+}
+
+fn orb(&bool a, &bool b) -> bool {
+    ret a || b;
+}
+
 // Local Variables:
 // mode: rust;
 // fill-column: 78;