Compute typestates for FRU exprs correctly, plus a bit of cleanup

The code in Issue 948 was causing typestate to diverge because
it was using the prestate for the whole expression -- not the post-
state for the fields list -- as the prestate for the record base
expression. Fixed.

Closes #948
This commit is contained in:
Tim Chevalier 2012-01-19 17:22:41 -08:00
parent b58f2b7bfb
commit c7592803d9
2 changed files with 41 additions and 50 deletions

View file

@ -10,7 +10,7 @@ import syntax::ast::*;
import syntax::ast_util::*; import syntax::ast_util::*;
import syntax::codemap::span; import syntax::codemap::span;
import middle::ty::{expr_ty, type_is_bot}; import middle::ty::{expr_ty, type_is_bot};
import util::common::{field_exprs, has_nonlocal_exits}; import util::common::*;
import driver::session::session; import driver::session::session;
fn forbid_upvar(fcx: fn_ctxt, rhs_id: node_id, sp: span, t: oper_type) { fn forbid_upvar(fcx: fn_ctxt, rhs_id: node_id, sp: span, t: oper_type) {
@ -384,20 +384,19 @@ fn find_pre_post_state_expr(fcx: fn_ctxt, pres: prestate, e: @expr) -> bool {
set_poststate_ann(fcx.ccx, e.id, block_poststate(fcx.ccx, b)); set_poststate_ann(fcx.ccx, e.id, block_poststate(fcx.ccx, b));
} }
expr_rec(fields, maybe_base) { expr_rec(fields, maybe_base) {
let exs = field_exprs(fields);
let changed = let changed =
find_pre_post_state_exprs(fcx, pres, e.id, find_pre_post_state_exprs(fcx, pres, e.id,
vec::init_elt(init_assign, vec::init_elt(init_assign,
vec::len(fields)), vec::len(fields)),
field_exprs(fields), return_val); exs, return_val);
alt maybe_base {
none {/* do nothing */ } let base_pres = alt vec::last(exs) { none { pres }
some(base) { some(f) { expr_poststate(fcx.ccx, f) }};
changed |= option::may(maybe_base, {|base|
find_pre_post_state_expr(fcx, pres, base) | changed |= find_pre_post_state_expr(fcx, base_pres, base) |
set_poststate_ann(fcx.ccx, e.id, set_poststate_ann(fcx.ccx, e.id,
expr_poststate(fcx.ccx, base)); expr_poststate(fcx.ccx, base))});
}
}
ret changed; ret changed;
} }
expr_tup(elts) { expr_tup(elts) {
@ -591,12 +590,8 @@ fn find_pre_post_state_expr(fcx: fn_ctxt, pres: prestate, e: @expr) -> bool {
} }
ret set_prestate_ann(fcx.ccx, e.id, pres) | ret set_prestate_ann(fcx.ccx, e.id, pres) |
set_poststate_ann(fcx.ccx, e.id, post) | set_poststate_ann(fcx.ccx, e.id, post) |
alt maybe_fail_val { option::maybe(false, maybe_fail_val, {|fail_val|
none { false } find_pre_post_state_expr(fcx, pres, fail_val)});
some(fail_val) {
find_pre_post_state_expr(fcx, pres, fail_val)
}
}
} }
expr_assert(p) { expr_assert(p) {
ret find_pre_post_state_sub(fcx, pres, p, e.id, none); ret find_pre_post_state_sub(fcx, pres, p, e.id, none);
@ -617,18 +612,14 @@ fn find_pre_post_state_expr(fcx: fn_ctxt, pres: prestate, e: @expr) -> bool {
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); let stmt_ann = stmt_to_ann(fcx.ccx, *s);
/* log(debug, "[" + fcx.name + "]");
log(error, ("[" + fcx.name + "]")); #debug("*At beginning: stmt = ");
#error("*At beginning: stmt = "); log_stmt(*s);
log_stmt_err(*s); #debug("*prestate = ");
#error("*prestate = "); log(debug, tritv::to_str(stmt_ann.states.prestate));
log_tritv_err(fcx, stmt_ann.states.prestate); #debug("*poststate =");
#error("*poststate ="); log(debug, tritv::to_str(stmt_ann.states.prestate));
log_tritv_err(fcx, stmt_ann.states.poststate);
#error("pres = ");
log_tritv_err(fcx, pres);
*/
alt s.node { alt s.node {
stmt_decl(adecl, id) { stmt_decl(adecl, id) {
alt adecl.node { alt adecl.node {
@ -643,16 +634,14 @@ fn find_pre_post_state_stmt(fcx: fn_ctxt, pres: prestate, s: @stmt) -> bool {
let changed = let changed =
set_poststate(stmt_ann, c_and_p.post) | c_and_p.changed; set_poststate(stmt_ann, c_and_p.post) | c_and_p.changed;
/* #debug("Summary: stmt = ");
#error("Summary: stmt = "); log_stmt(*s);
log_stmt_err(*s); #debug("prestate = ");
#error("prestate = "); log(debug, tritv::to_str(stmt_ann.states.prestate));
log_tritv_err(fcx, stmt_ann.states.prestate); #debug("poststate =");
#error("poststate ="); log(debug, tritv::to_str(stmt_ann.states.prestate));
log_tritv_err(fcx, stmt_ann.states.poststate); #debug("changed =");
#error("changed ="); log(debug, changed);
log(error, changed);
*/
ret changed; ret changed;
} }
@ -668,17 +657,14 @@ fn find_pre_post_state_stmt(fcx: fn_ctxt, pres: prestate, s: @stmt) -> bool {
set_prestate(stmt_ann, expr_prestate(fcx.ccx, ex)) | set_prestate(stmt_ann, expr_prestate(fcx.ccx, ex)) |
set_poststate(stmt_ann, expr_poststate(fcx.ccx, ex)); set_poststate(stmt_ann, expr_poststate(fcx.ccx, ex));
/*
#error("Finally:"); #debug("Finally:");
log_stmt_err(*s); log_stmt(*s);
log_err("prestate = "); log(debug, "prestate = ");
log_err(bitv::to_str(stmt_ann.states.prestate)); log(debug, tritv::to_str(stmt_ann.states.prestate));
log_tritv_err(fcx, stmt_ann.states.prestate); #debug("poststate =");
log_err("poststate ="); log(debug, (tritv::to_str(stmt_ann.states.poststate)));
log_err(bitv::to_str(stmt_ann.states.poststate)); #debug("changed =");
log_tritv_err(fcx, stmt_ann.states.poststate);
log_err("changed =");
*/
ret changed; ret changed;
} }

View file

@ -0,0 +1,5 @@
// error-pattern:beep boop
fn main() {
let origin = {x: 0, y: 0};
let f = {x: (fail "beep boop") with origin};
}