2011-06-15 13:19:50 -05:00
|
|
|
|
2011-05-12 10:24:54 -05:00
|
|
|
import std::map;
|
|
|
|
import std::map::hashmap;
|
2011-05-17 13:41:41 -05:00
|
|
|
import std::uint;
|
|
|
|
import std::int;
|
|
|
|
import std::vec;
|
2011-06-26 21:18:30 -05:00
|
|
|
import std::option;
|
2011-05-12 10:24:54 -05:00
|
|
|
import std::option::none;
|
2011-05-18 17:38:38 -05:00
|
|
|
import std::option::some;
|
2011-07-05 04:48:19 -05:00
|
|
|
import syntax::ast;
|
|
|
|
import ast::ty;
|
|
|
|
import ast::pat;
|
|
|
|
import syntax::codemap::codemap;
|
|
|
|
import syntax::codemap::span;
|
|
|
|
import ast::lit;
|
|
|
|
import ast::path;
|
|
|
|
import syntax::walk;
|
2011-05-12 10:24:54 -05:00
|
|
|
import std::io::stdout;
|
|
|
|
import std::io::str_writer;
|
|
|
|
import std::io::string_writer;
|
2011-07-05 04:48:19 -05:00
|
|
|
import syntax::print;
|
|
|
|
import print::pprust::print_block;
|
|
|
|
import print::pprust::print_item;
|
|
|
|
import print::pprust::print_expr;
|
|
|
|
import print::pprust::print_path;
|
|
|
|
import print::pprust::print_decl;
|
|
|
|
import print::pprust::print_fn;
|
|
|
|
import print::pprust::print_type;
|
|
|
|
import print::pprust::print_literal;
|
|
|
|
import print::pp::mk_printer;
|
2011-06-15 13:19:50 -05:00
|
|
|
|
Support all expression forms in typestate
Added support for self_method, cont, chan, port, recv, send, be,
do_while, spawn, and ext; handled break and cont correctly.
(However, there are no non-xfailed test cases for ext or spawn in
stage0 currently.)
Although the standard library compiles and all test cases pass with
typestate enabled, I left typestate checking disabled as rustc
terminates abnormally when building the standard library if so,
even though it does generate code correctly.
2011-04-21 19:39:04 -05:00
|
|
|
type flag = hashmap[str, ()];
|
2010-08-18 13:34:47 -05:00
|
|
|
|
2011-05-12 10:24:54 -05:00
|
|
|
fn def_eq(&ast::def_id a, &ast::def_id b) -> bool {
|
2011-03-08 13:59:38 -06:00
|
|
|
ret a._0 == b._0 && a._1 == b._1;
|
|
|
|
}
|
|
|
|
|
2011-05-12 10:24:54 -05:00
|
|
|
fn hash_def(&ast::def_id d) -> uint {
|
2011-03-31 13:55:28 -05:00
|
|
|
auto h = 5381u;
|
2011-06-15 13:19:50 -05:00
|
|
|
h = (h << 5u) + h ^ (d._0 as uint);
|
|
|
|
h = (h << 5u) + h ^ (d._1 as uint);
|
2011-03-31 13:55:28 -05:00
|
|
|
ret h;
|
|
|
|
}
|
2010-10-19 16:54:10 -05:00
|
|
|
|
2011-06-15 13:19:50 -05:00
|
|
|
fn new_def_hash[V]() -> std::map::hashmap[ast::def_id, V] {
|
2011-05-12 10:24:54 -05:00
|
|
|
let std::map::hashfn[ast::def_id] hasher = hash_def;
|
|
|
|
let std::map::eqfn[ast::def_id] eqer = def_eq;
|
2011-06-15 13:19:50 -05:00
|
|
|
ret std::map::mk_hashmap[ast::def_id, V](hasher, eqer);
|
2010-10-19 16:54:10 -05:00
|
|
|
}
|
|
|
|
|
2011-05-12 10:24:54 -05:00
|
|
|
fn elt_expr(&ast::elt e) -> @ast::expr { ret e.expr; }
|
2011-04-07 20:15:56 -05:00
|
|
|
|
2011-05-12 10:24:54 -05:00
|
|
|
fn elt_exprs(&vec[ast::elt] elts) -> vec[@ast::expr] {
|
2011-04-07 20:15:56 -05:00
|
|
|
auto f = elt_expr;
|
2011-05-17 13:41:41 -05:00
|
|
|
ret vec::map[ast::elt, @ast::expr](f, elts);
|
2011-04-07 20:15:56 -05:00
|
|
|
}
|
|
|
|
|
2011-05-30 17:56:01 -05:00
|
|
|
fn field_expr(&ast::field f) -> @ast::expr { ret f.node.expr; }
|
2011-04-12 14:16:21 -05:00
|
|
|
|
2011-06-15 13:19:50 -05:00
|
|
|
fn field_exprs(vec[ast::field] fields) -> vec[@ast::expr] {
|
2011-04-12 14:16:21 -05:00
|
|
|
auto f = field_expr;
|
2011-05-17 13:41:41 -05:00
|
|
|
ret vec::map[ast::field, @ast::expr](f, fields);
|
2011-04-12 14:16:21 -05:00
|
|
|
}
|
|
|
|
|
2011-07-05 04:48:19 -05:00
|
|
|
fn log_expr(&ast::expr e) { log print::pprust::expr_to_str(@e); }
|
Further work on typestate_check
Lots of work on typestate_check, seems to get a lot of the way
through checking the standard library.
* Added for, for_each, assign_op, bind, cast, put, check, break,
and cont. (I'm not sure break and cont are actually handled correctly.)
* Fixed side-effect bug in seq_preconds so that unioning the
preconditions of a sequence of statements or expressions
is handled correctly.
* Pass poststate correctly through a stmt_decl.
* Handle expr_ret and expr_fail properly (after execution of a ret
or fail, everything is true -- this is needed to handle ifs and alts
where one branch is a ret or fail)
* Fixed bug in set_prestate_ann where a thing that needed to be
mutated wasn't getting passed as an alias
* Fixed bug in how expr_alt was treated (zero is not the identity
for intersect, who knew, right?)
* Update logging to reflect log_err vs. log
* Fixed find_locals so as to return all local decls and exclude
function arguments.
* Make union_postconds work on an empty vector (needed to handle
empty blocks correctly)
* Added _vec.cat_options, which takes a list of option[T] to a list
of T, ignoring any Nones
* Added two test cases.
2011-04-20 14:11:01 -05:00
|
|
|
|
2011-07-05 04:48:19 -05:00
|
|
|
fn log_expr_err(&ast::expr e) { log_err print::pprust::expr_to_str(@e); }
|
Further work on typestate_check
Lots of work on typestate_check, seems to get a lot of the way
through checking the standard library.
* Added for, for_each, assign_op, bind, cast, put, check, break,
and cont. (I'm not sure break and cont are actually handled correctly.)
* Fixed side-effect bug in seq_preconds so that unioning the
preconditions of a sequence of statements or expressions
is handled correctly.
* Pass poststate correctly through a stmt_decl.
* Handle expr_ret and expr_fail properly (after execution of a ret
or fail, everything is true -- this is needed to handle ifs and alts
where one branch is a ret or fail)
* Fixed bug in set_prestate_ann where a thing that needed to be
mutated wasn't getting passed as an alias
* Fixed bug in how expr_alt was treated (zero is not the identity
for intersect, who knew, right?)
* Update logging to reflect log_err vs. log
* Fixed find_locals so as to return all local decls and exclude
function arguments.
* Make union_postconds work on an empty vector (needed to handle
empty blocks correctly)
* Added _vec.cat_options, which takes a list of option[T] to a list
of T, ignoring any Nones
* Added two test cases.
2011-04-20 14:11:01 -05:00
|
|
|
|
2011-07-05 04:48:19 -05:00
|
|
|
fn log_ty_err(&ty t) { log_err print::pprust::ty_to_str(t); }
|
2011-05-14 21:02:30 -05:00
|
|
|
|
2011-07-05 04:48:19 -05:00
|
|
|
fn log_pat_err(&@pat p) { log_err print::pprust::pat_to_str(p); }
|
2011-05-14 21:02:30 -05:00
|
|
|
|
2011-07-05 04:48:19 -05:00
|
|
|
fn log_block(&ast::block b) { log print::pprust::block_to_str(b); }
|
Further work on typestate_check
Lots of work on typestate_check, seems to get a lot of the way
through checking the standard library.
* Added for, for_each, assign_op, bind, cast, put, check, break,
and cont. (I'm not sure break and cont are actually handled correctly.)
* Fixed side-effect bug in seq_preconds so that unioning the
preconditions of a sequence of statements or expressions
is handled correctly.
* Pass poststate correctly through a stmt_decl.
* Handle expr_ret and expr_fail properly (after execution of a ret
or fail, everything is true -- this is needed to handle ifs and alts
where one branch is a ret or fail)
* Fixed bug in set_prestate_ann where a thing that needed to be
mutated wasn't getting passed as an alias
* Fixed bug in how expr_alt was treated (zero is not the identity
for intersect, who knew, right?)
* Update logging to reflect log_err vs. log
* Fixed find_locals so as to return all local decls and exclude
function arguments.
* Make union_postconds work on an empty vector (needed to handle
empty blocks correctly)
* Added _vec.cat_options, which takes a list of option[T] to a list
of T, ignoring any Nones
* Added two test cases.
2011-04-20 14:11:01 -05:00
|
|
|
|
2011-07-05 04:48:19 -05:00
|
|
|
fn log_block_err(&ast::block b) { log_err print::pprust::block_to_str(b); }
|
2011-04-12 14:16:21 -05:00
|
|
|
|
2011-07-05 04:48:19 -05:00
|
|
|
fn log_item_err(&@ast::item i) { log_err print::pprust::item_to_str(i); }
|
2011-04-22 13:08:47 -05:00
|
|
|
|
2011-06-15 13:19:50 -05:00
|
|
|
fn log_fn(&ast::_fn f, str name, vec[ast::ty_param] params) {
|
2011-07-05 04:48:19 -05:00
|
|
|
log print::pprust::fun_to_str(f, name, params);
|
2011-04-22 13:08:47 -05:00
|
|
|
}
|
|
|
|
|
2011-06-15 13:19:50 -05:00
|
|
|
fn log_fn_err(&ast::_fn f, str name, vec[ast::ty_param] params) {
|
2011-07-05 04:48:19 -05:00
|
|
|
log_err print::pprust::fun_to_str(f, name, params);
|
Further work on typestate_check
Lots of work on typestate_check, seems to get a lot of the way
through checking the standard library.
* Added for, for_each, assign_op, bind, cast, put, check, break,
and cont. (I'm not sure break and cont are actually handled correctly.)
* Fixed side-effect bug in seq_preconds so that unioning the
preconditions of a sequence of statements or expressions
is handled correctly.
* Pass poststate correctly through a stmt_decl.
* Handle expr_ret and expr_fail properly (after execution of a ret
or fail, everything is true -- this is needed to handle ifs and alts
where one branch is a ret or fail)
* Fixed bug in set_prestate_ann where a thing that needed to be
mutated wasn't getting passed as an alias
* Fixed bug in how expr_alt was treated (zero is not the identity
for intersect, who knew, right?)
* Update logging to reflect log_err vs. log
* Fixed find_locals so as to return all local decls and exclude
function arguments.
* Make union_postconds work on an empty vector (needed to handle
empty blocks correctly)
* Added _vec.cat_options, which takes a list of option[T] to a list
of T, ignoring any Nones
* Added two test cases.
2011-04-20 14:11:01 -05:00
|
|
|
}
|
|
|
|
|
2011-07-05 04:48:19 -05:00
|
|
|
fn log_stmt(&ast::stmt st) { log print::pprust::stmt_to_str(st); }
|
Further work on typestate_check
Lots of work on typestate_check, seems to get a lot of the way
through checking the standard library.
* Added for, for_each, assign_op, bind, cast, put, check, break,
and cont. (I'm not sure break and cont are actually handled correctly.)
* Fixed side-effect bug in seq_preconds so that unioning the
preconditions of a sequence of statements or expressions
is handled correctly.
* Pass poststate correctly through a stmt_decl.
* Handle expr_ret and expr_fail properly (after execution of a ret
or fail, everything is true -- this is needed to handle ifs and alts
where one branch is a ret or fail)
* Fixed bug in set_prestate_ann where a thing that needed to be
mutated wasn't getting passed as an alias
* Fixed bug in how expr_alt was treated (zero is not the identity
for intersect, who knew, right?)
* Update logging to reflect log_err vs. log
* Fixed find_locals so as to return all local decls and exclude
function arguments.
* Make union_postconds work on an empty vector (needed to handle
empty blocks correctly)
* Added _vec.cat_options, which takes a list of option[T] to a list
of T, ignoring any Nones
* Added two test cases.
2011-04-20 14:11:01 -05:00
|
|
|
|
2011-07-05 04:48:19 -05:00
|
|
|
fn log_stmt_err(&ast::stmt st) { log_err print::pprust::stmt_to_str(st); }
|
Further work on typestate_check
Lots of work on typestate_check, seems to get a lot of the way
through checking the standard library.
* Added for, for_each, assign_op, bind, cast, put, check, break,
and cont. (I'm not sure break and cont are actually handled correctly.)
* Fixed side-effect bug in seq_preconds so that unioning the
preconditions of a sequence of statements or expressions
is handled correctly.
* Pass poststate correctly through a stmt_decl.
* Handle expr_ret and expr_fail properly (after execution of a ret
or fail, everything is true -- this is needed to handle ifs and alts
where one branch is a ret or fail)
* Fixed bug in set_prestate_ann where a thing that needed to be
mutated wasn't getting passed as an alias
* Fixed bug in how expr_alt was treated (zero is not the identity
for intersect, who knew, right?)
* Update logging to reflect log_err vs. log
* Fixed find_locals so as to return all local decls and exclude
function arguments.
* Make union_postconds work on an empty vector (needed to handle
empty blocks correctly)
* Added _vec.cat_options, which takes a list of option[T] to a list
of T, ignoring any Nones
* Added two test cases.
2011-04-20 14:11:01 -05:00
|
|
|
|
2011-05-12 10:24:54 -05:00
|
|
|
fn has_nonlocal_exits(&ast::block b) -> bool {
|
2011-06-15 13:19:50 -05:00
|
|
|
auto has_exits = @mutable false;
|
|
|
|
fn visit_expr(@mutable bool flag, &@ast::expr e) {
|
|
|
|
alt (e.node) {
|
2011-06-21 15:16:40 -05:00
|
|
|
case (ast::expr_break) { *flag = true; }
|
|
|
|
case (ast::expr_cont) { *flag = true; }
|
2011-06-15 13:19:50 -05:00
|
|
|
case (_) { }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
auto v =
|
|
|
|
rec(visit_expr_pre=bind visit_expr(has_exits, _)
|
|
|
|
with walk::default_visitor());
|
2011-05-26 19:16:54 -05:00
|
|
|
walk::walk_block(v, b);
|
|
|
|
ret *has_exits;
|
Support all expression forms in typestate
Added support for self_method, cont, chan, port, recv, send, be,
do_while, spawn, and ext; handled break and cont correctly.
(However, there are no non-xfailed test cases for ext or spawn in
stage0 currently.)
Although the standard library compiles and all test cases pass with
typestate enabled, I left typestate checking disabled as rustc
terminates abnormally when building the standard library if so,
even though it does generate code correctly.
2011-04-21 19:39:04 -05:00
|
|
|
}
|
2011-05-14 21:02:30 -05:00
|
|
|
|
2011-06-16 17:58:25 -05:00
|
|
|
fn local_rhs_span(&@ast::local l, &span def) -> span {
|
|
|
|
alt (l.node.init) {
|
2011-05-30 23:39:19 -05:00
|
|
|
case (some(?i)) { ret i.expr.span; }
|
2011-05-18 17:38:38 -05:00
|
|
|
case (_) { ret def; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-01 20:10:10 -05:00
|
|
|
fn lit_eq(&@ast::lit l, &@ast::lit m) -> bool {
|
|
|
|
alt (l.node) {
|
2011-06-15 13:19:50 -05:00
|
|
|
case (ast::lit_str(?s, ?kind_s)) {
|
2011-06-01 20:10:10 -05:00
|
|
|
alt (m.node) {
|
2011-06-15 13:19:50 -05:00
|
|
|
case (ast::lit_str(?t, ?kind_t)) {
|
2011-06-09 19:11:21 -05:00
|
|
|
ret s == t && kind_s == kind_t;
|
|
|
|
}
|
2011-06-15 13:19:50 -05:00
|
|
|
case (_) { ret false; }
|
2011-06-01 20:10:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
case (ast::lit_char(?c)) {
|
|
|
|
alt (m.node) {
|
|
|
|
case (ast::lit_char(?d)) { ret c == d; }
|
2011-06-15 13:19:50 -05:00
|
|
|
case (_) { ret false; }
|
2011-06-01 20:10:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
case (ast::lit_int(?i)) {
|
|
|
|
alt (m.node) {
|
|
|
|
case (ast::lit_int(?j)) { ret i == j; }
|
2011-06-15 13:19:50 -05:00
|
|
|
case (_) { ret false; }
|
2011-06-01 20:10:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
case (ast::lit_uint(?i)) {
|
|
|
|
alt (m.node) {
|
|
|
|
case (ast::lit_uint(?j)) { ret i == j; }
|
2011-06-15 13:19:50 -05:00
|
|
|
case (_) { ret false; }
|
2011-06-01 20:10:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
case (ast::lit_mach_int(_, ?i)) {
|
|
|
|
alt (m.node) {
|
|
|
|
case (ast::lit_mach_int(_, ?j)) { ret i == j; }
|
2011-06-15 13:19:50 -05:00
|
|
|
case (_) { ret false; }
|
2011-06-01 20:10:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
case (ast::lit_float(?s)) {
|
|
|
|
alt (m.node) {
|
|
|
|
case (ast::lit_float(?t)) { ret s == t; }
|
2011-06-15 13:19:50 -05:00
|
|
|
case (_) { ret false; }
|
2011-06-01 20:10:10 -05:00
|
|
|
}
|
|
|
|
}
|
2011-06-15 13:19:50 -05:00
|
|
|
case (ast::lit_mach_float(_, ?s)) {
|
2011-06-01 20:10:10 -05:00
|
|
|
alt (m.node) {
|
2011-06-15 13:19:50 -05:00
|
|
|
case (ast::lit_mach_float(_, ?t)) { ret s == t; }
|
|
|
|
case (_) { ret false; }
|
2011-06-01 20:10:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
case (ast::lit_nil) {
|
|
|
|
alt (m.node) {
|
|
|
|
case (ast::lit_nil) { ret true; }
|
2011-06-15 13:19:50 -05:00
|
|
|
case (_) { ret false; }
|
2011-06-01 20:10:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
case (ast::lit_bool(?b)) {
|
|
|
|
alt (m.node) {
|
|
|
|
case (ast::lit_bool(?c)) { ret b == c; }
|
2011-06-15 13:19:50 -05:00
|
|
|
case (_) { ret false; }
|
2011-06-01 20:10:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Compute typestate properly for move
typestate now drops constraints correctly in the post-state of
a move expression or a declaration whose op is a move. It doesn't
yet drop constraints mentioning variables that get updated.
To do this, I had to change typestate to use trit-vectors instead
of bit-vectors, because for every constraint, there are three
possible values: known-to-be-false (e.g. after x <- y, init(y) is
known-to-be-false), known-to-be-true, and unknown. Before, we
conflated known-to-be-false with unknown. But move requires them
to be treated differently. Consider:
(program a)
(a1) x = 1;
(a2) y <- x;
(a3) log x;
(program b)
(b1) x = 1;
(b2) y <- z;
(b3) log x;
With only two values, the postcondition of statement a2 for
constraint init(x) is the same as that of b2: 0. But in (a2)'s
postcondition, init(x) *must* be false, but in (b2)'s condition,
it's just whatever it was in the postcondition of the preceding statement.
2011-06-22 23:26:34 -05:00
|
|
|
// FIXME move to vec
|
|
|
|
fn any[T](&fn(&T) -> bool f, &vec[T] v) -> bool {
|
|
|
|
for (T t in v) {
|
|
|
|
if (f(t)) { ret true; }
|
|
|
|
}
|
|
|
|
ret false;
|
|
|
|
}
|
|
|
|
|
2010-08-18 13:34:47 -05:00
|
|
|
//
|
|
|
|
// Local Variables:
|
|
|
|
// mode: rust
|
|
|
|
// fill-column: 78;
|
|
|
|
// indent-tabs-mode: nil
|
|
|
|
// c-basic-offset: 4
|
|
|
|
// buffer-file-coding-system: utf-8-unix
|
2011-03-25 17:07:27 -05:00
|
|
|
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
|
2010-08-18 13:34:47 -05:00
|
|
|
// End:
|
|
|
|
//
|