Skip to content

Typestate 2 #380

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
May 17, 2011
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,5 @@ config.mk
src/.DS_Store
/stage0/
/dl/
/stage1/
*.bz2
34 changes: 20 additions & 14 deletions src/comp/driver/rustc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import middle::trans;
import middle::resolve;
import middle::ty;
import middle::typeck;
import middle::typestate_check;
import middle::tstate::ck;
import back::link;
import lib::llvm;
import util::common;
Expand Down Expand Up @@ -105,7 +105,8 @@ fn compile_input(session::session sess,

if (sess.get_opts().run_typestate) {
crate = time(time_passes, "typestate checking",
bind typestate_check::check_crate(crate, def_map));
bind middle::tstate::ck::check_crate(node_type_table,
ty_cx, crate));
}

auto llmod = time[llvm::ModuleRef](time_passes, "translation",
Expand Down Expand Up @@ -165,26 +166,31 @@ options:
}

fn get_os(str triple) -> session::os {
if (_str::find(triple, "win32") > 0 ||
_str::find(triple, "mingw32") > 0 ) {
if (_str::find(triple, "win32") >= 0 ||
_str::find(triple, "mingw32") >= 0 ) {
ret session::os_win32;
} else if (_str::find(triple, "darwin") > 0) { ret session::os_macos; }
else if (_str::find(triple, "linux") > 0) { ret session::os_linux; }
} else if (_str::find(triple, "darwin") >= 0) { ret session::os_macos; }
else if (_str::find(triple, "linux") >= 0) { ret session::os_linux; }
else { log_err "Unknown operating system!"; fail; }
}

fn get_arch(str triple) -> session::arch {
if (_str::find(triple, "i386") > 0 ||
_str::find(triple, "i486") > 0 ||
_str::find(triple, "i586") > 0 ||
_str::find(triple, "i686") > 0 ||
_str::find(triple, "i786") > 0 ) {
if (_str::find(triple, "i386") >= 0 ||
_str::find(triple, "i486") >= 0 ||
_str::find(triple, "i586") >= 0 ||
_str::find(triple, "i686") >= 0 ||
_str::find(triple, "i786") >= 0 ) {
ret session::arch_x86;
} else if (_str::find(triple, "x86_64") > 0) {
} else if (_str::find(triple, "x86_64") >= 0) {
ret session::arch_x64;
} else if (_str::find(triple, "arm") > 0 ||
_str::find(triple, "xscale") > 0 ) {
} else if (_str::find(triple, "arm") >= 0 ||
_str::find(triple, "xscale") >= 0 ) {
ret session::arch_arm;
}
else {
log_err ("Unknown architecture! " + triple);
fail;
}
}

fn get_default_sysroot(str binary) -> str {
Expand Down
18 changes: 15 additions & 3 deletions src/comp/front/ast.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

import std::map::hashmap;
import std::option;
import std::_str;
Expand All @@ -7,7 +6,7 @@ import util::common::span;
import util::common::spanned;
import util::common::ty_mach;
import util::common::filename;
import util::typestate_ann::ts_ann;
import middle::tstate::ann::ts_ann;

type ident = str;

Expand Down Expand Up @@ -323,6 +322,12 @@ type ty_method = rec(proto proto, ident ident,
type ty = spanned[ty_];
tag ty_ {
ty_nil;
ty_bot; /* return type of ! functions and type of
ret/fail/break/cont. there is no syntax
for this type. */
/* bot represents the value of functions that don't return a value
locally to their context. in contrast, things like log that do
return, but don't return a meaningful value, have result type nil. */
ty_bool;
ty_int;
ty_uint;
Expand Down Expand Up @@ -354,12 +359,19 @@ type constr = spanned[constr_];
type arg = rec(mode mode, @ty ty, ident ident, def_id id);
type fn_decl = rec(vec[arg] inputs,
@ty output,
purity purity);
purity purity,
controlflow cf);
tag purity {
pure_fn; // declared with "pred"
impure_fn; // declared with "fn"
}

tag controlflow {
noreturn; // functions with return type _|_ that always
// raise an error or exit (i.e. never return to the caller)
return; // everything else
}

type _fn = rec(fn_decl decl,
proto proto,
block body);
Expand Down
42 changes: 33 additions & 9 deletions src/comp/front/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ tag file_type {
SOURCE_FILE;
}

tag ty_or_bang {
a_ty(@ast::ty);
a_bang;
}

state type parser =
state obj {
fn peek() -> token::token;
Expand Down Expand Up @@ -448,6 +453,13 @@ fn parse_ty_constrs(@ast::ty t, parser p) -> @ast::ty {
ret t;
}

fn parse_ty_or_bang(parser p) -> ty_or_bang {
alt (p.peek()) {
case (token::NOT) { p.bump(); ret a_bang; }
case (_) { ret a_ty(parse_ty(p)); }
}
}

fn parse_ty(parser p) -> @ast::ty {
auto lo = p.get_lo_pos();
auto hi = lo;
Expand Down Expand Up @@ -1713,20 +1725,31 @@ fn parse_fn_decl(parser p, ast::purity purity) -> ast::fn_decl {
some(token::COMMA),
pf, p);

let @ast::ty output;
let ty_or_bang res;

// FIXME: dropping constrs on the floor at the moment.
// pick them up when they're used by typestate pass.
parse_constrs(p);

if (p.peek() == token::RARROW) {
p.bump();
output = parse_ty(p);
res = parse_ty_or_bang(p);
} else {
output = @spanned(inputs.span.lo, inputs.span.hi, ast::ty_nil);
res = a_ty(@spanned(inputs.span.lo, inputs.span.hi, ast::ty_nil));
}

alt (res) {
case (a_ty(?t)) {
ret rec(inputs=inputs.node, output=t,
purity=purity, cf=ast::return);
}
case (a_bang) {
ret rec(inputs=inputs.node,
output=@spanned(p.get_lo_pos(),
p.get_hi_pos(), ast::ty_bot),
purity=purity, cf=ast::noreturn);
}
}
// FIXME
ret rec(inputs=inputs.node, output=output, purity=purity);
}

fn parse_fn(parser p, ast::proto proto, ast::purity purity) -> ast::_fn {
Expand Down Expand Up @@ -1778,11 +1801,12 @@ fn parse_dtor(parser p) -> @ast::method {
let vec[ast::arg] inputs = vec();
let @ast::ty output = @spanned(lo, lo, ast::ty_nil);
let ast::fn_decl d = rec(inputs=inputs,
output=output,
purity=ast::impure_fn);
output=output,
purity=ast::impure_fn,
cf=ast::return);
let ast::_fn f = rec(decl = d,
proto = ast::proto_fn,
body = b);
proto = ast::proto_fn,
body = b);
let ast::method_ m = rec(ident="drop",
meth=f,
id=p.next_def_id(),
Expand Down
20 changes: 14 additions & 6 deletions src/comp/middle/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ import util::common::new_str_hash;
import util::common::spanned;
import util::common::span;
import util::common::ty_mach;
import util::typestate_ann::ts_ann;
import middle::tstate::ann::ts_ann;

import front::ast;
import front::ast::fn_decl;
import front::ast::ident;
import front::ast::path;
import front::ast::mutability;
import front::ast::controlflow;
import front::ast::ty;
import front::ast::expr;
import front::ast::stmt;
Expand Down Expand Up @@ -44,6 +45,7 @@ type ast_fold[ENV] =

// Type folds.
(fn(&ENV e, &span sp) -> @ty) fold_ty_nil,
(fn(&ENV e, &span sp) -> @ty) fold_ty_bot,
(fn(&ENV e, &span sp) -> @ty) fold_ty_bool,
(fn(&ENV e, &span sp) -> @ty) fold_ty_int,
(fn(&ENV e, &span sp) -> @ty) fold_ty_uint,
Expand Down Expand Up @@ -314,7 +316,7 @@ type ast_fold[ENV] =
(fn(&ENV e,
&vec[arg] inputs,
&@ty output,
&purity p) -> ast::fn_decl) fold_fn_decl,
&purity p, &controlflow c) -> ast::fn_decl) fold_fn_decl,

(fn(&ENV e, &ast::_mod m) -> ast::_mod) fold_mod,

Expand Down Expand Up @@ -375,6 +377,7 @@ fn fold_ty[ENV](&ENV env, &ast_fold[ENV] fld, &@ty t) -> @ty {

alt (t.node) {
case (ast::ty_nil) { ret fld.fold_ty_nil(env_, t.span); }
case (ast::ty_bot) { ret fld.fold_ty_bot(env_, t.span); }
case (ast::ty_bool) { ret fld.fold_ty_bool(env_, t.span); }
case (ast::ty_int) { ret fld.fold_ty_int(env_, t.span); }
case (ast::ty_uint) { ret fld.fold_ty_uint(env_, t.span); }
Expand Down Expand Up @@ -926,7 +929,7 @@ fn fold_fn_decl[ENV](&ENV env, &ast_fold[ENV] fld,
inputs += vec(fold_arg(env, fld, a));
}
auto output = fold_ty[ENV](env, fld, decl.output);
ret fld.fold_fn_decl(env, inputs, output, decl.purity);
ret fld.fold_fn_decl(env, inputs, output, decl.purity, decl.cf);
}

fn fold_fn[ENV](&ENV env, &ast_fold[ENV] fld, &ast::_fn f) -> ast::_fn {
Expand Down Expand Up @@ -1202,6 +1205,10 @@ fn identity_fold_ty_nil[ENV](&ENV env, &span sp) -> @ty {
ret @respan(sp, ast::ty_nil);
}

fn identity_fold_ty_bot[ENV](&ENV env, &span sp) -> @ty {
ret @respan(sp, ast::ty_bot);
}

fn identity_fold_ty_bool[ENV](&ENV env, &span sp) -> @ty {
ret @respan(sp, ast::ty_bool);
}
Expand Down Expand Up @@ -1622,8 +1629,8 @@ fn identity_fold_block[ENV](&ENV e, &span sp, &ast::block_ blk) -> block {
fn identity_fold_fn_decl[ENV](&ENV e,
&vec[arg] inputs,
&@ty output,
&purity p) -> ast::fn_decl {
ret rec(inputs=inputs, output=output, purity=p);
&purity p, &controlflow c) -> ast::fn_decl {
ret rec(inputs=inputs, output=output, purity=p, cf=c);
}

fn identity_fold_fn[ENV](&ENV e,
Expand Down Expand Up @@ -1722,6 +1729,7 @@ fn new_identity_fold[ENV]() -> ast_fold[ENV] {
fold_path = bind identity_fold_path[ENV](_,_,_),

fold_ty_nil = bind identity_fold_ty_nil[ENV](_,_),
fold_ty_bot = bind identity_fold_ty_bot[ENV](_,_),
fold_ty_bool = bind identity_fold_ty_bool[ENV](_,_),
fold_ty_int = bind identity_fold_ty_int[ENV](_,_),
fold_ty_uint = bind identity_fold_ty_uint[ENV](_,_),
Expand Down Expand Up @@ -1821,7 +1829,7 @@ fn new_identity_fold[ENV]() -> ast_fold[ENV] {
fold_ann = bind identity_fold_ann[ENV](_,_),

fold_fn = bind identity_fold_fn[ENV](_,_,_,_),
fold_fn_decl = bind identity_fold_fn_decl[ENV](_,_,_,_),
fold_fn_decl = bind identity_fold_fn_decl[ENV](_,_,_,_,_),
fold_mod = bind identity_fold_mod[ENV](_,_),
fold_native_mod = bind identity_fold_native_mod[ENV](_,_),
fold_crate = bind identity_fold_crate[ENV](_,_,_,_),
Expand Down
1 change: 1 addition & 0 deletions src/comp/middle/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ mod Encode {
w.write_str(common::uistr(id));
}
case (ty::ty_type) {w.write_char('Y');}
case (ty::ty_task) {w.write_char('a');}

// These two don't appear in crate metadata, but are here because
// `hash_ty()` uses this function.
Expand Down
2 changes: 1 addition & 1 deletion src/comp/middle/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import util::common::new_int_hash;
import util::common::new_uint_hash;
import util::common::new_str_hash;
import util::common::span;
import util::typestate_ann::ts_ann;
import middle::tstate::ann::ts_ann;
import std::map::hashmap;
import std::list::list;
import std::list::nil;
Expand Down
25 changes: 20 additions & 5 deletions src/comp/middle/trans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -757,6 +757,7 @@ fn type_of_inner(&@crate_ctxt cx, &ty::t t) -> TypeRef {
alt (ty::struct(cx.tcx, t)) {
case (ty::ty_native) { llty = T_ptr(T_i8()); }
case (ty::ty_nil) { llty = T_nil(); }
case (ty::ty_bot) { llty = T_nil(); } /* ...I guess? */
case (ty::ty_bool) { llty = T_bool(); }
case (ty::ty_int) { llty = T_int(); }
case (ty::ty_float) { llty = T_float(); }
Expand Down Expand Up @@ -3186,8 +3187,8 @@ fn copy_ty(&@block_ctxt cx,
if (ty::type_is_scalar(cx.fcx.lcx.ccx.tcx, t) ||
ty::type_is_native(cx.fcx.lcx.ccx.tcx, t)) {
ret res(cx, cx.build.Store(src, dst));

} else if (ty::type_is_nil(cx.fcx.lcx.ccx.tcx, t)) {
} else if (ty::type_is_nil(cx.fcx.lcx.ccx.tcx, t) ||
ty::type_is_bot(cx.fcx.lcx.ccx.tcx, t)) {
ret res(cx, C_nil());

} else if (ty::type_is_boxed(cx.fcx.lcx.ccx.tcx, t)) {
Expand Down Expand Up @@ -3552,6 +3553,8 @@ fn autoderef(&@block_ctxt cx, ValueRef v, &ty::t t) -> result {
}
}
}

fail; // fools the return-checker
}

fn autoderefed_ty(&@crate_ctxt ccx, &ty::t t) -> ty::t {
Expand All @@ -3567,6 +3570,8 @@ fn autoderefed_ty(&@crate_ctxt ccx, &ty::t t) -> ty::t {
}
}
}

fail; // fools the return-checker
}

fn trans_binary(&@block_ctxt cx, ast::binop op,
Expand All @@ -3591,12 +3596,17 @@ fn trans_binary(&@block_ctxt cx, ast::binop op,
auto lhs_false_cx = new_scope_block_ctxt(cx, "lhs false");
auto lhs_false_res = res(lhs_false_cx, C_bool(false));

// The following line ensures that any cleanups for rhs
// are done within the block for rhs. This is necessary
// because and/or are lazy. So the rhs may never execute,
// and the cleanups can't be pushed into later code.
auto rhs_bcx = trans_block_cleanups(rhs_res.bcx, rhs_cx);

lhs_res.bcx.build.CondBr(lhs_res.val,
rhs_cx.llbb,
lhs_false_cx.llbb);

ret join_results(cx, T_bool(),
vec(lhs_false_res, rhs_res));
vec(lhs_false_res, rec(bcx=rhs_bcx with rhs_res)));
}

case (ast::or) {
Expand All @@ -3615,12 +3625,15 @@ fn trans_binary(&@block_ctxt cx, ast::binop op,
auto lhs_true_cx = new_scope_block_ctxt(cx, "lhs true");
auto lhs_true_res = res(lhs_true_cx, C_bool(true));

// see the and case for an explanation
auto rhs_bcx = trans_block_cleanups(rhs_res.bcx, rhs_cx);

lhs_res.bcx.build.CondBr(lhs_res.val,
lhs_true_cx.llbb,
rhs_cx.llbb);

ret join_results(cx, T_bool(),
vec(lhs_true_res, rhs_res));
vec(lhs_true_res, rec(bcx=rhs_bcx with rhs_res)));
}

case (_) {
Expand Down Expand Up @@ -4984,6 +4997,8 @@ fn trans_bind(&@block_ctxt cx, &@ast::expr f,
ret res(bcx, pair_v);
}
}

fail; // sadly needed b/c the compiler doesn't know yet that unimpl fails
}

fn trans_arg_expr(&@block_ctxt cx,
Expand Down
Loading