Continued sketching out code for checking states against preconditions.

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.
This commit is contained in:
Tim Chevalier 2011-04-06 17:56:44 -07:00
parent 36d75d6391
commit 2e90bd94de
16 changed files with 362 additions and 151 deletions

1
.gitignore vendored
View File

@ -52,3 +52,4 @@ config.mk
/test/
/build/
src/.DS_Store
/stage0/

View File

@ -215,8 +215,8 @@ tag mode {
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));

View File

@ -11,6 +11,7 @@ import util.common;
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 @@ impure fn parse_source_stmt(parser p) -> @ast.stmt {
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 @@ impure fn parse_source_stmt(parser p) -> @ast.stmt {
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 index_arm(@ast.pat pat) -> hashmap[ast.ident,ast.def_id] {
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; }

View File

@ -7,6 +7,7 @@ import util.common.new_str_hash;
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;
@ -232,10 +233,12 @@ type ast_fold[ENV] =
// 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](_,_,_,_,_,_,_),

View File

@ -6,6 +6,7 @@ import front.creader;
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 lookup_name_wrapped(&env e, ast.ident i, namespace ns)
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);

View 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 @@ iter block_locals(&ast.block b) -> @ast.local {
// 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;

View 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 (_) {

View 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));
}
}

View File

@ -11,6 +11,7 @@ import front.ast.stmt;
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;
@ -70,9 +71,17 @@ import util.typestate_ann.prestate;
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;
@ -97,6 +106,7 @@ import std.option;
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;
@ -106,6 +116,8 @@ import std.list.foldl;
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,25 +354,58 @@ 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);
}
}
fn stmt_ann(&stmt s) -> option.t[@ts_ann] {
alt (s.node) {
case (stmt_decl(_,?a)) {
ret a;
}
case (_) {
ret ann_none;
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)) {
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)) {
// ret p.states;
}
}
}
}
}
@ -386,64 +431,17 @@ fn expr_pp(&expr e) -> pre_and_post {
}
}
/* fails if e has no annotation */
fn expr_states(&expr e) -> pre_and_post_state {
alt (expr_ann(e)) {
case (ann_none) {
log "expr_pp: the impossible happened (no annotation)";
fail;
fn stmt_states(&stmt s, uint nv) -> pre_and_post_state {
alt (stmt_ann(s)) {
case (none[@ts_ann]) {
ret empty_states(nv);
}
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.states;
}
}
case (some[@ts_ann](?a)) {
ret a.states;
}
}
}
/* fails if no annotation */
fn stmt_pp(&stmt s) -> pre_and_post {
alt (stmt_ann(s)) {
case (ann_none) {
fail;
}
case (ann_type(_, _, ?maybe_pp)) {
alt (maybe_pp) {
case (none[@ts_ann]) {
fail;
}
case (some[@ts_ann](?p)) {
ret p.conditions;
}
}
}
}
}
/* fails if no annotation */
fn stmt_states(&stmt s) -> pre_and_post_state {
alt (stmt_ann(s)) {
case (ann_none) {
fail;
}
case (ann_type(_, _, ?maybe_pp)) {
alt (maybe_pp) {
case (none[@ts_ann]) {
fail;
}
case (some[@ts_ann](?p)) {
ret p.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 find_pre_post_expr(&fn_info enclosing, &expr e) -> @expr {
}
}
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 fixed_point_states(fn_info f_info,
}
}
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 */

View File

@ -339,8 +339,8 @@ impure fn print_block(ps s, ast.block blk) {
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);}

View 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 {

View 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 @@ impure fn require_and_preserve(uint i, &pre_and_post p) -> () {
bitv.set(p.postcondition, i, true);
}
fn implies(bitv.t a, bitv.t b) -> bool {
bitv.difference(b, a);
ret (bitv.equal(b, bitv.create(b.nbits, false)));
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);
be bitv.is_false(b);
}

View 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;

View File

@ -135,6 +135,28 @@ impure fn set(&t v, uint i, bool x) {
}
}
/* 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;

View 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;

View 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;