In typestate, consider infinite loops w/ conts to be infinite

If a loop { } contains a cont, that doesn't affect whether the entire
loop diverges. Only breaks affect that. Fix that in typestate.
This commit is contained in:
Tim Chevalier 2012-03-10 20:34:57 -08:00
parent 35400e13ad
commit 205cefdc6e
2 changed files with 19 additions and 1 deletions

View file

@ -550,7 +550,9 @@ fn find_pre_post_state_expr(fcx: fn_ctxt, pres: prestate, e: @expr) -> bool {
/* conservative approximation: if a loop contains a break
or cont, we assume nothing about the poststate */
/* which is still unsound -- see [Break-unsound] */
if has_nonlocal_exits(body) {
if may_break(body) {
/* Only do this if there are *breaks* not conts.
An infinite loop with conts is still an infinite loop. */
ret changed | set_poststate_ann(fcx.ccx, e.id, pres);
} else {
ret changed | set_poststate_ann(fcx.ccx, e.id,

View file

@ -83,6 +83,22 @@ fn has_nonlocal_exits(b: ast::blk) -> bool {
ret *has_exits;
}
/* FIXME: copy/paste, yuck */
fn may_break(b: ast::blk) -> bool {
let has_exits = @mutable false;
fn visit_expr(flag: @mutable bool, e: @ast::expr) {
alt e.node {
ast::expr_break { *flag = true; }
_ { }
}
}
let v =
visit::mk_simple_visitor(@{visit_expr: bind visit_expr(has_exits, _)
with *visit::default_simple_visitor()});
visit::visit_block(b, (), v);
ret *has_exits;
}
fn local_rhs_span(l: @ast::local, def: span) -> span {
alt l.node.init { some(i) { ret i.expr.span; } _ { ret def; } }
}