Skip to content

Commit 1c786bc

Browse files
committed
Initialize all constraints to False
Previously, typestate was initializing the init constraint for a declared-but-not-initialized variable (like x in "let x;") to False, but other constraints to Don't-know. This led to over-lenient results when a variable was used before declaration (see the included test case). Now, everything gets initialized to False in the prestate/poststate- finding phase, and Don't-know should only be used in pre/postconditions. This aspect of the algorithm really needs formalization (just on paper), but for now, this closes #700
1 parent e76efbc commit 1c786bc

File tree

4 files changed

+41
-9
lines changed

4 files changed

+41
-9
lines changed

src/comp/middle/tstate/bitvectors.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,11 @@ fn kill_prestate(fcx: &fn_ctxt, id: node_id, c: &tsconstr) -> bool {
183183
node_id_to_ts_ann(fcx.ccx, id).states);
184184
}
185185

186+
fn kill_all_prestate(fcx: &fn_ctxt, id: node_id) {
187+
tritv::tritv_kill(node_id_to_ts_ann(fcx.ccx, id).states.prestate);
188+
}
189+
190+
186191
fn kill_poststate(fcx: &fn_ctxt, id: node_id, c: &tsconstr) -> bool {
187192
log "kill_poststate";
188193
ret clear_in_poststate(bit_num(fcx, c),

src/comp/middle/tstate/states.rs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,7 @@ fn find_pre_post_state_stmt(fcx: &fn_ctxt, pres: &prestate, s: @stmt)
594594
-> bool {
595595
let stmt_ann = stmt_to_ann(fcx.ccx, *s);
596596
/*
597+
log_err ("[" + fcx.name + "]");
597598
log_err "*At beginning: stmt = ";
598599
log_stmt_err(*s);
599600
log_err "*prestate = ";
@@ -617,7 +618,8 @@ fn find_pre_post_state_stmt(fcx: &fn_ctxt, pres: &prestate, s: @stmt)
617618

618619
let changed = (set_poststate(stmt_ann, c_and_p.post)
619620
| c_and_p.changed);
620-
/*
621+
622+
/*
621623
log_err "Summary: stmt = ";
622624
log_stmt_err(*s);
623625
log_err "prestate = ";
@@ -638,11 +640,12 @@ fn find_pre_post_state_stmt(fcx: &fn_ctxt, pres: &prestate, s: @stmt)
638640
}
639641
}
640642
stmt_expr(ex, _) {
641-
ret find_pre_post_state_expr(fcx, pres, ex) |
643+
let changed = find_pre_post_state_expr(fcx, pres, ex) |
642644
set_prestate(stmt_ann, expr_prestate(fcx.ccx, ex)) |
643645
set_poststate(stmt_ann, expr_poststate(fcx.ccx, ex));
644-
/*
645-
log_err "Finally:";
646+
647+
/*
648+
log_err "Finally:";
646649
log_stmt_err(*s);
647650
log_err("prestate = ");
648651
// log_err(bitv::to_str(stmt_ann.states.prestate));
@@ -651,8 +654,9 @@ fn find_pre_post_state_stmt(fcx: &fn_ctxt, pres: &prestate, s: @stmt)
651654
// log_err(bitv::to_str(stmt_ann.states.poststate));
652655
log_tritv_err(fcx, stmt_ann.states.poststate);
653656
log_err("changed =");
654-
log_err(changed);
655-
*/
657+
*/
658+
659+
ret changed;
656660
}
657661
_ { ret false; }
658662
}
@@ -707,9 +711,9 @@ fn find_pre_post_state_block(fcx: &fn_ctxt, pres0: &prestate, b: &blk) ->
707711
fn find_pre_post_state_fn(fcx: &fn_ctxt, f: &_fn) -> bool {
708712

709713
let num_constrs = num_constraints(fcx.enclosing);
710-
// make sure the return and diverge bits start out False
711-
kill_prestate(fcx, f.body.node.id, fcx.enclosing.i_return);
712-
kill_prestate(fcx, f.body.node.id, fcx.enclosing.i_diverge);
714+
// All constraints are considered false until proven otherwise.
715+
// This ensures that intersect works correctly.
716+
kill_all_prestate(fcx, f.body.node.id);
713717

714718
// Instantiate any constraints on the arguments so we can use them
715719
let block_pre = block_prestate(fcx.ccx, f.body);

src/comp/middle/tstate/tritv.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export tritv_union;
1616
export tritv_intersect;
1717
export tritv_copy;
1818
export tritv_clear;
19+
export tritv_kill;
1920
export tritv_doesntcare;
2021
export to_str;
2122

@@ -218,6 +219,11 @@ fn tritv_clear(v: &t) {
218219
while i < v.nbits { tritv_set(i, v, dont_care); i += 1u; }
219220
}
220221

222+
fn tritv_kill(v: &t) {
223+
let i: uint = 0u;
224+
while i < v.nbits { tritv_set(i, v, tfalse); i += 1u; }
225+
}
226+
221227
fn tritv_clone(v: &t) -> t {
222228
ret {uncertain: bitv::clone(v.uncertain),
223229
val: bitv::clone(v.val),

src/test/compile-fail/alt-join.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// error-pattern:Unsatisfied precondition constraint
2+
// a good test that we merge paths correctly in the presence of a
3+
// variable that's used before it's declared
4+
// should be rejected by typestate because we use x without initializing it
5+
6+
fn my_fail() -> ! { fail; }
7+
8+
fn main() {
9+
10+
alt (true) {
11+
false { my_fail(); }
12+
true {}
13+
}
14+
15+
log x;
16+
let x:int;
17+
}

0 commit comments

Comments
 (0)