Invalidate constraints correctly after an assignment expression
Modified typestate to throw away any constraints mentioning a variable on the LHS of an assignment, recv, assign_op, or on either side of a swap. Some code cleanup as well.
This commit is contained in:
parent
818d7c9398
commit
582e1f13f0
10 changed files with 444 additions and 378 deletions
|
@ -11,6 +11,9 @@ type ident = str;
|
||||||
// Functions may or may not have names.
|
// Functions may or may not have names.
|
||||||
type fn_ident = option::t[ident];
|
type fn_ident = option::t[ident];
|
||||||
|
|
||||||
|
// FIXME: with typestate constraint, could say
|
||||||
|
// idents and types are the same length, and are
|
||||||
|
// non-empty
|
||||||
type path_ = rec(vec[ident] idents, vec[@ty] types);
|
type path_ = rec(vec[ident] idents, vec[@ty] types);
|
||||||
|
|
||||||
type path = spanned[path_];
|
type path = spanned[path_];
|
||||||
|
|
|
@ -112,28 +112,37 @@ fn set_in_postcond(uint i, &pre_and_post p) -> bool {
|
||||||
// sets the ith bit in p's post
|
// sets the ith bit in p's post
|
||||||
auto was_set = tritv_get(p.postcondition, i);
|
auto was_set = tritv_get(p.postcondition, i);
|
||||||
tritv_set(i, p.postcondition, ttrue);
|
tritv_set(i, p.postcondition, ttrue);
|
||||||
ret was_set != ttrue;
|
ret was_set == dont_care;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_in_poststate(uint i, &pre_and_post_state s) -> bool {
|
fn set_in_poststate(uint i, &pre_and_post_state s) -> bool {
|
||||||
// sets the ith bit in p's post
|
// sets the ith bit in p's post
|
||||||
auto was_set = tritv_get(s.poststate, i);
|
ret set_in_poststate_(i, s.poststate);
|
||||||
tritv_set(i, s.poststate, ttrue);
|
}
|
||||||
ret was_set != ttrue;
|
|
||||||
|
fn set_in_poststate_(uint i, &poststate p) -> bool {
|
||||||
|
auto was_set = tritv_get(p, i);
|
||||||
|
tritv_set(i, p, ttrue);
|
||||||
|
ret was_set == dont_care;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_in_poststate(uint i, &pre_and_post_state s) -> bool {
|
fn clear_in_poststate(uint i, &pre_and_post_state s) -> bool {
|
||||||
// sets the ith bit in p's post
|
// sets the ith bit in p's post
|
||||||
auto was_set = tritv_get(s.poststate, i);
|
ret clear_in_poststate_(i, s.poststate);
|
||||||
tritv_set(i, s.poststate, tfalse);
|
}
|
||||||
ret was_set != tfalse;
|
|
||||||
|
fn clear_in_poststate_(uint i, &poststate s) -> bool {
|
||||||
|
auto was_set = tritv_get(s, i);
|
||||||
|
tritv_set(i, s, tfalse);
|
||||||
|
ret was_set == dont_care;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_in_postcond(uint i, &pre_and_post s) -> bool {
|
fn clear_in_postcond(uint i, &pre_and_post s) -> bool {
|
||||||
// sets the ith bit in p's post
|
// sets the ith bit in p's post
|
||||||
auto was_set = tritv_get(s.postcondition, i);
|
auto was_set = tritv_get(s.postcondition, i);
|
||||||
tritv_set(i, s.postcondition, tfalse);
|
tritv_set(i, s.postcondition, tfalse);
|
||||||
ret was_set != tfalse;
|
ret was_set == dont_care;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets all the bits in a's precondition to equal the
|
// Sets all the bits in a's precondition to equal the
|
||||||
|
@ -222,6 +231,14 @@ fn implies(t a, t b) -> bool {
|
||||||
tritv_difference(tmp, a);
|
tritv_difference(tmp, a);
|
||||||
ret tritv_doesntcare(tmp);
|
ret tritv_doesntcare(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn trit_str(trit t) -> str {
|
||||||
|
alt (t) {
|
||||||
|
case (dont_care) { "?" }
|
||||||
|
case (ttrue) { "1" }
|
||||||
|
case (tfalse) { "0" }
|
||||||
|
}
|
||||||
|
}
|
||||||
//
|
//
|
||||||
// Local Variables:
|
// Local Variables:
|
||||||
// mode: rust
|
// mode: rust
|
||||||
|
|
|
@ -39,6 +39,7 @@ import tstate::ann::set_postcondition;
|
||||||
import tstate::ann::ts_ann;
|
import tstate::ann::ts_ann;
|
||||||
import tstate::ann::clear_in_postcond;
|
import tstate::ann::clear_in_postcond;
|
||||||
import tstate::ann::clear_in_poststate;
|
import tstate::ann::clear_in_poststate;
|
||||||
|
import tstate::ann::clear_in_poststate_;
|
||||||
import tritv::*;
|
import tritv::*;
|
||||||
|
|
||||||
import pretty::ppaux::constr_args_to_str;
|
import pretty::ppaux::constr_args_to_str;
|
||||||
|
@ -655,8 +656,9 @@ tag if_ty {
|
||||||
plain_if;
|
plain_if;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn local_node_id_to_def_id(&fn_ctxt fcx, &span sp, &node_id i) -> def_id {
|
fn local_node_id_to_def_id_strict(&fn_ctxt fcx, &span sp, &node_id i)
|
||||||
alt (fcx.ccx.tcx.def_map.find(i)) {
|
-> def_id {
|
||||||
|
alt (local_node_id_to_def(fcx, i)) {
|
||||||
case (some(def_local(?d_id))) {
|
case (some(def_local(?d_id))) {
|
||||||
ret d_id;
|
ret d_id;
|
||||||
}
|
}
|
||||||
|
@ -675,30 +677,86 @@ fn local_node_id_to_def_id(&fn_ctxt fcx, &span sp, &node_id i) -> def_id {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn forget_in_postcond(&fn_ctxt fcx, &span dead_sp,
|
fn local_node_id_to_def(&fn_ctxt fcx, &node_id i) -> option::t[def]
|
||||||
node_id parent_exp, node_id dead_v) {
|
{ fcx.ccx.tcx.def_map.find(i) }
|
||||||
// In the postcondition given by parent_exp, clear the bits
|
|
||||||
// for any constraints mentioning dead_v
|
fn local_node_id_to_def_id(&fn_ctxt fcx, &node_id i) -> option::t[def_id] {
|
||||||
auto d_id = local_node_id_to_def_id(fcx, dead_sp, dead_v);
|
alt (local_node_id_to_def(fcx, i)) {
|
||||||
for (norm_constraint c in constraints(fcx)) {
|
case (some(def_local(?d_id))) { some(d_id) }
|
||||||
if (constraint_mentions(fcx, c, d_id)) {
|
case (some (def_arg(?a_id))) { some(a_id) }
|
||||||
clear_in_postcond(c.bit_num,
|
case (_) { none }
|
||||||
node_id_to_ts_ann(fcx.ccx, parent_exp).conditions);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn forget_in_poststate(&fn_ctxt fcx, &span dead_sp,
|
/* FIXME should refactor this better */
|
||||||
node_id parent_exp, node_id dead_v) -> bool {
|
fn forget_in_postcond(&fn_ctxt fcx, node_id parent_exp, node_id dead_v) {
|
||||||
|
// In the postcondition given by parent_exp, clear the bits
|
||||||
|
// for any constraints mentioning dead_v
|
||||||
|
auto d = local_node_id_to_def_id(fcx, dead_v);
|
||||||
|
alt (d) {
|
||||||
|
case (some(?d_id)) {
|
||||||
|
for (norm_constraint c in constraints(fcx)) {
|
||||||
|
if (constraint_mentions(fcx, c, d_id)) {
|
||||||
|
clear_in_postcond(c.bit_num,
|
||||||
|
node_id_to_ts_ann(fcx.ccx, parent_exp).conditions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case (_) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn forget_in_postcond_still_init(&fn_ctxt fcx, node_id parent_exp,
|
||||||
|
node_id dead_v) {
|
||||||
|
// In the postcondition given by parent_exp, clear the bits
|
||||||
|
// for any constraints mentioning dead_v
|
||||||
|
auto d = local_node_id_to_def_id(fcx, dead_v);
|
||||||
|
alt (d) {
|
||||||
|
case (some(?d_id)) {
|
||||||
|
for (norm_constraint c in constraints(fcx)) {
|
||||||
|
if (non_init_constraint_mentions(fcx, c, d_id)) {
|
||||||
|
clear_in_postcond(c.bit_num,
|
||||||
|
node_id_to_ts_ann(fcx.ccx, parent_exp).conditions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case (_) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn forget_in_poststate(&fn_ctxt fcx, &poststate p, node_id dead_v) -> bool {
|
||||||
// In the poststate given by parent_exp, clear the bits
|
// In the poststate given by parent_exp, clear the bits
|
||||||
// for any constraints mentioning dead_v
|
// for any constraints mentioning dead_v
|
||||||
auto d_id = local_node_id_to_def_id(fcx, dead_sp, dead_v);
|
auto d = local_node_id_to_def_id(fcx, dead_v);
|
||||||
auto changed = false;
|
auto changed = false;
|
||||||
for (norm_constraint c in constraints(fcx)) {
|
alt (d) {
|
||||||
if (constraint_mentions(fcx, c, d_id)) {
|
case (some(?d_id)) {
|
||||||
changed = clear_in_poststate(c.bit_num,
|
for (norm_constraint c in constraints(fcx)) {
|
||||||
node_id_to_ts_ann(fcx.ccx, parent_exp).states) || changed;
|
if (constraint_mentions(fcx, c, d_id)) {
|
||||||
|
changed = clear_in_poststate_(c.bit_num, p) || changed;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
case (_) {}
|
||||||
|
}
|
||||||
|
ret changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn forget_in_poststate_still_init(&fn_ctxt fcx, &poststate p, node_id dead_v)
|
||||||
|
-> bool {
|
||||||
|
// In the poststate given by parent_exp, clear the bits
|
||||||
|
// for any constraints mentioning dead_v
|
||||||
|
auto d = local_node_id_to_def_id(fcx, dead_v);
|
||||||
|
auto changed = false;
|
||||||
|
alt (d) {
|
||||||
|
case (some(?d_id)) {
|
||||||
|
for (norm_constraint c in constraints(fcx)) {
|
||||||
|
if (non_init_constraint_mentions(fcx, c, d_id)) {
|
||||||
|
changed = clear_in_poststate_(c.bit_num, p) || changed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case (_) {}
|
||||||
}
|
}
|
||||||
ret changed;
|
ret changed;
|
||||||
}
|
}
|
||||||
|
@ -714,6 +772,18 @@ fn constraint_mentions(&fn_ctxt fcx, &norm_constraint c, &def_id v) -> bool {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn non_init_constraint_mentions(&fn_ctxt fcx, &norm_constraint c,
|
||||||
|
&def_id v) -> bool {
|
||||||
|
ret (alt (c.c.node.c) {
|
||||||
|
case (ninit(_)) {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
case (npred(_, ?args)) {
|
||||||
|
args_mention(args, v)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fn args_mention(&vec[@constr_arg_use] args, &def_id v) -> bool {
|
fn args_mention(&vec[@constr_arg_use] args, &def_id v) -> bool {
|
||||||
fn mentions(&def_id v, &@constr_arg_use a) -> bool {
|
fn mentions(&def_id v, &@constr_arg_use a) -> bool {
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
|
|
||||||
import front::ast::*;
|
import front::ast::*;
|
||||||
|
import std::option::*;
|
||||||
import std::vec;
|
import std::vec;
|
||||||
import std::vec::len;
|
import std::vec::len;
|
||||||
import std::vec::slice;
|
import std::vec::slice;
|
||||||
|
import aux::local_node_id_to_def;
|
||||||
import aux::fn_ctxt;
|
import aux::fn_ctxt;
|
||||||
import aux::fn_info;
|
import aux::fn_info;
|
||||||
import aux::log_tritv;
|
import aux::log_tritv;
|
||||||
|
@ -38,7 +41,9 @@ import tstate::ann::intersect;
|
||||||
import tstate::ann::clone;
|
import tstate::ann::clone;
|
||||||
import tstate::ann::set_in_postcond;
|
import tstate::ann::set_in_postcond;
|
||||||
import tstate::ann::set_in_poststate;
|
import tstate::ann::set_in_poststate;
|
||||||
|
import tstate::ann::set_in_poststate_;
|
||||||
import tstate::ann::clear_in_poststate;
|
import tstate::ann::clear_in_poststate;
|
||||||
|
import tstate::ann::clear_in_poststate_;
|
||||||
import tritv::*;
|
import tritv::*;
|
||||||
|
|
||||||
fn bit_num(&fn_ctxt fcx, &constr_ c) -> uint {
|
fn bit_num(&fn_ctxt fcx, &constr_ c) -> uint {
|
||||||
|
@ -219,6 +224,36 @@ fn kill_poststate(&fn_ctxt fcx, node_id id, &constr_ c) -> bool {
|
||||||
ret clear_in_poststate(bit_num(fcx, c),
|
ret clear_in_poststate(bit_num(fcx, c),
|
||||||
node_id_to_ts_ann(fcx.ccx, id).states);
|
node_id_to_ts_ann(fcx.ccx, id).states);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn clear_in_poststate_expr(&fn_ctxt fcx, &@expr e, &poststate t) {
|
||||||
|
alt (e.node) {
|
||||||
|
case (expr_path(?p)) {
|
||||||
|
alt (vec::last(p.node.idents)) {
|
||||||
|
case (some(?i)) {
|
||||||
|
alt (local_node_id_to_def(fcx, e.id)) {
|
||||||
|
case (some(def_local(?d_id))) {
|
||||||
|
clear_in_poststate_(bit_num(fcx,
|
||||||
|
rec(id=d_id._1,
|
||||||
|
c=ninit(i))), t);
|
||||||
|
}
|
||||||
|
case (some(_)) { /* ignore args (for now...) */ }
|
||||||
|
case (_) {
|
||||||
|
fcx.ccx.tcx.sess.bug("clear_in_poststate_expr: \
|
||||||
|
unbound var"); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case (_) { fcx.ccx.tcx.sess.bug("clear_in_poststate_expr"); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case (_) { /* do nothing */ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_in_poststate_ident(&fn_ctxt fcx, &node_id id, &ident ident,
|
||||||
|
&poststate t) -> bool {
|
||||||
|
ret set_in_poststate_(bit_num(fcx, rec(id=id, c=ninit(ident))), t);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Local Variables:
|
// Local Variables:
|
||||||
// mode: rust
|
// mode: rust
|
||||||
|
|
|
@ -48,6 +48,7 @@ import aux::if_ty;
|
||||||
import aux::if_check;
|
import aux::if_check;
|
||||||
import aux::plain_if;
|
import aux::plain_if;
|
||||||
import aux::forget_in_postcond;
|
import aux::forget_in_postcond;
|
||||||
|
import aux::forget_in_postcond_still_init;
|
||||||
|
|
||||||
import aux::constraints_expr;
|
import aux::constraints_expr;
|
||||||
import aux::substitute_constr_args;
|
import aux::substitute_constr_args;
|
||||||
|
@ -61,7 +62,6 @@ import bitvectors::seq_postconds;
|
||||||
import bitvectors::intersect_postconds;
|
import bitvectors::intersect_postconds;
|
||||||
import bitvectors::declare_var;
|
import bitvectors::declare_var;
|
||||||
import bitvectors::gen_poststate;
|
import bitvectors::gen_poststate;
|
||||||
import bitvectors::kill_poststate;
|
|
||||||
import bitvectors::relax_precond_block;
|
import bitvectors::relax_precond_block;
|
||||||
import bitvectors::gen;
|
import bitvectors::gen;
|
||||||
import front::ast::*;
|
import front::ast::*;
|
||||||
|
@ -274,19 +274,13 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) {
|
||||||
auto enclosing = fcx.enclosing;
|
auto enclosing = fcx.enclosing;
|
||||||
auto num_local_vars = num_constraints(enclosing);
|
auto num_local_vars = num_constraints(enclosing);
|
||||||
fn do_rand_(fn_ctxt fcx, &@expr e) { find_pre_post_expr(fcx, e); }
|
fn do_rand_(fn_ctxt fcx, &@expr e) { find_pre_post_expr(fcx, e); }
|
||||||
log "find_pre_post_expr (num_constraints =" + uistr(num_local_vars) +
|
|
||||||
"):";
|
|
||||||
log_expr(*e);
|
|
||||||
alt (e.node) {
|
alt (e.node) {
|
||||||
case (expr_call(?operator, ?operands)) {
|
case (expr_call(?operator, ?operands)) {
|
||||||
auto args = vec::clone[@expr](operands);
|
auto args = vec::clone(operands);
|
||||||
vec::push[@expr](args, operator);
|
vec::push(args, operator);
|
||||||
find_pre_post_exprs(fcx, args, e.id);
|
find_pre_post_exprs(fcx, args, e.id);
|
||||||
/* see if the call has any constraints on its type */
|
/* see if the call has any constraints on its type */
|
||||||
|
|
||||||
log "a function: ";
|
|
||||||
log_expr(*operator);
|
|
||||||
auto pp = expr_pp(fcx.ccx, e);
|
|
||||||
for (@ty::constr_def c in constraints_expr(fcx.ccx.tcx, operator))
|
for (@ty::constr_def c in constraints_expr(fcx.ccx.tcx, operator))
|
||||||
{
|
{
|
||||||
auto i =
|
auto i =
|
||||||
|
@ -294,7 +288,7 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) {
|
||||||
rec(id=c.node.id._1,
|
rec(id=c.node.id._1,
|
||||||
c=substitute_constr_args(fcx.ccx.tcx,
|
c=substitute_constr_args(fcx.ccx.tcx,
|
||||||
operands, c)));
|
operands, c)));
|
||||||
require(i, pp);
|
require(i, expr_pp(fcx.ccx, e));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if this is a failing call, its postcondition sets everything */
|
/* if this is a failing call, its postcondition sets everything */
|
||||||
|
@ -304,8 +298,8 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case (expr_spawn(_, _, ?operator, ?operands)) {
|
case (expr_spawn(_, _, ?operator, ?operands)) {
|
||||||
auto args = vec::clone[@expr](operands);
|
auto args = vec::clone(operands);
|
||||||
vec::push[@expr](args, operator);
|
vec::push(args, operator);
|
||||||
find_pre_post_exprs(fcx, args, e.id);
|
find_pre_post_exprs(fcx, args, e.id);
|
||||||
}
|
}
|
||||||
case (expr_vec(?args, _, _)) {
|
case (expr_vec(?args, _, _)) {
|
||||||
|
@ -356,7 +350,7 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) {
|
||||||
}
|
}
|
||||||
case (expr_rec(?fields, ?maybe_base)) {
|
case (expr_rec(?fields, ?maybe_base)) {
|
||||||
auto es = field_exprs(fields);
|
auto es = field_exprs(fields);
|
||||||
vec::plus_option[@expr](es, maybe_base);
|
vec::plus_option(es, maybe_base);
|
||||||
find_pre_post_exprs(fcx, es, e.id);
|
find_pre_post_exprs(fcx, es, e.id);
|
||||||
}
|
}
|
||||||
case (expr_move(?lhs, ?rhs)) {
|
case (expr_move(?lhs, ?rhs)) {
|
||||||
|
@ -366,17 +360,22 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) {
|
||||||
}
|
}
|
||||||
case (_) { find_pre_post_exprs(fcx, [lhs, rhs], e.id); }
|
case (_) { find_pre_post_exprs(fcx, [lhs, rhs], e.id); }
|
||||||
}
|
}
|
||||||
forget_in_postcond(fcx, rhs.span, e.id, rhs.id);
|
forget_in_postcond(fcx, e.id, rhs.id);
|
||||||
}
|
}
|
||||||
case (expr_swap(?lhs, ?rhs)) {
|
case (expr_swap(?lhs, ?rhs)) {
|
||||||
// Both sides must already be initialized
|
// Both sides must already be initialized
|
||||||
|
|
||||||
find_pre_post_exprs(fcx, [lhs, rhs], e.id);
|
find_pre_post_exprs(fcx, [lhs, rhs], e.id);
|
||||||
|
forget_in_postcond_still_init(fcx, e.id, lhs.id);
|
||||||
|
forget_in_postcond_still_init(fcx, e.id, rhs.id);
|
||||||
|
// Could be more precise and swap the roles of lhs and rhs
|
||||||
|
// in any constraints
|
||||||
}
|
}
|
||||||
case (expr_assign(?lhs, ?rhs)) {
|
case (expr_assign(?lhs, ?rhs)) {
|
||||||
alt (lhs.node) {
|
alt (lhs.node) {
|
||||||
case (expr_path(?p)) {
|
case (expr_path(?p)) {
|
||||||
gen_if_local(fcx, lhs, rhs, e.id, lhs.id, p);
|
gen_if_local(fcx, lhs, rhs, e.id, lhs.id, p);
|
||||||
|
forget_in_postcond_still_init(fcx, e.id, lhs.id);
|
||||||
}
|
}
|
||||||
case (_) { find_pre_post_exprs(fcx, [lhs, rhs], e.id); }
|
case (_) { find_pre_post_exprs(fcx, [lhs, rhs], e.id); }
|
||||||
}
|
}
|
||||||
|
@ -385,7 +384,8 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) {
|
||||||
alt (rhs.node) {
|
alt (rhs.node) {
|
||||||
case (expr_path(?p)) {
|
case (expr_path(?p)) {
|
||||||
gen_if_local(fcx, rhs, lhs, e.id, rhs.id, p);
|
gen_if_local(fcx, rhs, lhs, e.id, rhs.id, p);
|
||||||
}
|
forget_in_postcond_still_init(fcx, e.id, lhs.id);
|
||||||
|
}
|
||||||
case (_) {
|
case (_) {
|
||||||
// doesn't check that rhs is an lval, but
|
// doesn't check that rhs is an lval, but
|
||||||
// that's probably ok
|
// that's probably ok
|
||||||
|
@ -399,6 +399,7 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) {
|
||||||
already be initialized */
|
already be initialized */
|
||||||
|
|
||||||
find_pre_post_exprs(fcx, [lhs, rhs], e.id);
|
find_pre_post_exprs(fcx, [lhs, rhs], e.id);
|
||||||
|
forget_in_postcond_still_init(fcx, e.id, lhs.id);
|
||||||
}
|
}
|
||||||
case (expr_lit(_)) { clear_pp(expr_pp(fcx.ccx, e)); }
|
case (expr_lit(_)) { clear_pp(expr_pp(fcx.ccx, e)); }
|
||||||
case (expr_ret(?maybe_val)) {
|
case (expr_ret(?maybe_val)) {
|
||||||
|
@ -585,8 +586,8 @@ fn find_pre_post_stmt(&fn_ctxt fcx, &stmt s) {
|
||||||
|
|
||||||
alt (an_init.op) {
|
alt (an_init.op) {
|
||||||
case (init_move) {
|
case (init_move) {
|
||||||
forget_in_postcond(fcx, an_init.expr.span,
|
forget_in_postcond(fcx, id,
|
||||||
id, an_init.expr.id);
|
an_init.expr.id);
|
||||||
}
|
}
|
||||||
case (_) { /* nothing gets deinitialized */ }
|
case (_) { /* nothing gets deinitialized */ }
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,20 +7,21 @@ import std::option::is_none;
|
||||||
import std::option::none;
|
import std::option::none;
|
||||||
import std::option::some;
|
import std::option::some;
|
||||||
import std::option::maybe;
|
import std::option::maybe;
|
||||||
|
import tstate::ann::set_in_poststate_;
|
||||||
import tstate::ann::pre_and_post;
|
import tstate::ann::pre_and_post;
|
||||||
import tstate::ann::get_post;
|
import tstate::ann::get_post;
|
||||||
import tstate::ann::postcond;
|
import tstate::ann::postcond;
|
||||||
import tstate::ann::empty_pre_post;
|
import tstate::ann::empty_pre_post;
|
||||||
import tstate::ann::empty_poststate;
|
import tstate::ann::empty_poststate;
|
||||||
import tstate::ann::require_and_preserve;
|
import tstate::ann::clear_in_poststate;
|
||||||
import tstate::ann::intersect;
|
import tstate::ann::intersect;
|
||||||
import tstate::ann::empty_prestate;
|
import tstate::ann::empty_prestate;
|
||||||
import tstate::ann::prestate;
|
import tstate::ann::prestate;
|
||||||
import tstate::ann::poststate;
|
import tstate::ann::poststate;
|
||||||
import tstate::ann::false_postcond;
|
import tstate::ann::false_postcond;
|
||||||
import tstate::ann::ts_ann;
|
import tstate::ann::ts_ann;
|
||||||
import tstate::ann::extend_prestate;
|
import tstate::ann::set_prestate;
|
||||||
import tstate::ann::extend_poststate;
|
import tstate::ann::set_poststate;
|
||||||
import aux::crate_ctxt;
|
import aux::crate_ctxt;
|
||||||
import aux::fn_ctxt;
|
import aux::fn_ctxt;
|
||||||
import aux::num_constraints;
|
import aux::num_constraints;
|
||||||
|
@ -61,13 +62,14 @@ import aux::if_ty;
|
||||||
import aux::if_check;
|
import aux::if_check;
|
||||||
import aux::plain_if;
|
import aux::plain_if;
|
||||||
import aux::forget_in_poststate;
|
import aux::forget_in_poststate;
|
||||||
|
import aux::forget_in_poststate_still_init;
|
||||||
import tritv::tritv_clone;
|
import tritv::tritv_clone;
|
||||||
import tritv::tritv_set;
|
import tritv::tritv_set;
|
||||||
import tritv::ttrue;
|
import tritv::ttrue;
|
||||||
|
|
||||||
import bitvectors::seq_preconds;
|
import bitvectors::set_in_poststate_ident;
|
||||||
|
import bitvectors::clear_in_poststate_expr;
|
||||||
import bitvectors::intersect_postconds;
|
import bitvectors::intersect_postconds;
|
||||||
import bitvectors::declare_var;
|
|
||||||
import bitvectors::bit_num;
|
import bitvectors::bit_num;
|
||||||
import bitvectors::gen_poststate;
|
import bitvectors::gen_poststate;
|
||||||
import bitvectors::kill_poststate;
|
import bitvectors::kill_poststate;
|
||||||
|
@ -89,23 +91,101 @@ import util::common::log_stmt;
|
||||||
import util::common::log_stmt_err;
|
import util::common::log_stmt_err;
|
||||||
import util::common::log_expr_err;
|
import util::common::log_expr_err;
|
||||||
|
|
||||||
|
// Used to communicate which operands should be invalidated
|
||||||
|
// to helper functions
|
||||||
|
tag oper_type {
|
||||||
|
oper_move;
|
||||||
|
oper_swap;
|
||||||
|
oper_assign;
|
||||||
|
oper_pure;
|
||||||
|
}
|
||||||
|
|
||||||
fn seq_states(&fn_ctxt fcx, prestate pres, vec[@expr] exprs) ->
|
fn seq_states(&fn_ctxt fcx, prestate pres, vec[@expr] exprs) ->
|
||||||
tup(bool, poststate) {
|
tup(bool, poststate) {
|
||||||
auto changed = false;
|
auto changed = false;
|
||||||
auto post = pres;
|
auto post = pres;
|
||||||
for (@expr e in exprs) {
|
for (@expr e in exprs) {
|
||||||
changed = find_pre_post_state_expr(fcx, post, e) || changed;
|
changed = find_pre_post_state_expr(fcx, post, e) || changed;
|
||||||
|
// log_err("Seq_states: changed =");
|
||||||
|
// log_err changed;
|
||||||
post = expr_poststate(fcx.ccx, e);
|
post = expr_poststate(fcx.ccx, e);
|
||||||
}
|
}
|
||||||
ret tup(changed, post);
|
ret tup(changed, post);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_pre_post_state_sub(&fn_ctxt fcx, &prestate pres, &@expr e,
|
||||||
|
node_id parent, option::t[aux::constr_] c)
|
||||||
|
-> bool {
|
||||||
|
auto changed = find_pre_post_state_expr(fcx, pres, e);
|
||||||
|
|
||||||
|
changed = set_prestate_ann(fcx.ccx, parent, pres) || changed;
|
||||||
|
|
||||||
|
auto post = tritv_clone(expr_poststate(fcx.ccx, e));
|
||||||
|
alt (c) {
|
||||||
|
case (none) {}
|
||||||
|
case (some(?c1)) {
|
||||||
|
set_in_poststate_(bit_num(fcx, c1), post);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
changed = set_poststate_ann(fcx.ccx, parent, post) || changed;
|
||||||
|
ret changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_pre_post_state_two(&fn_ctxt fcx, &prestate pres, &@expr a, &@expr b,
|
||||||
|
node_id parent, oper_type op) -> bool {
|
||||||
|
auto changed = set_prestate_ann(fcx.ccx, parent, pres);
|
||||||
|
changed = find_pre_post_state_expr(fcx, pres, a) || changed;
|
||||||
|
changed = find_pre_post_state_expr(fcx, expr_poststate(fcx.ccx, a), b)
|
||||||
|
|| changed;
|
||||||
|
|
||||||
|
// for termination, need to make sure intermediate changes don't set
|
||||||
|
// changed flag
|
||||||
|
auto post = tritv_clone(expr_poststate(fcx.ccx, b));
|
||||||
|
alt (op) {
|
||||||
|
case (oper_move) {
|
||||||
|
forget_in_poststate(fcx, post, b.id);
|
||||||
|
gen_if_local(fcx, post, a);
|
||||||
|
}
|
||||||
|
case (oper_swap) {
|
||||||
|
forget_in_poststate_still_init(fcx, post, a.id);
|
||||||
|
forget_in_poststate_still_init(fcx, post, b.id);
|
||||||
|
}
|
||||||
|
case (oper_assign) {
|
||||||
|
forget_in_poststate_still_init(fcx, post, a.id);
|
||||||
|
gen_if_local(fcx, post, a);
|
||||||
|
}
|
||||||
|
case (_) {}
|
||||||
|
}
|
||||||
|
changed = set_poststate_ann(fcx.ccx, parent, post) || changed;
|
||||||
|
ret changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_pre_post_state_call(&fn_ctxt fcx, &prestate pres, &@expr a,
|
||||||
|
node_id id, &vec[@expr] bs,
|
||||||
|
controlflow cf) -> bool {
|
||||||
|
auto changed = find_pre_post_state_expr(fcx, pres, a);
|
||||||
|
ret find_pre_post_state_exprs(fcx,
|
||||||
|
expr_poststate(fcx.ccx, a), id, bs, cf) || changed;
|
||||||
|
}
|
||||||
|
|
||||||
fn find_pre_post_state_exprs(&fn_ctxt fcx, &prestate pres, ast::node_id id,
|
fn find_pre_post_state_exprs(&fn_ctxt fcx, &prestate pres, ast::node_id id,
|
||||||
&vec[@expr] es) -> bool {
|
&vec[@expr] es, controlflow cf) -> bool {
|
||||||
auto rslt = seq_states(fcx, pres, es);
|
auto res = seq_states(fcx, pres, es);
|
||||||
auto changed = rslt._0;
|
auto changed = res._0;
|
||||||
changed = extend_prestate_ann(fcx.ccx, id, pres) || changed;
|
changed = set_prestate_ann(fcx.ccx, id, pres) || changed;
|
||||||
changed = extend_poststate_ann(fcx.ccx, id, rslt._1) || changed;
|
/* if this is a failing call, it sets everything as initialized */
|
||||||
|
alt (cf) {
|
||||||
|
case (noreturn) {
|
||||||
|
changed =
|
||||||
|
set_poststate_ann(fcx.ccx, id,
|
||||||
|
false_postcond(num_constraints(fcx.enclosing))) ||
|
||||||
|
changed;
|
||||||
|
}
|
||||||
|
case (_) {
|
||||||
|
changed = set_poststate_ann(fcx.ccx, id, res._1) || changed;
|
||||||
|
}
|
||||||
|
}
|
||||||
ret changed;
|
ret changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,7 +196,7 @@ fn find_pre_post_state_loop(&fn_ctxt fcx, prestate pres, &@local l,
|
||||||
|
|
||||||
// FIXME: also want to set l as initialized, no?
|
// FIXME: also want to set l as initialized, no?
|
||||||
|
|
||||||
changed = extend_prestate_ann(fcx.ccx, id, pres) || changed;
|
changed = set_prestate_ann(fcx.ccx, id, pres) || changed;
|
||||||
changed = find_pre_post_state_expr(fcx, pres, index) || changed;
|
changed = find_pre_post_state_expr(fcx, pres, index) || changed;
|
||||||
/* in general, would need the intersection of
|
/* in general, would need the intersection of
|
||||||
(poststate of index, poststate of body) */
|
(poststate of index, poststate of body) */
|
||||||
|
@ -132,18 +212,22 @@ fn find_pre_post_state_loop(&fn_ctxt fcx, prestate pres, &@local l,
|
||||||
auto res_p =
|
auto res_p =
|
||||||
intersect_postconds([expr_poststate(fcx.ccx, index),
|
intersect_postconds([expr_poststate(fcx.ccx, index),
|
||||||
block_poststate(fcx.ccx, body)]);
|
block_poststate(fcx.ccx, body)]);
|
||||||
changed = extend_poststate_ann(fcx.ccx, id, res_p) || changed;
|
changed = set_poststate_ann(fcx.ccx, id, res_p) || changed;
|
||||||
ret changed;
|
ret changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_if_local(&fn_ctxt fcx, node_id new_var, node_id id, &path p) -> bool {
|
fn gen_if_local(&fn_ctxt fcx, &poststate p, &@expr e) -> bool {
|
||||||
alt (node_id_to_def(fcx.ccx, new_var)) {
|
alt (e.node) {
|
||||||
case (some(def_local(?loc))) {
|
case (expr_path(?pth)) {
|
||||||
ret gen_poststate(fcx, id,
|
alt (node_id_to_def(fcx.ccx, e.id)) {
|
||||||
rec(id=loc._1,
|
case (some(def_local(?loc))) {
|
||||||
c=ninit(path_to_ident(fcx.ccx.tcx, p))));
|
ret set_in_poststate_ident(fcx, loc._1,
|
||||||
|
path_to_ident(fcx.ccx.tcx, pth), p);
|
||||||
|
}
|
||||||
|
case (_) { ret false; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case (_) { ret false; }
|
case (_) { ret false; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,7 +236,7 @@ fn join_then_else(&fn_ctxt fcx, &@expr antec, &block conseq,
|
||||||
&prestate pres) -> bool {
|
&prestate pres) -> bool {
|
||||||
auto changed = false;
|
auto changed = false;
|
||||||
|
|
||||||
changed = extend_prestate_ann(fcx.ccx, id, pres) || changed;
|
changed = set_prestate_ann(fcx.ccx, id, pres) || changed;
|
||||||
changed = find_pre_post_state_expr(fcx, pres, antec) || changed;
|
changed = find_pre_post_state_expr(fcx, pres, antec) || changed;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -178,7 +262,7 @@ fn join_then_else(&fn_ctxt fcx, &@expr antec, &block conseq,
|
||||||
conseq) || changed;
|
conseq) || changed;
|
||||||
|
|
||||||
changed =
|
changed =
|
||||||
extend_poststate_ann(fcx.ccx, id,
|
set_poststate_ann(fcx.ccx, id,
|
||||||
expr_poststate(fcx.ccx, antec))
|
expr_poststate(fcx.ccx, antec))
|
||||||
|| changed;
|
|| changed;
|
||||||
}
|
}
|
||||||
|
@ -218,7 +302,7 @@ fn join_then_else(&fn_ctxt fcx, &@expr antec, &block conseq,
|
||||||
block_poststate(fcx.ccx, conseq))); */
|
block_poststate(fcx.ccx, conseq))); */
|
||||||
|
|
||||||
changed =
|
changed =
|
||||||
extend_poststate_ann(fcx.ccx, id, poststate_res) ||
|
set_poststate_ann(fcx.ccx, id, poststate_res) ||
|
||||||
changed;
|
changed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -228,100 +312,44 @@ fn join_then_else(&fn_ctxt fcx, &@expr antec, &block conseq,
|
||||||
fn find_pre_post_state_expr(&fn_ctxt fcx, &prestate pres, @expr e) -> bool {
|
fn find_pre_post_state_expr(&fn_ctxt fcx, &prestate pres, @expr e) -> bool {
|
||||||
auto changed = false;
|
auto changed = false;
|
||||||
auto num_local_vars = num_constraints(fcx.enclosing);
|
auto num_local_vars = num_constraints(fcx.enclosing);
|
||||||
/*
|
|
||||||
log_err("states:");
|
|
||||||
log_expr_err(*e);
|
|
||||||
aux::log_bitv_err(fcx, expr_prestate(fcx.ccx, e));
|
|
||||||
aux::log_bitv_err(fcx, expr_poststate(fcx.ccx, e));
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* FIXME could get rid of some of the copy/paste */
|
|
||||||
alt (e.node) {
|
alt (e.node) {
|
||||||
case (expr_vec(?elts, _, _)) {
|
case (expr_vec(?elts, _, _)) {
|
||||||
ret find_pre_post_state_exprs(fcx, pres, e.id, elts);
|
ret find_pre_post_state_exprs(fcx, pres, e.id, elts, return);
|
||||||
}
|
}
|
||||||
case (expr_tup(?elts)) {
|
case (expr_tup(?elts)) {
|
||||||
ret find_pre_post_state_exprs(fcx, pres, e.id, elt_exprs(elts));
|
ret find_pre_post_state_exprs(fcx, pres, e.id,
|
||||||
|
elt_exprs(elts), return);
|
||||||
}
|
}
|
||||||
case (expr_call(?operator, ?operands)) {
|
case (expr_call(?operator, ?operands)) {
|
||||||
/* do the prestate for the rator */
|
changed = find_pre_post_state_call(fcx, pres, operator,
|
||||||
|
e.id, operands,
|
||||||
/* fcx.ccx.tcx.sess.span_note(operator.span,
|
controlflow_expr(fcx.ccx, operator))
|
||||||
"pres = " + aux::bitv_to_str(fcx, pres));
|
|| changed;
|
||||||
*/
|
|
||||||
|
|
||||||
changed =
|
|
||||||
find_pre_post_state_expr(fcx, pres, operator) || changed;
|
|
||||||
/* rands go left-to-right */
|
|
||||||
|
|
||||||
changed =
|
|
||||||
find_pre_post_state_exprs(fcx,
|
|
||||||
expr_poststate(fcx.ccx, operator),
|
|
||||||
e.id, operands) || changed;
|
|
||||||
/* if this is a failing call, it sets everything as initialized */
|
|
||||||
|
|
||||||
alt (controlflow_expr(fcx.ccx, operator)) {
|
|
||||||
case (noreturn) {
|
|
||||||
changed =
|
|
||||||
set_poststate_ann(fcx.ccx, e.id,
|
|
||||||
false_postcond(num_local_vars)) ||
|
|
||||||
changed;
|
|
||||||
}
|
|
||||||
case (_) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fcx.ccx.tcx.sess.span_note(operator.span,
|
|
||||||
"pres = " + aux::bitv_to_str(fcx, expr_poststate(fcx.ccx, e)));
|
|
||||||
*/
|
|
||||||
ret changed;
|
ret changed;
|
||||||
}
|
}
|
||||||
case (expr_spawn(_, _, ?operator, ?operands)) {
|
case (expr_spawn(_, _, ?operator, ?operands)) {
|
||||||
changed = find_pre_post_state_expr(fcx, pres, operator);
|
ret find_pre_post_state_call(fcx, pres, operator, e.id, operands,
|
||||||
ret find_pre_post_state_exprs(fcx,
|
return);
|
||||||
expr_poststate(fcx.ccx, operator),
|
}
|
||||||
e.id, operands) || changed;
|
|
||||||
}
|
|
||||||
case (expr_bind(?operator, ?maybe_args)) {
|
case (expr_bind(?operator, ?maybe_args)) {
|
||||||
changed =
|
ret find_pre_post_state_call(fcx, pres, operator, e.id,
|
||||||
find_pre_post_state_expr(fcx, pres, operator) || changed;
|
cat_options(maybe_args), return);
|
||||||
ret find_pre_post_state_exprs
|
|
||||||
(fcx, expr_poststate(fcx.ccx, operator), e.id,
|
|
||||||
cat_options[@expr](maybe_args)) || changed;
|
|
||||||
}
|
}
|
||||||
case (expr_path(_)) { ret pure_exp(fcx.ccx, e.id, pres); }
|
case (expr_path(_)) { ret pure_exp(fcx.ccx, e.id, pres); }
|
||||||
case (expr_log(_, ?ex)) {
|
case (expr_log(_, ?ex)) {
|
||||||
/* factor out the "one exp" pattern */
|
ret find_pre_post_state_sub(fcx, pres, ex, e.id, none);
|
||||||
|
|
||||||
changed = find_pre_post_state_expr(fcx, pres, ex);
|
|
||||||
changed = extend_prestate_ann(fcx.ccx, e.id, pres) || changed;
|
|
||||||
changed = extend_poststate_ann
|
|
||||||
(fcx.ccx, e.id, expr_poststate(fcx.ccx, ex)) || changed;
|
|
||||||
ret changed;
|
|
||||||
}
|
}
|
||||||
case (expr_chan(?ex)) {
|
case (expr_chan(?ex)) {
|
||||||
changed = find_pre_post_state_expr(fcx, pres, ex);
|
ret find_pre_post_state_sub(fcx, pres, ex, e.id, none);
|
||||||
changed = extend_prestate_ann(fcx.ccx, e.id, pres) || changed;
|
|
||||||
changed = extend_poststate_ann
|
|
||||||
(fcx.ccx, e.id, expr_poststate(fcx.ccx, ex)) || changed;
|
|
||||||
ret changed;
|
|
||||||
}
|
}
|
||||||
case (expr_ext(_, _, _, ?expanded)) {
|
case (expr_ext(_, _, _, ?expanded)) {
|
||||||
changed = find_pre_post_state_expr(fcx, pres, expanded);
|
ret find_pre_post_state_sub(fcx, pres, expanded, e.id, none);
|
||||||
changed = extend_prestate_ann(fcx.ccx, e.id, pres) || changed;
|
|
||||||
changed = extend_poststate_ann
|
|
||||||
(fcx.ccx, e.id, expr_poststate(fcx.ccx, expanded)) || changed;
|
|
||||||
ret changed;
|
|
||||||
}
|
}
|
||||||
case (expr_put(?maybe_e)) {
|
case (expr_put(?maybe_e)) {
|
||||||
alt (maybe_e) {
|
alt (maybe_e) {
|
||||||
case (some(?arg)) {
|
case (some(?arg)) {
|
||||||
changed = find_pre_post_state_expr(fcx, pres, arg);
|
ret find_pre_post_state_sub(fcx, pres, arg, e.id, none);
|
||||||
changed = extend_prestate_ann
|
|
||||||
(fcx.ccx, e.id, pres) || changed;
|
|
||||||
changed = extend_poststate_ann
|
|
||||||
(fcx.ccx, e.id, expr_poststate(fcx.ccx, arg)) ||
|
|
||||||
changed;
|
|
||||||
ret changed;
|
|
||||||
}
|
}
|
||||||
case (none) { ret pure_exp(fcx.ccx, e.id, pres); }
|
case (none) { ret pure_exp(fcx.ccx, e.id, pres); }
|
||||||
}
|
}
|
||||||
|
@ -331,20 +359,20 @@ fn find_pre_post_state_expr(&fn_ctxt fcx, &prestate pres, @expr e) -> bool {
|
||||||
case (expr_fn(?f)) { ret pure_exp(fcx.ccx, e.id, pres); }
|
case (expr_fn(?f)) { ret pure_exp(fcx.ccx, e.id, pres); }
|
||||||
case (expr_block(?b)) {
|
case (expr_block(?b)) {
|
||||||
changed = find_pre_post_state_block(fcx, pres, b) || changed;
|
changed = find_pre_post_state_block(fcx, pres, b) || changed;
|
||||||
changed = extend_prestate_ann(fcx.ccx, e.id, pres) || changed;
|
changed = set_prestate_ann(fcx.ccx, e.id, pres) || changed;
|
||||||
changed = extend_poststate_ann
|
changed = set_poststate_ann
|
||||||
(fcx.ccx, e.id, block_poststate(fcx.ccx, b)) || changed;
|
(fcx.ccx, e.id, block_poststate(fcx.ccx, b)) || changed;
|
||||||
ret changed;
|
ret changed;
|
||||||
}
|
}
|
||||||
case (expr_rec(?fields, ?maybe_base)) {
|
case (expr_rec(?fields, ?maybe_base)) {
|
||||||
changed = find_pre_post_state_exprs
|
changed = find_pre_post_state_exprs
|
||||||
(fcx, pres, e.id, field_exprs(fields)) || changed;
|
(fcx, pres, e.id, field_exprs(fields), return) || changed;
|
||||||
alt (maybe_base) {
|
alt (maybe_base) {
|
||||||
case (none) {/* do nothing */ }
|
case (none) {/* do nothing */ }
|
||||||
case (some(?base)) {
|
case (some(?base)) {
|
||||||
changed =
|
changed =
|
||||||
find_pre_post_state_expr(fcx, pres, base) || changed;
|
find_pre_post_state_expr(fcx, pres, base) || changed;
|
||||||
changed = extend_poststate_ann
|
changed = set_poststate_ann
|
||||||
(fcx.ccx, e.id, expr_poststate(fcx.ccx, base))
|
(fcx.ccx, e.id, expr_poststate(fcx.ccx, base))
|
||||||
|| changed;
|
|| changed;
|
||||||
}
|
}
|
||||||
|
@ -352,108 +380,34 @@ fn find_pre_post_state_expr(&fn_ctxt fcx, &prestate pres, @expr e) -> bool {
|
||||||
ret changed;
|
ret changed;
|
||||||
}
|
}
|
||||||
case (expr_move(?lhs, ?rhs)) {
|
case (expr_move(?lhs, ?rhs)) {
|
||||||
|
ret find_pre_post_state_two(fcx, pres, lhs, rhs,
|
||||||
extend_prestate_ann(fcx.ccx, e.id, pres);
|
e.id, oper_move);
|
||||||
alt (lhs.node) {
|
|
||||||
case (expr_path(?p)) {
|
|
||||||
// assignment to local var
|
|
||||||
|
|
||||||
changed = pure_exp(fcx.ccx, lhs.id, pres) || changed;
|
|
||||||
changed = find_pre_post_state_expr
|
|
||||||
(fcx, pres, rhs) || changed;
|
|
||||||
// not extending e's poststate,
|
|
||||||
// because rhs is getting deinit'd anyway
|
|
||||||
changed = gen_if_local(fcx, lhs.id, e.id, p) || changed;
|
|
||||||
}
|
|
||||||
case (_) {
|
|
||||||
// assignment to something that must already have been
|
|
||||||
// init'd
|
|
||||||
|
|
||||||
changed = find_pre_post_state_expr(fcx, pres, lhs)
|
|
||||||
|| changed;
|
|
||||||
changed = find_pre_post_state_expr
|
|
||||||
(fcx, expr_poststate(fcx.ccx, lhs), rhs)
|
|
||||||
|| changed;
|
|
||||||
changed = extend_poststate_ann
|
|
||||||
(fcx.ccx, e.id, expr_poststate(fcx.ccx, rhs))
|
|
||||||
|| changed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
changed = forget_in_poststate(fcx, rhs.span, e.id, rhs.id)
|
|
||||||
|| changed;
|
|
||||||
ret changed;
|
|
||||||
}
|
}
|
||||||
case (expr_assign(?lhs, ?rhs)) {
|
case (expr_assign(?lhs, ?rhs)) {
|
||||||
extend_prestate_ann(fcx.ccx, e.id, pres);
|
ret find_pre_post_state_two(fcx, pres, lhs, rhs,
|
||||||
alt (lhs.node) {
|
e.id, oper_assign);
|
||||||
case (expr_path(?p)) {
|
|
||||||
// assignment to local var
|
|
||||||
|
|
||||||
changed = pure_exp(fcx.ccx, lhs.id, pres) || changed;
|
|
||||||
changed = find_pre_post_state_expr(fcx, pres, rhs)
|
|
||||||
|| changed;
|
|
||||||
changed = extend_poststate_ann
|
|
||||||
(fcx.ccx, e.id, expr_poststate(fcx.ccx, rhs))
|
|
||||||
|| changed;
|
|
||||||
changed = gen_if_local(fcx, lhs.id, e.id, p) || changed;
|
|
||||||
}
|
|
||||||
case (_) {
|
|
||||||
// assignment to something that must already have been
|
|
||||||
// init'd
|
|
||||||
|
|
||||||
changed = find_pre_post_state_expr(fcx, pres, lhs)
|
|
||||||
|| changed;
|
|
||||||
changed = find_pre_post_state_expr
|
|
||||||
(fcx, expr_poststate(fcx.ccx, lhs), rhs) || changed;
|
|
||||||
changed = extend_poststate_ann
|
|
||||||
(fcx.ccx, e.id, expr_poststate(fcx.ccx, rhs))
|
|
||||||
|| changed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ret changed;
|
|
||||||
}
|
}
|
||||||
case (expr_swap(?lhs, ?rhs)) {
|
case (expr_swap(?lhs, ?rhs)) {
|
||||||
/* quite similar to binary -- should abstract this */
|
ret find_pre_post_state_two(fcx, pres, lhs, rhs, e.id,
|
||||||
|
oper_swap);
|
||||||
changed = extend_prestate_ann(fcx.ccx, e.id, pres) || changed;
|
// Could be more precise and actually swap the role of
|
||||||
changed = find_pre_post_state_expr(fcx, pres, lhs) || changed;
|
// lhs and rhs in constraints
|
||||||
changed = find_pre_post_state_expr
|
|
||||||
(fcx, expr_poststate(fcx.ccx, lhs), rhs) || changed;
|
|
||||||
changed = extend_poststate_ann
|
|
||||||
(fcx.ccx, e.id, expr_poststate(fcx.ccx, rhs)) || changed;
|
|
||||||
ret changed;
|
|
||||||
}
|
}
|
||||||
case (expr_recv(?lhs, ?rhs)) {
|
case (expr_recv(?lhs, ?rhs)) {
|
||||||
extend_prestate_ann(fcx.ccx, e.id, pres);
|
// Opposite order as most other binary operations,
|
||||||
alt (rhs.node) {
|
// so not using find_pre_post_state_two
|
||||||
case (expr_path(?p)) {
|
auto changed = set_prestate_ann(fcx.ccx, e.id, pres);
|
||||||
// receive to local var
|
changed = find_pre_post_state_expr(fcx, pres, lhs) || changed;
|
||||||
|
changed = find_pre_post_state_expr(fcx,
|
||||||
changed = pure_exp(fcx.ccx, rhs.id, pres) || changed;
|
expr_poststate(fcx.ccx, lhs), rhs) || changed;
|
||||||
changed = find_pre_post_state_expr(fcx, pres, lhs)
|
auto post = tritv_clone(expr_poststate(fcx.ccx, rhs));
|
||||||
|| changed;
|
forget_in_poststate_still_init(fcx, post, rhs.id);
|
||||||
changed = extend_poststate_ann
|
gen_if_local(fcx, post, rhs);
|
||||||
(fcx.ccx, e.id, expr_poststate(fcx.ccx, lhs))
|
changed = set_poststate_ann(fcx.ccx, e.id, post) || changed;
|
||||||
|| changed;
|
|
||||||
changed = gen_if_local(fcx, rhs.id, e.id, p) || changed;
|
|
||||||
}
|
|
||||||
case (_) {
|
|
||||||
// receive to something that must already have been init'd
|
|
||||||
|
|
||||||
changed = find_pre_post_state_expr
|
|
||||||
(fcx, pres, rhs) || changed;
|
|
||||||
changed = find_pre_post_state_expr
|
|
||||||
(fcx, expr_poststate(fcx.ccx, rhs), lhs) || changed;
|
|
||||||
changed = extend_poststate_ann
|
|
||||||
(fcx.ccx, e.id, expr_poststate(fcx.ccx, lhs))
|
|
||||||
|| changed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ret changed;
|
ret changed;
|
||||||
}
|
}
|
||||||
case (expr_ret(?maybe_ret_val)) {
|
case (expr_ret(?maybe_ret_val)) {
|
||||||
changed = extend_prestate_ann(fcx.ccx, e.id, pres) || changed;
|
changed = set_prestate_ann(fcx.ccx, e.id, pres) || changed;
|
||||||
/* normally, everything is true if execution continues after
|
/* normally, everything is true if execution continues after
|
||||||
a ret expression (since execution never continues locally
|
a ret expression (since execution never continues locally
|
||||||
after a ret expression */
|
after a ret expression */
|
||||||
|
@ -471,14 +425,14 @@ fn find_pre_post_state_expr(&fn_ctxt fcx, &prestate pres, @expr e) -> bool {
|
||||||
alt (maybe_ret_val) {
|
alt (maybe_ret_val) {
|
||||||
case (none) {/* do nothing */ }
|
case (none) {/* do nothing */ }
|
||||||
case (some(?ret_val)) {
|
case (some(?ret_val)) {
|
||||||
changed = find_pre_post_state_expr
|
changed = find_pre_post_state_expr(fcx, pres, ret_val)
|
||||||
(fcx, pres, ret_val) || changed;
|
|| changed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret changed;
|
ret changed;
|
||||||
}
|
}
|
||||||
case (expr_be(?val)) {
|
case (expr_be(?val)) {
|
||||||
changed = extend_prestate_ann(fcx.ccx, e.id, pres) || changed;
|
changed = set_prestate_ann(fcx.ccx, e.id, pres) || changed;
|
||||||
set_poststate_ann(fcx.ccx, e.id, false_postcond(num_local_vars));
|
set_poststate_ann(fcx.ccx, e.id, false_postcond(num_local_vars));
|
||||||
changed = find_pre_post_state_expr(fcx, pres, val) || changed;
|
changed = find_pre_post_state_expr(fcx, pres, val) || changed;
|
||||||
ret changed;
|
ret changed;
|
||||||
|
@ -494,38 +448,17 @@ fn find_pre_post_state_expr(&fn_ctxt fcx, &prestate pres, @expr e) -> bool {
|
||||||
}
|
}
|
||||||
case (expr_binary(?bop, ?l, ?r)) {
|
case (expr_binary(?bop, ?l, ?r)) {
|
||||||
/* FIXME: what if bop is lazy? */
|
/* FIXME: what if bop is lazy? */
|
||||||
|
ret find_pre_post_state_two(fcx, pres, l, r, e.id, oper_pure);
|
||||||
changed = extend_prestate_ann(fcx.ccx, e.id, pres) || changed;
|
|
||||||
changed = find_pre_post_state_expr(fcx, pres, l) || changed;
|
|
||||||
changed = find_pre_post_state_expr
|
|
||||||
(fcx, expr_poststate(fcx.ccx, l), r) || changed;
|
|
||||||
changed = extend_poststate_ann
|
|
||||||
(fcx.ccx, e.id, expr_poststate(fcx.ccx, r)) || changed;
|
|
||||||
ret changed;
|
|
||||||
}
|
}
|
||||||
case (expr_send(?l, ?r)) {
|
case (expr_send(?l, ?r)) {
|
||||||
changed = extend_prestate_ann(fcx.ccx, e.id, pres) || changed;
|
ret find_pre_post_state_two(fcx, pres, l, r, e.id, oper_pure);
|
||||||
changed = find_pre_post_state_expr(fcx, pres, l) || changed;
|
|
||||||
changed = find_pre_post_state_expr
|
|
||||||
(fcx, expr_poststate(fcx.ccx, l), r) || changed;
|
|
||||||
changed = extend_poststate_ann
|
|
||||||
(fcx.ccx, e.id, expr_poststate(fcx.ccx, r)) || changed;
|
|
||||||
ret changed;
|
|
||||||
}
|
}
|
||||||
case (expr_assign_op(?op, ?lhs, ?rhs)) {
|
case (expr_assign_op(?op, ?lhs, ?rhs)) {
|
||||||
/* quite similar to binary -- should abstract this */
|
ret find_pre_post_state_two(fcx, pres, lhs, rhs, e.id,
|
||||||
|
oper_assign);
|
||||||
changed = extend_prestate_ann(fcx.ccx, e.id, pres) || changed;
|
|
||||||
changed = find_pre_post_state_expr(fcx, pres, lhs) || changed;
|
|
||||||
changed =
|
|
||||||
find_pre_post_state_expr(fcx, expr_poststate(fcx.ccx, lhs),
|
|
||||||
rhs) || changed;
|
|
||||||
changed = extend_poststate_ann
|
|
||||||
(fcx.ccx, e.id, expr_poststate(fcx.ccx, rhs)) || changed;
|
|
||||||
ret changed;
|
|
||||||
}
|
}
|
||||||
case (expr_while(?test, ?body)) {
|
case (expr_while(?test, ?body)) {
|
||||||
changed = extend_prestate_ann(fcx.ccx, e.id, pres) || changed;
|
changed = set_prestate_ann(fcx.ccx, e.id, pres) || changed;
|
||||||
/* to handle general predicates, we need to pass in
|
/* to handle general predicates, we need to pass in
|
||||||
pres `intersect` (poststate(a))
|
pres `intersect` (poststate(a))
|
||||||
like: auto test_pres = intersect_postconds(pres,
|
like: auto test_pres = intersect_postconds(pres,
|
||||||
|
@ -547,12 +480,12 @@ fn find_pre_post_state_expr(&fn_ctxt fcx, &prestate pres, @expr e) -> bool {
|
||||||
|
|
||||||
auto e_post = expr_poststate(fcx.ccx, test);
|
auto e_post = expr_poststate(fcx.ccx, test);
|
||||||
auto b_post = block_poststate(fcx.ccx, body);
|
auto b_post = block_poststate(fcx.ccx, body);
|
||||||
ret extend_poststate_ann
|
ret set_poststate_ann
|
||||||
(fcx.ccx, e.id, intersect_postconds([e_post, b_post])) ||
|
(fcx.ccx, e.id, intersect_postconds([e_post, b_post])) ||
|
||||||
changed
|
changed;
|
||||||
}
|
}
|
||||||
case (expr_do_while(?body, ?test)) {
|
case (expr_do_while(?body, ?test)) {
|
||||||
changed = extend_prestate_ann(fcx.ccx, e.id, pres) || changed;
|
changed = set_prestate_ann(fcx.ccx, e.id, pres) || changed;
|
||||||
auto changed0 = changed;
|
auto changed0 = changed;
|
||||||
changed = find_pre_post_state_block(fcx, pres, body) || changed;
|
changed = find_pre_post_state_block(fcx, pres, body) || changed;
|
||||||
/* conservative approximination: if the body of the loop
|
/* conservative approximination: if the body of the loop
|
||||||
|
@ -579,7 +512,7 @@ fn find_pre_post_state_expr(&fn_ctxt fcx, &prestate pres, @expr e) -> bool {
|
||||||
set_poststate_ann(fcx.ccx, e.id, pres);
|
set_poststate_ann(fcx.ccx, e.id, pres);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
changed = extend_poststate_ann(fcx.ccx, e.id,
|
changed = set_poststate_ann(fcx.ccx, e.id,
|
||||||
expr_poststate(fcx.ccx, test)) ||
|
expr_poststate(fcx.ccx, test)) ||
|
||||||
changed;
|
changed;
|
||||||
}
|
}
|
||||||
|
@ -592,18 +525,10 @@ fn find_pre_post_state_expr(&fn_ctxt fcx, &prestate pres, @expr e) -> bool {
|
||||||
ret find_pre_post_state_loop(fcx, pres, d, index, body, e.id);
|
ret find_pre_post_state_loop(fcx, pres, d, index, body, e.id);
|
||||||
}
|
}
|
||||||
case (expr_index(?val, ?sub)) {
|
case (expr_index(?val, ?sub)) {
|
||||||
changed = extend_prestate_ann(fcx.ccx, e.id, pres) || changed;
|
ret find_pre_post_state_two(fcx, pres, val, sub, e.id, oper_pure);
|
||||||
changed = find_pre_post_state_expr(fcx, pres, val) || changed;
|
|
||||||
changed =
|
|
||||||
find_pre_post_state_expr
|
|
||||||
(fcx, expr_poststate(fcx.ccx, val), sub) || changed;
|
|
||||||
changed =
|
|
||||||
extend_poststate_ann(fcx.ccx, e.id,
|
|
||||||
expr_poststate(fcx.ccx, sub));
|
|
||||||
ret changed;
|
|
||||||
}
|
}
|
||||||
case (expr_alt(?val, ?alts)) {
|
case (expr_alt(?val, ?alts)) {
|
||||||
changed = extend_prestate_ann(fcx.ccx, e.id, pres) || changed;
|
changed = set_prestate_ann(fcx.ccx, e.id, pres) || changed;
|
||||||
changed = find_pre_post_state_expr(fcx, pres, val) || changed;
|
changed = find_pre_post_state_expr(fcx, pres, val) || changed;
|
||||||
auto e_post = expr_poststate(fcx.ccx, val);
|
auto e_post = expr_poststate(fcx.ccx, val);
|
||||||
auto a_post;
|
auto a_post;
|
||||||
|
@ -624,32 +549,20 @@ fn find_pre_post_state_expr(&fn_ctxt fcx, &prestate pres, @expr e) -> bool {
|
||||||
|
|
||||||
a_post = e_post;
|
a_post = e_post;
|
||||||
}
|
}
|
||||||
changed = extend_poststate_ann(fcx.ccx, e.id, a_post) || changed;
|
changed = set_poststate_ann(fcx.ccx, e.id, a_post) || changed;
|
||||||
ret changed;
|
ret changed;
|
||||||
}
|
}
|
||||||
case (expr_field(?val, _)) {
|
case (expr_field(?val, _)) {
|
||||||
changed = find_pre_post_state_expr(fcx, pres, val);
|
ret find_pre_post_state_sub(fcx, pres, val, e.id, none);
|
||||||
changed = extend_prestate_ann(fcx.ccx, e.id, pres) || changed;
|
|
||||||
changed = extend_poststate_ann
|
|
||||||
(fcx.ccx, e.id, expr_poststate(fcx.ccx, val)) || changed;
|
|
||||||
ret changed;
|
|
||||||
}
|
}
|
||||||
case (expr_unary(_, ?operand)) {
|
case (expr_unary(_, ?operand)) {
|
||||||
changed = find_pre_post_state_expr(fcx, pres, operand) || changed;
|
ret find_pre_post_state_sub(fcx, pres, operand, e.id, none);
|
||||||
changed = extend_prestate_ann(fcx.ccx, e.id, pres) || changed;
|
|
||||||
ret extend_poststate_ann
|
|
||||||
(fcx.ccx, e.id, expr_poststate(fcx.ccx, operand))
|
|
||||||
|| changed;
|
|
||||||
}
|
}
|
||||||
case (expr_cast(?operand, _)) {
|
case (expr_cast(?operand, _)) {
|
||||||
changed = find_pre_post_state_expr(fcx, pres, operand) || changed;
|
ret find_pre_post_state_sub(fcx, pres, operand, e.id, none);
|
||||||
changed = extend_prestate_ann(fcx.ccx, e.id, pres) || changed;
|
|
||||||
ret extend_poststate_ann
|
|
||||||
(fcx.ccx, e.id, expr_poststate(fcx.ccx, operand))
|
|
||||||
|| changed;
|
|
||||||
}
|
}
|
||||||
case (expr_fail(_)) {
|
case (expr_fail(_)) {
|
||||||
changed = extend_prestate_ann(fcx.ccx, e.id, pres) || changed;
|
changed = set_prestate_ann(fcx.ccx, e.id, pres) || changed;
|
||||||
/* if execution continues after fail, then everything is true!
|
/* if execution continues after fail, then everything is true!
|
||||||
woo! */
|
woo! */
|
||||||
|
|
||||||
|
@ -658,19 +571,14 @@ fn find_pre_post_state_expr(&fn_ctxt fcx, &prestate pres, @expr e) -> bool {
|
||||||
ret changed;
|
ret changed;
|
||||||
}
|
}
|
||||||
case (expr_assert(?p)) {
|
case (expr_assert(?p)) {
|
||||||
changed = extend_prestate_ann(fcx.ccx, e.id, pres) || changed;
|
ret find_pre_post_state_sub(fcx, pres, p, e.id, none);
|
||||||
changed = find_pre_post_state_expr(fcx, pres, p) || changed;
|
|
||||||
changed = extend_poststate_ann(fcx.ccx, e.id, pres) || changed;
|
|
||||||
ret changed;
|
|
||||||
}
|
}
|
||||||
case (expr_check(?p)) {
|
case (expr_check(?p)) {
|
||||||
changed = extend_prestate_ann(fcx.ccx, e.id, pres) || changed;
|
|
||||||
changed = find_pre_post_state_expr(fcx, pres, p) || changed;
|
|
||||||
changed = extend_poststate_ann(fcx.ccx, e.id, pres) || changed;
|
|
||||||
/* predicate p holds after this expression executes */
|
/* predicate p holds after this expression executes */
|
||||||
|
|
||||||
let aux::constr c = expr_to_constr(fcx.ccx.tcx, p);
|
let aux::constr c = expr_to_constr(fcx.ccx.tcx, p);
|
||||||
changed = gen_poststate(fcx, e.id, c.node) || changed;
|
changed = find_pre_post_state_sub(fcx, pres, p, e.id,
|
||||||
|
some(c.node)) || changed;
|
||||||
ret changed;
|
ret changed;
|
||||||
}
|
}
|
||||||
case (expr_if_check(?p, ?conseq, ?maybe_alt)) {
|
case (expr_if_check(?p, ?conseq, ?maybe_alt)) {
|
||||||
|
@ -686,14 +594,7 @@ fn find_pre_post_state_expr(&fn_ctxt fcx, &prestate pres, @expr e) -> bool {
|
||||||
case (expr_anon_obj(?anon_obj, _, _)) {
|
case (expr_anon_obj(?anon_obj, _, _)) {
|
||||||
alt (anon_obj.with_obj) {
|
alt (anon_obj.with_obj) {
|
||||||
case (some(?wt)) {
|
case (some(?wt)) {
|
||||||
changed = find_pre_post_state_expr(fcx, pres, wt);
|
ret find_pre_post_state_sub(fcx, pres, wt, e.id, none);
|
||||||
changed =
|
|
||||||
extend_prestate_ann(fcx.ccx, e.id, pres) || changed;
|
|
||||||
changed =
|
|
||||||
extend_poststate_ann(fcx.ccx, e.id,
|
|
||||||
expr_poststate(fcx.ccx, wt)) ||
|
|
||||||
changed;
|
|
||||||
ret changed;
|
|
||||||
}
|
}
|
||||||
case (none) { ret pure_exp(fcx.ccx, e.id, pres); }
|
case (none) { ret pure_exp(fcx.ccx, e.id, pres); }
|
||||||
}
|
}
|
||||||
|
@ -705,15 +606,15 @@ fn find_pre_post_state_stmt(&fn_ctxt fcx, &prestate pres, @stmt s) -> bool {
|
||||||
auto changed = false;
|
auto changed = false;
|
||||||
auto stmt_ann = stmt_to_ann(fcx.ccx, *s);
|
auto stmt_ann = stmt_to_ann(fcx.ccx, *s);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
log_err "*At beginning: stmt = ";
|
log_err "*At beginning: stmt = ";
|
||||||
log_stmt_err(*s);
|
log_stmt_err(*s);
|
||||||
log_err "*prestate = ";
|
log_err "*prestate = ";
|
||||||
log_err bitv::to_str(stmt_ann.states.prestate);
|
log_err tritv::to_str(stmt_ann.states.prestate);
|
||||||
log_err "*poststate =";
|
log_err "*poststate =";
|
||||||
log_err bitv::to_str(stmt_ann.states.poststate);
|
log_err tritv::to_str(stmt_ann.states.poststate);
|
||||||
log_err "*changed =";
|
log_err "pres = ";
|
||||||
log_err changed;
|
log_err tritv::to_str(pres);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
alt (s.node) {
|
alt (s.node) {
|
||||||
|
@ -723,37 +624,32 @@ fn find_pre_post_state_stmt(&fn_ctxt fcx, &prestate pres, @stmt s) -> bool {
|
||||||
alt (alocal.node.init) {
|
alt (alocal.node.init) {
|
||||||
case (some(?an_init)) {
|
case (some(?an_init)) {
|
||||||
changed =
|
changed =
|
||||||
extend_prestate(stmt_ann.states.prestate,
|
set_prestate(stmt_ann, pres) || changed;
|
||||||
pres) || changed;
|
|
||||||
changed =
|
changed =
|
||||||
find_pre_post_state_expr(fcx, pres,
|
find_pre_post_state_expr(fcx, pres,
|
||||||
an_init.expr)
|
an_init.expr)
|
||||||
|| changed;
|
|| changed;
|
||||||
|
|
||||||
|
auto post = tritv_clone(expr_poststate(fcx.ccx,
|
||||||
/* FIXME less copypasta */
|
an_init.expr));
|
||||||
alt (an_init.op) {
|
alt (an_init.op) {
|
||||||
case (init_move) {
|
case (init_move) {
|
||||||
changed = forget_in_poststate(fcx,
|
clear_in_poststate_expr(fcx, an_init.expr,
|
||||||
an_init.expr.span, id, an_init.expr.id)
|
post);
|
||||||
|| changed;
|
|
||||||
/* Safe to forget rhs's poststate here 'cause it's a var. */
|
|
||||||
}
|
}
|
||||||
case (_) { /* nothing gets deinitialized */
|
case (_) { /* nothing gets deinitialized */ }
|
||||||
changed =
|
|
||||||
extend_poststate(
|
|
||||||
stmt_ann.states.poststate,
|
|
||||||
expr_poststate(fcx.ccx, an_init.expr))
|
|
||||||
|| changed;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
changed =
|
set_in_poststate_ident(fcx, alocal.node.id,
|
||||||
gen_poststate(fcx, id,
|
alocal.node.ident, post);
|
||||||
rec(id=alocal.node.id,
|
|
||||||
c=ninit(alocal.node.ident)))
|
/* important to do this in one step to ensure
|
||||||
|
termination (don't want to set changed to true
|
||||||
|
for intermediate changes) */
|
||||||
|
changed = set_poststate(stmt_ann, post)
|
||||||
|| changed;
|
|| changed;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
log_err "Summary: stmt = ";
|
log_err "Summary: stmt = ";
|
||||||
log_stmt_err(*s);
|
log_stmt_err(*s);
|
||||||
|
@ -769,22 +665,18 @@ fn find_pre_post_state_stmt(&fn_ctxt fcx, &prestate pres, @stmt s) -> bool {
|
||||||
}
|
}
|
||||||
case (none) {
|
case (none) {
|
||||||
changed =
|
changed =
|
||||||
extend_prestate(stmt_ann.states.prestate,
|
set_prestate(stmt_ann, pres) || changed;
|
||||||
pres) || changed;
|
|
||||||
changed =
|
changed =
|
||||||
extend_poststate(stmt_ann.states.poststate,
|
set_poststate(stmt_ann, pres) || changed;
|
||||||
pres) || changed;
|
|
||||||
ret changed;
|
ret changed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case (decl_item(?an_item)) {
|
case (decl_item(?an_item)) {
|
||||||
changed =
|
changed =
|
||||||
extend_prestate(stmt_ann.states.prestate, pres) ||
|
set_prestate(stmt_ann, pres) || changed;
|
||||||
changed;
|
|
||||||
changed =
|
changed =
|
||||||
extend_poststate(stmt_ann.states.poststate, pres) ||
|
set_poststate(stmt_ann, pres) || changed;
|
||||||
changed;
|
|
||||||
/* the outer "walk" will recurse into the item */
|
/* the outer "walk" will recurse into the item */
|
||||||
|
|
||||||
ret changed;
|
ret changed;
|
||||||
|
@ -794,14 +686,13 @@ fn find_pre_post_state_stmt(&fn_ctxt fcx, &prestate pres, @stmt s) -> bool {
|
||||||
case (stmt_expr(?ex, _)) {
|
case (stmt_expr(?ex, _)) {
|
||||||
changed = find_pre_post_state_expr(fcx, pres, ex) || changed;
|
changed = find_pre_post_state_expr(fcx, pres, ex) || changed;
|
||||||
changed =
|
changed =
|
||||||
extend_prestate(stmt_ann.states.prestate,
|
set_prestate(stmt_ann, expr_prestate(fcx.ccx, ex)) || changed;
|
||||||
expr_prestate(fcx.ccx, ex)) || changed;
|
|
||||||
changed =
|
changed =
|
||||||
extend_poststate(stmt_ann.states.poststate,
|
set_poststate(stmt_ann, expr_poststate(fcx.ccx, ex))
|
||||||
expr_poststate(fcx.ccx, ex)) || changed;
|
|| changed;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
log_err("Summary: stmt = ");
|
log_err "Finally:";
|
||||||
log_stmt_err(*s);
|
log_stmt_err(*s);
|
||||||
log_err("prestate = ");
|
log_err("prestate = ");
|
||||||
// log_err(bitv::to_str(stmt_ann.states.prestate));
|
// log_err(bitv::to_str(stmt_ann.states.prestate));
|
||||||
|
@ -848,7 +739,7 @@ fn find_pre_post_state_block(&fn_ctxt fcx, &prestate pres0, &block b) ->
|
||||||
|
|
||||||
set_prestate_ann(fcx.ccx, b.node.id, pres0);
|
set_prestate_ann(fcx.ccx, b.node.id, pres0);
|
||||||
set_poststate_ann(fcx.ccx, b.node.id, post);
|
set_poststate_ann(fcx.ccx, b.node.id, post);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
log_err "For block:";
|
log_err "For block:";
|
||||||
log_block_err(b);
|
log_block_err(b);
|
||||||
|
@ -881,16 +772,7 @@ fn find_pre_post_state_fn(&fn_ctxt fcx, &_fn f) -> bool {
|
||||||
if (!type_is_nil(fcx.ccx.tcx, tailty) &&
|
if (!type_is_nil(fcx.ccx.tcx, tailty) &&
|
||||||
!type_is_bot(fcx.ccx.tcx, tailty)) {
|
!type_is_bot(fcx.ccx.tcx, tailty)) {
|
||||||
auto p = false_postcond(num_local_vars);
|
auto p = false_postcond(num_local_vars);
|
||||||
set_poststate_ann(fcx.ccx, tailexpr.id, p);
|
|
||||||
// be sure to set the block poststate to the same thing
|
|
||||||
set_poststate_ann(fcx.ccx, f.body.node.id, p);
|
set_poststate_ann(fcx.ccx, f.body.node.id, p);
|
||||||
alt (fcx.enclosing.cf) {
|
|
||||||
case (noreturn) {
|
|
||||||
kill_poststate(fcx, tailexpr.id,
|
|
||||||
rec(id=fcx.id, c=ninit(fcx.name)));
|
|
||||||
}
|
|
||||||
case (_) { }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case (none) {/* fallthrough */ }
|
case (none) {/* fallthrough */ }
|
||||||
|
|
|
@ -17,6 +17,7 @@ export tritv_intersect;
|
||||||
export tritv_copy;
|
export tritv_copy;
|
||||||
export tritv_clear;
|
export tritv_clear;
|
||||||
export tritv_doesntcare;
|
export tritv_doesntcare;
|
||||||
|
export to_str;
|
||||||
|
|
||||||
/* for a fixed index:
|
/* for a fixed index:
|
||||||
10 = "this constraint may or may not be true after execution"
|
10 = "this constraint may or may not be true after execution"
|
||||||
|
@ -81,7 +82,6 @@ fn trit_or(trit a, trit b) -> trit {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: not sure about this
|
|
||||||
fn trit_and(trit a, trit b) -> trit {
|
fn trit_and(trit a, trit b) -> trit {
|
||||||
alt (a) {
|
alt (a) {
|
||||||
case (dont_care) { dont_care }
|
case (dont_care) { dont_care }
|
||||||
|
@ -89,13 +89,15 @@ fn trit_and(trit a, trit b) -> trit {
|
||||||
alt (b) {
|
alt (b) {
|
||||||
case (dont_care) { dont_care }
|
case (dont_care) { dont_care }
|
||||||
case (ttrue) { ttrue }
|
case (ttrue) { ttrue }
|
||||||
case (tfalse) { tfalse } // FIXME: ???
|
case (tfalse) { dont_care } // ???
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case (tfalse) { tfalse }
|
case (tfalse) { tfalse }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn change(bool changed, trit old, trit new) -> bool { changed || new != old }
|
||||||
|
|
||||||
fn tritv_difference(&t p1, &t p2) -> bool {
|
fn tritv_difference(&t p1, &t p2) -> bool {
|
||||||
let uint i = 0u;
|
let uint i = 0u;
|
||||||
assert (p1.nbits == p2.nbits);
|
assert (p1.nbits == p2.nbits);
|
||||||
|
@ -104,7 +106,7 @@ fn tritv_difference(&t p1, &t p2) -> bool {
|
||||||
while (i < sz) {
|
while (i < sz) {
|
||||||
auto old = tritv_get(p1, i);
|
auto old = tritv_get(p1, i);
|
||||||
auto new = trit_minus(old, tritv_get(p2, i));
|
auto new = trit_minus(old, tritv_get(p2, i));
|
||||||
changed = changed || (old != new);
|
changed = change(changed, old, new);
|
||||||
tritv_set(i, p1, new);
|
tritv_set(i, p1, new);
|
||||||
i += 1u;
|
i += 1u;
|
||||||
}
|
}
|
||||||
|
@ -119,7 +121,7 @@ fn tritv_union(&t p1, &t p2) -> bool {
|
||||||
while (i < sz) {
|
while (i < sz) {
|
||||||
auto old = tritv_get(p1, i);
|
auto old = tritv_get(p1, i);
|
||||||
auto new = trit_or(old, tritv_get(p2, i));
|
auto new = trit_or(old, tritv_get(p2, i));
|
||||||
changed = changed || (old != new);
|
changed = change(changed, old, new);
|
||||||
tritv_set(i, p1, new);
|
tritv_set(i, p1, new);
|
||||||
i += 1u;
|
i += 1u;
|
||||||
}
|
}
|
||||||
|
@ -134,7 +136,7 @@ fn tritv_intersect(&t p1, &t p2) -> bool {
|
||||||
while (i < sz) {
|
while (i < sz) {
|
||||||
auto old = tritv_get(p1, i);
|
auto old = tritv_get(p1, i);
|
||||||
auto new = trit_and(old, tritv_get(p2, i));
|
auto new = trit_and(old, tritv_get(p2, i));
|
||||||
changed = changed || (old != new);
|
changed = change(changed, old, new);
|
||||||
tritv_set(i, p1, new);
|
tritv_set(i, p1, new);
|
||||||
i += 1u;
|
i += 1u;
|
||||||
}
|
}
|
||||||
|
@ -166,24 +168,26 @@ fn tritv_set(uint i, &t v, trit t) -> bool {
|
||||||
bitv::set(v.val, i, false);
|
bitv::set(v.val, i, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret (old != t);
|
ret change(false, old, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tritv_copy(&t target, &t source) -> bool {
|
fn tritv_copy(&t target, &t source) -> bool {
|
||||||
let uint i = 0u;
|
let uint i = 0u;
|
||||||
assert (target.nbits == source.nbits);
|
assert (target.nbits == source.nbits);
|
||||||
auto changed = false;
|
auto changed = false;
|
||||||
auto old;
|
auto oldunc;
|
||||||
auto new;
|
auto newunc;
|
||||||
|
auto oldval;
|
||||||
|
auto newval;
|
||||||
while (i < target.nbits) {
|
while (i < target.nbits) {
|
||||||
old = bitv::get(target.uncertain, i);
|
oldunc = bitv::get(target.uncertain, i);
|
||||||
new = bitv::get(source.uncertain, i);
|
newunc = bitv::get(source.uncertain, i);
|
||||||
bitv::set(target.uncertain, i, new);
|
oldval = bitv::get(target.val, i);
|
||||||
changed = changed || (old != new);
|
newval = bitv::get(source.val, i);
|
||||||
old = bitv::get(target.val, i);
|
bitv::set(target.uncertain, i, newunc);
|
||||||
new = bitv::get(source.val, i);
|
changed = changed || (oldunc && !newunc);
|
||||||
bitv::set(target.val, i, new);
|
bitv::set(target.val, i, newval);
|
||||||
changed = changed || (old != new);
|
changed = changed || (oldval && !newval);
|
||||||
i += 1u;
|
i += 1u;
|
||||||
}
|
}
|
||||||
ret changed;
|
ret changed;
|
||||||
|
@ -234,6 +238,20 @@ fn to_vec(&t v) -> vec[uint] {
|
||||||
}
|
}
|
||||||
ret rslt;
|
ret rslt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn to_str(&t v) -> str {
|
||||||
|
let uint i = 0u;
|
||||||
|
let str res = "";
|
||||||
|
while (i < v.nbits) {
|
||||||
|
res += alt (tritv_get(v, i)) {
|
||||||
|
case (dont_care) { "?" }
|
||||||
|
case (ttrue) { "1" }
|
||||||
|
case (tfalse) { "0" } };
|
||||||
|
i += 1u;
|
||||||
|
}
|
||||||
|
ret res;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Local Variables:
|
// Local Variables:
|
||||||
// mode: rust
|
// mode: rust
|
||||||
|
|
|
@ -116,7 +116,7 @@ fn buf_off[T](array[T] v, uint offset) -> vbuf {
|
||||||
|
|
||||||
fn print_debug_info[T](array[T] v) { rustrt::vec_print_debug_info[T](v); }
|
fn print_debug_info[T](array[T] v) { rustrt::vec_print_debug_info[T](v); }
|
||||||
|
|
||||||
|
// FIXME: typestate precondition (list is non-empty)
|
||||||
// Returns the last element of v.
|
// Returns the last element of v.
|
||||||
fn last[T](array[T] v) -> option::t[T] {
|
fn last[T](array[T] v) -> option::t[T] {
|
||||||
auto l = len[T](v);
|
auto l = len[T](v);
|
||||||
|
|
20
src/test/compile-fail/pred-assign.rs
Normal file
20
src/test/compile-fail/pred-assign.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// xfail-stage0
|
||||||
|
// -*- rust -*-
|
||||||
|
|
||||||
|
// error-pattern: Unsatisfied precondition constraint (for example, lt(a, b)
|
||||||
|
|
||||||
|
fn f(int a, int b) : lt(a,b) {
|
||||||
|
}
|
||||||
|
|
||||||
|
pred lt(int a, int b) -> bool {
|
||||||
|
ret a < b;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let int a = 10;
|
||||||
|
let int b = 23;
|
||||||
|
let int c = 77;
|
||||||
|
check lt(a,b);
|
||||||
|
a = 24;
|
||||||
|
f(a,b);
|
||||||
|
}
|
20
src/test/compile-fail/pred-swap.rs
Normal file
20
src/test/compile-fail/pred-swap.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// xfail-stage0
|
||||||
|
// -*- rust -*-
|
||||||
|
|
||||||
|
// error-pattern: Unsatisfied precondition constraint (for example, lt(a, b)
|
||||||
|
|
||||||
|
fn f(int a, int b) : lt(a,b) {
|
||||||
|
}
|
||||||
|
|
||||||
|
pred lt(int a, int b) -> bool {
|
||||||
|
ret a < b;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let int a = 10;
|
||||||
|
let int b = 23;
|
||||||
|
let int c = 77;
|
||||||
|
check lt(a,b);
|
||||||
|
b <-> a;
|
||||||
|
f(a,b);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue