Start to check expr_check and expr_call constraints in typestate

Start writing the cases for expr_check and expr_call to take
predicates into account, but this isn't working yet.
This commit is contained in:
Tim Chevalier 2011-06-09 09:56:35 -07:00
parent 17ff2a0d79
commit b34a97de39
4 changed files with 61 additions and 3 deletions

View file

@ -89,6 +89,11 @@ fn pps_len(&pre_and_post p) -> uint {
ret p.precondition.nbits;
}
fn require(uint i, &pre_and_post p) -> () {
// sets the ith bit in p's pre
bitv::set(p.precondition, i, true);
}
fn require_and_preserve(uint i, &pre_and_post p) -> () {
// sets the ith bit in p's pre and post
bitv::set(p.precondition, i, true);

View file

@ -144,7 +144,6 @@ fn intersect_postconds(&vec[postcond] pcs) -> postcond {
}
fn gen(&fn_ctxt fcx, &ann a, &def_id id, &constr_occ o) -> bool {
log "gen";
ret set_in_postcond(bit_num(fcx, id, o),
(ann_to_ts_ann(fcx.ccx, a)).conditions);
}

View file

@ -4,12 +4,15 @@ import std::option;
import std::option::none;
import std::option::some;
// FIXME: needs to be tstate::ann because ann is also a type name...
// that's probably a bug.
import tstate::ann::pre_and_post;
import tstate::ann::get_post;
import tstate::ann::postcond;
import tstate::ann::true_precond;
import tstate::ann::false_postcond;
import tstate::ann::empty_poststate;
import tstate::ann::require;
import tstate::ann::require_and_preserve;
import tstate::ann::union;
import tstate::ann::intersect;
@ -22,6 +25,7 @@ import aux::fn_ctxt;
import aux::occ_init;
import aux::num_constraints;
import aux::constraint;
import aux::constr_occ;
import aux::expr_pp;
import aux::stmt_pp;
import aux::block_pp;
@ -41,6 +45,11 @@ import aux::ann_to_def_strict;
import aux::ann_to_ts_ann;
import aux::set_postcond_false;
import aux::controlflow_expr;
import aux::expr_to_constr;
import aux::constraint_info;
import aux::constr_to_constr_occ;
import aux::constraints_expr;
import aux::substitute_constr_args;
import bitvectors::seq_preconds;
import bitvectors::union_postconds;
@ -52,6 +61,7 @@ import bitvectors::gen;
import front::ast::*;
import middle::ty::expr_ann;
import middle::ty::lookup_fn_decl;
import util::common::new_def_hash;
import util::common::decl_lhs;
@ -210,6 +220,38 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) -> () {
auto args = vec::clone[@expr](operands);
vec::push[@expr](args, operator);
find_pre_post_exprs(fcx, args, a);
/* see if the call has any constraints on its in type */
let option::t[tup(fn_decl, def_id)] decl_and_id =
lookup_fn_decl(fcx.ccx.tcx, expr_ann(operator));
alt (decl_and_id) {
case (some(?p)) {
log("known function: " );
log_expr(*operator);
let def_id f_id = p._1;
let fn_decl f_decl = p._0;
auto pp = expr_pp(fcx.ccx, e);
for (@constr c in constraints_expr(fcx.ccx, operator)) {
auto i = bit_num(fcx, f_id,
substitute_constr_args(fcx.ccx.tcx, operands,
f_decl.inputs, c));
require(i, pp);
}
}
// FIXME: Soundness? If a function is constrained...
// shouldn't be able to pass it as an argument
// But typechecking guarantees that. However, we could
// have an unknown function w/ a constrained type =>
// no decl... but need to know the argument names.
// Fix that and then make a test w/ a higher-order
// constrained function.
case (_) {
log("unknown function: " );
log_expr(*operator);
/* unknown function -- do nothing */ }
}
// FIXME: constraints on result type
/* if this is a failing call, its postcondition sets everything */
alt (controlflow_expr(fcx.ccx, operator)) {
case (noreturn) {
@ -471,9 +513,14 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) -> () {
copy_pre_post(fcx.ccx, a, p);
}
case (expr_check(?p, ?a)) {
/* will need to change when we support arbitrary predicates... */
/* FIXME: Can we bypass this by having a
node-id-to-constr_occ table? */
find_pre_post_expr(fcx, p);
copy_pre_post(fcx.ccx, a, p);
/* predicate p holds after this expression executes */
let constraint_info c = expr_to_constr(fcx.ccx.tcx, p);
let constr_occ o = constr_to_constr_occ(fcx.ccx.tcx, c.c.node);
gen(fcx, a, c.id, o);
}
case(expr_bind(?operator, ?maybe_args, ?a)) {
auto args = vec::cat_options[@expr](maybe_args);

View file

@ -49,6 +49,10 @@ import aux::block_states;
import aux::controlflow_expr;
import aux::ann_to_def;
import aux::occ_init;
import aux::expr_to_constr;
import aux::constraint_info;
import aux::constr_to_constr_occ;
import aux::constr_occ;
import bitvectors::seq_preconds;
import bitvectors::union_postconds;
@ -521,8 +525,11 @@ fn find_pre_post_state_expr(&fn_ctxt fcx, &prestate pres, @expr e) -> bool {
case (expr_check(?p, ?a)) {
changed = extend_prestate_ann(fcx.ccx, a, pres) || changed;
changed = find_pre_post_state_expr(fcx, pres, p) || changed;
/* FIXME: update the postcondition to reflect that p holds */
changed = extend_poststate_ann(fcx.ccx, a, pres) || changed;
/* predicate p holds after this expression executes */
let constraint_info c = expr_to_constr(fcx.ccx.tcx, p);
let constr_occ o = constr_to_constr_occ(fcx.ccx.tcx, c.c.node);
changed = gen_poststate(fcx, a, c.id, o) || changed;
ret changed;
}
case (expr_break(?a)) {