From 126cd44c38404f51cc3c42e9dfde771c527bdbd6 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Fri, 29 Jul 2011 15:59:38 -0700 Subject: [PATCH] Refactor typestate code involving stmt_decls To handle multiple-LHS declarations with initializers properly, I changed seq_states to take a list of expressions paired with optional names, not just a list of expressions. Then, the same logic that handles ordered lists of subexpressions everywhere else can handle multi- declarations. --- src/comp/middle/tstate/auxiliary.rs | 21 +++ src/comp/middle/tstate/bitvectors.rs | 10 ++ src/comp/middle/tstate/states.rs | 188 ++++++++++++++------------- 3 files changed, 127 insertions(+), 92 deletions(-) diff --git a/src/comp/middle/tstate/auxiliary.rs b/src/comp/middle/tstate/auxiliary.rs index 1a8119a1786e..1d78750cc099 100644 --- a/src/comp/middle/tstate/auxiliary.rs +++ b/src/comp/middle/tstate/auxiliary.rs @@ -1037,6 +1037,27 @@ fn ast_constr_to_sp_constr(tcx: &ty::ctxt, args: &arg[], c: &@constr) -> ret respan(c.span, tconstr); } +type binding = {lhs: option::t[inst], rhs: option::t[initializer]}; + +fn local_to_binding(loc : &@local) -> binding { + {lhs: some({ident: loc.node.ident, node: loc.node.id}), + rhs: loc.node.init} +} + +fn locals_to_bindings(locals : &(@local)[]) -> binding[] { + ivec::map(local_to_binding, locals) +} + +fn anon_bindings(es : &(@expr)[]) -> binding[] { + fn expr_to_initializer(e : &@expr) -> initializer { + {op: init_assign, expr: e} + } + ret ivec::map(fn (e : &@expr) -> binding { + {lhs: none, + rhs: some(expr_to_initializer(e)) } }, + es); +} + // // Local Variables: // mode: rust diff --git a/src/comp/middle/tstate/bitvectors.rs b/src/comp/middle/tstate/bitvectors.rs index d125427776a0..e38f39b8a2c1 100644 --- a/src/comp/middle/tstate/bitvectors.rs +++ b/src/comp/middle/tstate/bitvectors.rs @@ -208,6 +208,11 @@ fn clear_in_poststate_expr(fcx: &fn_ctxt, e: &@expr, t: &poststate) { } } +fn kill_poststate_(fcx : &fn_ctxt, c : &tsconstr, post : &poststate) -> bool { + log "kill_poststate_"; + ret clear_in_poststate_(bit_num(fcx, c), post); +} + fn set_in_poststate_ident(fcx: &fn_ctxt, id: &node_id, ident: &ident, t: &poststate) -> bool { ret set_in_poststate_(bit_num(fcx, ninit(id, ident)), t); @@ -227,6 +232,11 @@ fn clear_in_prestate_ident(fcx: &fn_ctxt, id: &node_id, ident: &ident, ret kill_prestate(fcx, parent, ninit(id, ident)); } +fn clear_in_poststate_ident_(fcx : &fn_ctxt, id : &node_id, ident : &ident, + post : &poststate) -> bool { + ret kill_poststate_(fcx, ninit(id, ident), post); +} + // // Local Variables: // mode: rust diff --git a/src/comp/middle/tstate/states.rs b/src/comp/middle/tstate/states.rs index afa34478d958..0aebc7659d1d 100644 --- a/src/comp/middle/tstate/states.rs +++ b/src/comp/middle/tstate/states.rs @@ -27,16 +27,6 @@ import tritv::tritv_set; import tritv::ttrue; import bitvectors::*; -/* -import bitvectors::set_in_poststate_ident; -import bitvectors::clear_in_poststate_expr; -import bitvectors::clear_in_prestate_ident; -import bitvectors::bit_num; -import bitvectors::gen_poststate; -import bitvectors::kill_poststate; -import bitvectors::clear_in_poststate_ident; -import bitvectors::intersect_states; -*/ import syntax::ast::*; import middle::ty::expr_ty; import middle::ty::type_is_nil; @@ -53,15 +43,66 @@ import util::common::log_stmt; import util::common::log_stmt_err; import util::common::log_expr_err; -fn seq_states(fcx: &fn_ctxt, pres: prestate, exprs: &(@expr)[]) -> - {changed: bool, post: poststate} { +fn handle_move_or_copy(fcx: &fn_ctxt, post: &poststate, rhs_path: &path, + rhs_id: &node_id, instlhs: &inst, init_op: &init_op) { + let rhs_d = local_node_id_to_def_id(fcx, rhs_id); + alt (rhs_d) { + some(rhsid) { + // RHS is a local var + let instrhs = + {ident: path_to_ident(fcx.ccx.tcx, rhs_path), node: rhsid.node}; + copy_in_poststate(fcx, post, instlhs, instrhs, + op_to_oper_ty(init_op)); + } + _ { + // not a local -- do nothing + } + } + if (init_op == init_move) { + forget_in_poststate(fcx, post, rhs_id); + } +} + +fn seq_states(fcx: &fn_ctxt, pres: &prestate, bindings: &binding[]) + -> {changed: bool, post: poststate} { let changed = false; - let post = pres; - for e: @expr in exprs { - changed |= find_pre_post_state_expr(fcx, post, e) || changed; - // log_err("Seq_states: changed ="); - // log_err changed; - post = expr_poststate(fcx.ccx, e); + let post = tritv_clone(pres); + for b:binding in bindings { + alt (b.rhs) { + some(an_init) { + // an expression, with or without a destination + changed |= find_pre_post_state_expr(fcx, post, an_init.expr) + || changed; + post = tritv_clone(expr_poststate(fcx.ccx, an_init.expr)); + alt (b.lhs) { + some(i) { + alt (an_init.expr.node) { + expr_path(p) { + handle_move_or_copy(fcx, post, p, an_init.expr.id, i, + an_init.op); + } + _ {} + } + set_in_poststate_ident(fcx, i.node, i.ident, post); + } + _ { + //This is an expression that doesn't get named. + // So, nothing more to do. + } + } + } + none { + alt (b.lhs) { + some(i) { + // variable w/o an initializer + clear_in_poststate_ident_(fcx, i.node, i.ident, post); + } + none { fcx.ccx.tcx.sess.bug("seq_states: binding has \ + neither an lhs nor an rhs"); + } + } + } + } } ret {changed: changed, post: post}; } @@ -154,7 +195,7 @@ fn find_pre_post_state_call(fcx: &fn_ctxt, pres: &prestate, a: &@expr, fn find_pre_post_state_exprs(fcx: &fn_ctxt, pres: &prestate, id: node_id, es: &(@expr)[], cf: controlflow) -> bool { - let rs = seq_states(fcx, pres, es); + let rs = seq_states(fcx, pres, anon_bindings(es)); let changed = rs.changed | set_prestate_ann(fcx.ccx, id, pres); /* if this is a failing call, it sets everything as initialized */ alt cf { @@ -561,91 +602,50 @@ fn find_pre_post_state_expr(fcx: &fn_ctxt, pres: &prestate, e: @expr) -> } } -fn find_pre_post_state_stmt(fcx: &fn_ctxt, pres: &prestate, s: @stmt) -> - bool { +fn find_pre_post_state_stmt(fcx: &fn_ctxt, pres: &prestate, s: @stmt) + -> bool { let stmt_ann = stmt_to_ann(fcx.ccx, *s); - - - /* +/* log_err "*At beginning: stmt = "; log_stmt_err(*s); log_err "*prestate = "; - log_err tritv::to_str(stmt_ann.states.prestate); + log_tritv_err(fcx, stmt_ann.states.prestate); log_err "*poststate ="; - log_err tritv::to_str(stmt_ann.states.poststate); + log_tritv_err(fcx, stmt_ann.states.poststate); log_err "pres = "; - log_err tritv::to_str(pres); - */ + log_tritv_err(fcx, pres); +*/ - alt s.node { + alt (s.node) { stmt_decl(adecl, id) { - alt adecl.node { + alt (adecl.node) { decl_local(alocals) { - let changed = false; - for alocal: @local in alocals { - alt alocal.node.init { - some(an_init) { - let changed = - set_prestate(stmt_ann, pres) | - find_pre_post_state_expr(fcx, pres, an_init.expr); + set_prestate(stmt_ann, pres); + let c_and_p = seq_states(fcx, pres, + locals_to_bindings(alocals)); + /* important to do this in one step to ensure + termination (don't want to set changed to true + for intermediate changes) */ - let post = - tritv_clone(expr_poststate(fcx.ccx, an_init.expr)); - alt an_init.expr.node { - expr_path(p) { + let changed = (set_poststate(stmt_ann, c_and_p.post) + | c_and_p.changed); + /* + log_err "Summary: stmt = "; + log_stmt_err(*s); + log_err "prestate = "; + log_tritv_err(fcx, stmt_ann.states.prestate); + log_err "poststate ="; + log_tritv_err(fcx, stmt_ann.states.poststate); + log_err "changed ="; + log_err changed; +*/ - let instlhs = - {ident: alocal.node.ident, node: alocal.node.id}; - let rhs_d = - local_node_id_to_local_def_id(fcx, - an_init.expr.id); - alt rhs_d { - some(rhsid) { - let instrhs = - {ident: path_to_ident(fcx.ccx.tcx, p), - node: rhsid}; - copy_in_poststate(fcx, post, instlhs, instrhs, - op_to_oper_ty(an_init.op)); - } - _ { } - } - } - _ { } - } - if an_init.op == init_move { - forget_in_poststate(fcx, post, an_init.expr.id); - } - set_in_poststate_ident(fcx, alocal.node.id, - alocal.node.ident, post); - /* - log_err "Summary: stmt = "; - log_stmt_err(*s); - log_err "prestate = "; - log_tritv_err(fcx, stmt_ann.states.prestate); - log_err "poststate ="; - log_tritv_err(fcx, post); - log_err "changed ="; - log_err changed; - */ - /* 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); - } - none. { - // let int = x; => x is uninit in poststate - set_poststate_ann(fcx.ccx, id, pres); - clear_in_poststate_ident(fcx, alocal.node.id, - alocal.node.ident, id); - set_prestate(stmt_ann, pres); - } - } - } ret changed; } decl_item(an_item) { - ret set_prestate(stmt_ann, pres) | set_poststate(stmt_ann, pres); - /* the outer "walk" will recurse into the item */ + ret set_prestate(stmt_ann, pres) | + set_poststate(stmt_ann, pres); + /* the outer visitor will recurse into the item */ } } } @@ -699,7 +699,8 @@ fn find_pre_post_state_block(fcx: &fn_ctxt, pres0: &prestate, b: &blk) -> set_prestate_ann(fcx.ccx, b.node.id, pres0); set_poststate_ann(fcx.ccx, b.node.id, post); - /* + +/* log_err "For block:"; log_block_err(b); log_err "poststate = "; @@ -708,12 +709,15 @@ fn find_pre_post_state_block(fcx: &fn_ctxt, pres0: &prestate, b: &blk) -> log_tritv_err(fcx, pres0); log_err "post:"; log_tritv_err(fcx, post); - */ + log_err "changed = "; + log_err changed; +*/ ret changed; } fn find_pre_post_state_fn(fcx: &fn_ctxt, f: &_fn) -> bool { + let num_local_vars = num_constraints(fcx.enclosing); // make sure the return bit starts out False clear_in_prestate_ident(fcx, fcx.id, fcx.name, f.body.node.id);