From 70e5457d7c99d3b273c3ef9edaebee1324be85c7 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Mon, 4 Apr 2011 15:44:15 -0700 Subject: Make box prefix operator and box type carry mutability flag. --- src/comp/front/ast.rs | 7 +++++-- src/comp/front/parser.rs | 3 ++- src/comp/middle/trans.rs | 10 +++++----- src/comp/middle/ty.rs | 4 ++-- src/comp/middle/typeck.rs | 7 +++---- 5 files changed, 17 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs index 46666a34..61450a1b 100644 --- a/src/comp/front/ast.rs +++ b/src/comp/front/ast.rs @@ -188,7 +188,7 @@ fn binop_to_str(binop op) -> str { tag unop { - box; + box(mutability); deref; bitnot; not; @@ -197,7 +197,10 @@ tag unop { fn unop_to_str(unop op) -> str { alt (op) { - case (box) {ret "@";} + case (box(?mt)) { + if (mt == mut) { ret "@mutable"; } + ret "@"; + } case (deref) {ret "*";} case (bitnot) {ret "~";} case (not) {ret "!";} diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index 4c3e6cf0..1e0a9042 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -1074,9 +1074,10 @@ impure fn parse_prefix_expr(parser p) -> @ast.expr { case (token.AT) { p.bump(); + auto m = parse_mutability(p); auto e = parse_prefix_expr(p); hi = e.span; - ex = ast.expr_unary(ast.box, e, ast.ann_none); + ex = ast.expr_unary(ast.box(m), e, ast.ann_none); } case (_) { diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 590b3ee8..aeeff169 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -1424,7 +1424,7 @@ fn trans_malloc_boxed(@block_ctxt cx, @ty.t t) -> result { // Synthesize a fake box type structurally so we have something // to measure the size of. auto boxed_body = ty.plain_tup_ty(vec(plain_ty(ty.ty_int), t)); - auto box_ptr = ty.plain_box_ty(t); + auto box_ptr = ty.plain_box_ty(t, ast.imm); auto sz = size_of(cx, boxed_body); auto llty = type_of(cx.fcx.ccx, box_ptr); ret trans_raw_malloc(sz.bcx, llty, sz.val); @@ -2005,7 +2005,7 @@ fn iter_structural_ty_full(@block_ctxt cx, auto box_a_ptr = cx.build.Load(box_a_cell); auto box_b_ptr = cx.build.Load(box_b_cell); auto tnil = plain_ty(ty.ty_nil); - auto tbox = ty.plain_box_ty(tnil); + auto tbox = ty.plain_box_ty(tnil, ast.imm); auto inner_cx = new_sub_block_ctxt(cx, "iter box"); auto next_cx = new_sub_block_ctxt(cx, "next"); @@ -2557,7 +2557,7 @@ fn trans_unary(@block_ctxt cx, ast.unop op, ret res(sub.bcx, sub.bcx.build.Neg(sub.val)); } } - case (ast.box) { + case (ast.box(_)) { auto e_ty = ty.expr_ty(e); auto e_val = sub.val; auto box_ty = node_ann_type(sub.bcx.fcx.ccx, a); @@ -3943,7 +3943,7 @@ fn trans_bind_thunk(@crate_ctxt cx, auto bcx = new_top_block_ctxt(fcx); auto lltop = bcx.llbb; - auto llclosure_ptr_ty = type_of(cx, ty.plain_box_ty(closure_ty)); + auto llclosure_ptr_ty = type_of(cx, ty.plain_box_ty(closure_ty, ast.imm)); auto llclosure = bcx.build.PointerCast(fcx.llenv, llclosure_ptr_ty); auto lltarget = GEP_tup_like(bcx, closure_ty, llclosure, @@ -5819,7 +5819,7 @@ fn trans_obj(@crate_ctxt cx, &ast._obj ob, ast.def_id oid, let @ty.t body_ty = ty.plain_tup_ty(vec(tydesc_ty, typarams_ty, fields_ty)); - let @ty.t boxed_body_ty = ty.plain_box_ty(body_ty); + let @ty.t boxed_body_ty = ty.plain_box_ty(body_ty, ast.imm); // Malloc a box for the body. auto box = trans_malloc_boxed(bcx, body_ty); diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index d0b5fe10..24bd647f 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -564,8 +564,8 @@ fn plain_ty(&sty st) -> @t { ret @rec(struct=st, cname=none[str]); } -fn plain_box_ty(@t subty) -> @t { - ret plain_ty(ty_box(rec(ty=subty, mut=ast.imm))); +fn plain_box_ty(@t subty, ast.mutability mut) -> @t { + ret plain_ty(ty_box(rec(ty=subty, mut=mut))); } fn plain_tup_ty(vec[@t] elem_tys) -> @t { diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index f726ae58..10cbd6d5 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -959,7 +959,7 @@ fn strip_boxes(@ty.t t) -> @ty.t { fn add_boxes(uint n, @ty.t t) -> @ty.t { auto t1 = t; while (n != 0u) { - t1 = ty.plain_box_ty(t1); + t1 = ty.plain_box_ty(t1, ast.imm); n -= 1u; } ret t1; @@ -1728,9 +1728,8 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr { auto oper_1 = check_expr(fcx, oper); auto oper_t = expr_ty(oper_1); alt (unop) { - case (ast.box) { - // TODO: mutable - oper_t = ty.plain_box_ty(oper_t); + case (ast.box(?mut)) { + oper_t = ty.plain_box_ty(oper_t, mut); } case (ast.deref) { alt (oper_t.struct) { -- cgit v1.2.3 From ba537fa5f5d7b816226871d0fffe2a9de4abd0ff Mon Sep 17 00:00:00 2001 From: Lindsey Kuper Date: Fri, 1 Apr 2011 17:20:22 -0700 Subject: Knocking out a quick fixme: pretty-printing exprs in error messages. --- src/comp/middle/trans.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index aeeff169..1ab8a18d 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -17,6 +17,8 @@ import middle.ty; import back.x86; import back.abi; +import pretty.pprust; + import middle.ty.pat_ty; import middle.ty.plain_ty; @@ -4913,8 +4915,7 @@ fn trans_log(@block_ctxt cx, @ast.expr e) -> result { fn trans_check_expr(@block_ctxt cx, @ast.expr e) -> result { auto cond_res = trans_expr(cx, e); - // FIXME: need pretty-printer. - auto expr_str = ""; + auto expr_str = pretty.pprust.expr_to_str(e); auto fail_cx = new_sub_block_ctxt(cx, "fail"); auto fail_res = trans_fail(fail_cx, e.span, expr_str); -- cgit v1.2.3 From 361ee5a68bf23c9fc65aee39618b5d1b0db4941b Mon Sep 17 00:00:00 2001 From: Lindsey Kuper Date: Fri, 1 Apr 2011 17:48:47 -0700 Subject: Oops -- if we're going to use the pretty-printer, we need it to work. --- src/comp/pretty/pprust.rs | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/comp/pretty/pprust.rs b/src/comp/pretty/pprust.rs index b0d6fb94..28f64c89 100644 --- a/src/comp/pretty/pprust.rs +++ b/src/comp/pretty/pprust.rs @@ -379,6 +379,11 @@ impure fn print_literal(ps s, @ast.lit lit) { wrd(s.s, common.istr(val as int)); wrd(s.s, common.ty_mach_to_str(mach)); } + case (ast.lit_mach_float(?mach,?val)) { + // val is already a str + wrd(s.s, val); + wrd(s.s, common.ty_mach_to_str(mach)); + } case (ast.lit_nil) {wrd(s.s, "()");} case (ast.lit_bool(?val)) { if (val) {wrd(s.s, "true");} else {wrd(s.s, "false");} -- cgit v1.2.3 From 8703c8067fb8a22ec9b296efea162aac3e7f9521 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Tue, 5 Apr 2011 21:21:32 +0000 Subject: FIx native wrapper generation to handle more arg types. --- src/comp/middle/trans.rs | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 1ab8a18d..6e3550bd 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -6148,7 +6148,7 @@ fn decl_native_fn_and_pair(@crate_ctxt cx, auto arg_n = 3u; auto pass_task; - auto lltaskptr = bcx.build.PtrToInt(fcx.lltaskptr, T_int()); + auto lltaskptr = vp2i(bcx, fcx.lltaskptr); alt (abi) { case (ast.native_abi_rust) { pass_task = true; @@ -6156,7 +6156,7 @@ fn decl_native_fn_and_pair(@crate_ctxt cx, for each (uint i in _uint.range(0u, num_ty_param)) { auto llarg = llvm.LLVMGetParam(fcx.llfn, arg_n); check (llarg as int != 0); - call_args += vec(bcx.build.PointerCast(llarg, T_i32())); + call_args += vec(vp2i(bcx, llarg)); arg_n += 1u; } } @@ -6169,6 +6169,26 @@ fn decl_native_fn_and_pair(@crate_ctxt cx, } } + fn push_arg(@block_ctxt cx, + &mutable vec[ValueRef] args, + ValueRef v, + @ty.t t) { + if (ty.type_is_integral(t)) { + auto lldsttype = T_int(); + auto llsrctype = type_of(cx.fcx.ccx, t); + if (llvm.LLVMGetIntTypeWidth(lldsttype) > + llvm.LLVMGetIntTypeWidth(llsrctype)) { + args += vec(cx.build.ZExtOrBitCast(v, T_int())); + } else { + args += vec(cx.build.TruncOrBitCast(v, T_int())); + } + } else if (ty.type_is_fp(t)) { + args += vec(cx.build.FPToSI(v, T_int())); + } else { + args += vec(vp2i(cx, v)); + } + } + auto r; auto rptr; auto args = ty.ty_fn_args(fn_type); @@ -6192,7 +6212,7 @@ fn decl_native_fn_and_pair(@crate_ctxt cx, for (ty.arg arg in args) { auto llarg = llvm.LLVMGetParam(fcx.llfn, arg_n); check (llarg as int != 0); - call_args += vec(bcx.build.PointerCast(llarg, T_i32())); + push_arg(bcx, call_args, llarg, arg.ty); arg_n += 1u; } -- cgit v1.2.3 From b8bb2e118e9815316320f946ef3fc7e6909ed7c9 Mon Sep 17 00:00:00 2001 From: Lindsey Kuper Date: Tue, 5 Apr 2011 14:18:44 -0700 Subject: Further on the path toward self-awareness. Mostly: * Merciless refactoring of trans.rs so that trans_call can work for self-calls as well as other kinds of calls Also: * Various changes to go with having idents, rather than exprs, in expr_call_self AST nodes * Added missing case for SELF token to token.to_str() --- src/comp/front/ast.rs | 2 +- src/comp/front/parser.rs | 4 +- src/comp/front/token.rs | 2 + src/comp/middle/fold.rs | 11 ++- src/comp/middle/trans.rs | 178 ++++++++++++++++++---------------------------- src/comp/middle/typeck.rs | 12 ++++ src/comp/pretty/pprust.rs | 8 ++- 7 files changed, 99 insertions(+), 118 deletions(-) (limited to 'src') diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs index 61450a1b..d41e6d60 100644 --- a/src/comp/front/ast.rs +++ b/src/comp/front/ast.rs @@ -258,7 +258,7 @@ tag expr_ { expr_tup(vec[elt], ann); expr_rec(vec[field], option.t[@expr], ann); expr_call(@expr, vec[@expr], ann); - expr_call_self(@expr, vec[@expr], ann); + expr_call_self(ident, vec[@expr], ann); expr_bind(@expr, vec[option.t[@expr]], ann); expr_spawn(spawn_dom, option.t[str], @expr, vec[@expr], ann); expr_binary(binop, @expr, @expr, ann); diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index 1e0a9042..31e470be 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -887,10 +887,12 @@ impure fn parse_bottom_expr(parser p) -> @ast.expr { } case (token.SELF) { + log "parsing a self-call..."; + p.bump(); expect(p, token.DOT); // The rest is a call expression. - auto e = parse_bottom_expr(p); + auto e = parse_ident(p); auto pf = parse_expr; auto es = parse_seq[@ast.expr](token.LPAREN, token.RPAREN, diff --git a/src/comp/front/token.rs b/src/comp/front/token.rs index 5ac9d662..dcfafadf 100644 --- a/src/comp/front/token.rs +++ b/src/comp/front/token.rs @@ -348,6 +348,8 @@ fn to_str(token t) -> str { /* Object type */ case (OBJ) { ret "obj"; } + case (SELF) { ret "self"; } + /* Comm and task types */ case (CHAN) { ret "chan"; } diff --git a/src/comp/middle/fold.rs b/src/comp/middle/fold.rs index d7a18783..77c89836 100644 --- a/src/comp/middle/fold.rs +++ b/src/comp/middle/fold.rs @@ -88,7 +88,7 @@ type ast_fold[ENV] = ann a) -> @expr) fold_expr_call, (fn(&ENV e, &span sp, - @expr f, vec[@expr] args, + ident id, vec[@expr] args, ann a) -> @expr) fold_expr_call_self, (fn(&ENV e, &span sp, @@ -566,10 +566,9 @@ fn fold_expr[ENV](&ENV env, ast_fold[ENV] fld, &@expr e) -> @expr { ret fld.fold_expr_call(env_, e.span, ff, aargs, t); } - case (ast.expr_call_self(?f, ?args, ?t)) { - auto ff = fold_expr(env_, fld, f); + case (ast.expr_call_self(?ident, ?args, ?t)) { auto aargs = fold_exprs(env_, fld, args); - ret fld.fold_expr_call_self(env_, e.span, ff, aargs, t); + ret fld.fold_expr_call_self(env_, e.span, ident, aargs, t); } case (ast.expr_bind(?f, ?args_opt, ?t)) { @@ -1185,9 +1184,9 @@ fn identity_fold_expr_call[ENV](&ENV env, &span sp, @expr f, ret @respan(sp, ast.expr_call(f, args, a)); } -fn identity_fold_expr_call_self[ENV](&ENV env, &span sp, @expr f, +fn identity_fold_expr_call_self[ENV](&ENV env, &span sp, ident id, vec[@expr] args, ann a) -> @expr { - ret @respan(sp, ast.expr_call_self(f, args, a)); + ret @respan(sp, ast.expr_call_self(id, args, a)); } fn identity_fold_expr_bind[ENV](&ENV env, &span sp, @expr f, diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 6e3550bd..b61aa244 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -12,6 +12,7 @@ import std.option.none; import front.ast; import front.creader; +import pretty.pprust; import driver.session; import middle.ty; import back.x86; @@ -114,12 +115,14 @@ state type crate_ctxt = rec(session.session sess, vec[str] path, std.sha1.sha1 sha); +type self_vt = rec(ValueRef v, @ty.t t); + state type fn_ctxt = rec(ValueRef llfn, ValueRef lltaskptr, ValueRef llenv, ValueRef llretptr, mutable BasicBlockRef llallocas, - mutable option.t[ValueRef] llself, + mutable option.t[self_vt] llself, mutable option.t[ValueRef] lliterbody, hashmap[ast.def_id, ValueRef] llargs, hashmap[ast.def_id, ValueRef] llobjfields, @@ -3783,12 +3786,12 @@ fn trans_path(@block_ctxt cx, &ast.path p, &option.t[ast.def] dopt, fail; } -fn trans_field(@block_ctxt cx, &ast.span sp, @ast.expr base, +fn trans_field(@block_ctxt cx, &ast.span sp, ValueRef v, @ty.t t0, &ast.ident field, &ast.ann ann) -> lval_result { - auto r = trans_expr(cx, base); - auto t = ty.expr_ty(base); - r = autoderef(r.bcx, r.val, t); - t = autoderefed_ty(t); + + auto r = autoderef(cx, v, t0); + auto t = autoderefed_ty(t0); + alt (t.struct) { case (ty.ty_tup(_)) { let uint ix = ty.field_num(cx.fcx.ccx.sess, sp, field); @@ -3881,11 +3884,30 @@ fn trans_lval(@block_ctxt cx, @ast.expr e) -> lval_result { ret trans_path(cx, p, dopt, ann); } case (ast.expr_field(?base, ?ident, ?ann)) { - ret trans_field(cx, e.span, base, ident, ann); + auto r = trans_expr(cx, base); + auto t = ty.expr_ty(base); + ret trans_field(r.bcx, e.span, r.val, t, ident, ann); } case (ast.expr_index(?base, ?idx, ?ann)) { ret trans_index(cx, e.span, base, idx, ann); } + + // Kind of bizarre to pass an *entire* self-call here...but let's try + // it + case (ast.expr_call_self(?ident, _, ?ann)) { + alt (cx.fcx.llself) { + case (some[self_vt](?s_vt)) { + auto r = s_vt.v; + auto t = s_vt.t; + ret trans_field(cx, e.span, r, t, ident, ann); + } + case (_) { + // Shouldn't happen. + fail; + } + + } + } case (_) { cx.fcx.ccx.sess.unimpl("expr variant in trans_lval"); } } fail; @@ -4462,70 +4484,6 @@ fn trans_call(@block_ctxt cx, @ast.expr f, ret res(bcx, retval); } -fn trans_call_self(@block_ctxt cx, @ast.expr f, - option.t[ValueRef] lliterbody, - vec[@ast.expr] args, - &ast.ann ann) -> result { - log "translating a self-call"; - - auto f_res = trans_lval(cx, f); - auto faddr = f_res.res.val; - auto llenv = C_null(T_opaque_closure_ptr(cx.fcx.ccx.tn)); - - alt (f_res.llobj) { - case (some[ValueRef](_)) { - // It's a vtbl entry. - faddr = f_res.res.bcx.build.Load(faddr); - } - case (none[ValueRef]) { - // It's a closure. - auto bcx = f_res.res.bcx; - auto pair = faddr; - faddr = bcx.build.GEP(pair, vec(C_int(0), - C_int(abi.fn_field_code))); - faddr = bcx.build.Load(faddr); - - auto llclosure = bcx.build.GEP(pair, - vec(C_int(0), - C_int(abi.fn_field_box))); - llenv = bcx.build.Load(llclosure); - } - } - auto fn_ty = ty.expr_ty(f); - auto ret_ty = ty.ann_to_type(ann); - auto args_res = trans_args(f_res.res.bcx, - llenv, f_res.llobj, - f_res.generic, - lliterbody, - args, fn_ty); - - auto bcx = args_res._0; - auto llargs = args_res._1; - auto llretslot = args_res._2; - - /* - log "calling: " + val_str(cx.fcx.ccx.tn, faddr); - - for (ValueRef arg in llargs) { - log "arg: " + val_str(cx.fcx.ccx.tn, arg); - } - */ - - bcx.build.FastCall(faddr, llargs); - auto retval = C_nil(); - - if (!ty.type_is_nil(ret_ty)) { - retval = load_scalar_or_boxed(bcx, llretslot, ret_ty); - // Retval doesn't correspond to anything really tangible in the frame, - // but it's a ref all the same, so we put a note here to drop it when - // we're done in this scope. - find_scope_cx(cx).cleanups += - vec(clean(bind drop_ty(_, retval, ret_ty))); - } - - ret res(bcx, retval); -} - fn trans_tup(@block_ctxt cx, vec[ast.elt] elts, &ast.ann ann) -> result { auto bcx = cx; @@ -4762,8 +4720,9 @@ fn trans_expr(@block_ctxt cx, @ast.expr e) -> result { ret trans_call(cx, f, none[ValueRef], args, ann); } - case (ast.expr_call_self(?f, ?args, ?ann)) { - ret trans_call_self(cx, f, none[ValueRef], args, ann); + case (ast.expr_call_self(?ident, ?args, ?ann)) { + // A weird hack to make self-calls work. + ret trans_call(cx, e, none[ValueRef], args, ann); } case (ast.expr_cast(?e, _, ?ann)) { @@ -5473,7 +5432,7 @@ fn new_fn_ctxt(@crate_ctxt cx, llenv=llenv, llretptr=llretptr, mutable llallocas = llallocas, - mutable llself=none[ValueRef], + mutable llself=none[self_vt], mutable lliterbody=none[ValueRef], llargs=llargs, llobjfields=llobjfields, @@ -5492,27 +5451,24 @@ fn new_fn_ctxt(@crate_ctxt cx, fn create_llargs_for_fn_args(&@fn_ctxt cx, ast.proto proto, - option.t[TypeRef] ty_self, + option.t[tup(TypeRef, @ty.t)] ty_self, @ty.t ret_ty, &vec[ast.arg] args, &vec[ast.ty_param] ty_params) { - alt (ty_self) { - case (some[TypeRef](_)) { - cx.llself = some[ValueRef](cx.llenv); - } - case (_) { - } - } - auto arg_n = 3u; - if (ty_self == none[TypeRef]) { - for (ast.ty_param tp in ty_params) { - auto llarg = llvm.LLVMGetParam(cx.llfn, arg_n); - check (llarg as int != 0); - cx.lltydescs.insert(tp.id, llarg); - arg_n += 1u; + alt (ty_self) { + case (some[tup(TypeRef, @ty.t)](?tt)) { + cx.llself = some[self_vt](rec(v = cx.llenv, t = tt._1)); + } + case (none[tup(TypeRef, @ty.t)]) { + for (ast.ty_param tp in ty_params) { + auto llarg = llvm.LLVMGetParam(cx.llfn, arg_n); + check (llarg as int != 0); + cx.lltydescs.insert(tp.id, llarg); + arg_n += 1u; + } } } @@ -5536,17 +5492,17 @@ fn create_llargs_for_fn_args(&@fn_ctxt cx, // were passed and whatnot. Apparently mem2reg will mop up. fn copy_any_self_to_alloca(@fn_ctxt fcx, - option.t[TypeRef] ty_self) { + option.t[tup(TypeRef, @ty.t)] ty_self) { auto bcx = llallocas_block_ctxt(fcx); alt (fcx.llself) { - case (some[ValueRef](?self_v)) { + case (some[self_vt](?s_vt)) { alt (ty_self) { - case (some[TypeRef](?self_t)) { - auto a = alloca(bcx, self_t); - bcx.build.Store(self_v, a); - fcx.llself = some[ValueRef](a); + case (some[tup(TypeRef, @ty.t)](?tt)) { + auto a = alloca(bcx, tt._0); + bcx.build.Store(s_vt.v, a); + fcx.llself = some[self_vt](rec(v = a, t = s_vt.t)); } } } @@ -5608,7 +5564,7 @@ fn ret_ty_of_fn(ast.ann ann) -> @ty.t { ret ret_ty_of_fn_ty(ty.ann_to_type(ann)); } -fn populate_fn_ctxt_from_llself(@fn_ctxt fcx, ValueRef llself) { +fn populate_fn_ctxt_from_llself(@fn_ctxt fcx, self_vt llself) { auto bcx = llallocas_block_ctxt(fcx); let vec[@ty.t] field_tys = vec(); @@ -5625,7 +5581,7 @@ fn populate_fn_ctxt_from_llself(@fn_ctxt fcx, ValueRef llself) { let TypeRef llobj_box_ty = T_obj_ptr(bcx.fcx.ccx.tn, n_typarams); auto box_cell = - bcx.build.GEP(llself, + bcx.build.GEP(llself.v, vec(C_int(0), C_int(abi.obj_field_box))); @@ -5678,7 +5634,7 @@ fn populate_fn_ctxt_from_llself(@fn_ctxt fcx, ValueRef llself) { } fn trans_fn(@crate_ctxt cx, &ast._fn f, ast.def_id fid, - option.t[TypeRef] ty_self, + option.t[tup(TypeRef, @ty.t)] ty_self, &vec[ast.ty_param] ty_params, &ast.ann ann) { auto llfndecl = cx.item_ids.get(fid); @@ -5691,7 +5647,7 @@ fn trans_fn(@crate_ctxt cx, &ast._fn f, ast.def_id fid, copy_any_self_to_alloca(fcx, ty_self); alt (fcx.llself) { - case (some[ValueRef](?llself)) { + case (some[self_vt](?llself)) { populate_fn_ctxt_from_llself(fcx, llself); } case (_) { @@ -5714,7 +5670,9 @@ fn trans_fn(@crate_ctxt cx, &ast._fn f, ast.def_id fid, new_builder(fcx.llallocas).Br(lltop); } -fn trans_vtbl(@crate_ctxt cx, TypeRef self_ty, +fn trans_vtbl(@crate_ctxt cx, + TypeRef llself_ty, + @ty.t self_ty, &ast._obj ob, &vec[ast.ty_param] ty_params) -> ValueRef { let vec[ValueRef] methods = vec(); @@ -5732,7 +5690,7 @@ fn trans_vtbl(@crate_ctxt cx, TypeRef self_ty, alt (node_ann_type(cx, m.node.ann).struct) { case (ty.ty_fn(?proto, ?inputs, ?output)) { llfnty = type_of_fn_full(cx, proto, - some[TypeRef](self_ty), + some[TypeRef](llself_ty), inputs, output, _vec.len[ast.ty_param](ty_params)); } @@ -5744,7 +5702,8 @@ fn trans_vtbl(@crate_ctxt cx, TypeRef self_ty, cx.item_ids.insert(m.node.id, llfn); cx.item_symbols.insert(m.node.id, s); - trans_fn(mcx, m.node.meth, m.node.id, some[TypeRef](self_ty), + trans_fn(mcx, m.node.meth, m.node.id, + some[tup(TypeRef, @ty.t)](tup(llself_ty, self_ty)), ty_params, m.node.ann); methods += vec(llfn); } @@ -5775,7 +5734,8 @@ fn trans_obj(@crate_ctxt cx, &ast._obj ob, ast.def_id oid, auto fcx = new_fn_ctxt(cx, llctor_decl); create_llargs_for_fn_args(fcx, ast.proto_fn, - none[TypeRef], ret_ty_of_fn(ann), + none[tup(TypeRef, @ty.t)], + ret_ty_of_fn(ann), fn_args, ty_params); let vec[ty.arg] arg_tys = arg_tys_of_fn(ann); @@ -5784,9 +5744,10 @@ fn trans_obj(@crate_ctxt cx, &ast._obj ob, ast.def_id oid, auto bcx = new_top_block_ctxt(fcx); auto lltop = bcx.llbb; - auto llself_ty = type_of(cx, ret_ty_of_fn(ann)); + auto self_ty = ret_ty_of_fn(ann); + auto llself_ty = type_of(cx, self_ty); auto pair = bcx.fcx.llretptr; - auto vtbl = trans_vtbl(cx, llself_ty, ob, ty_params); + auto vtbl = trans_vtbl(cx, llself_ty, self_ty, ob, ty_params); auto pair_vtbl = bcx.build.GEP(pair, vec(C_int(0), C_int(abi.obj_field_vtbl))); @@ -5907,7 +5868,8 @@ fn trans_tag_variant(@crate_ctxt cx, ast.def_id tag_id, auto fcx = new_fn_ctxt(cx, llfndecl); create_llargs_for_fn_args(fcx, ast.proto_fn, - none[TypeRef], ret_ty_of_fn(variant.node.ann), + none[tup(TypeRef, @ty.t)], + ret_ty_of_fn(variant.node.ann), fn_args, ty_params); let vec[@ty.t] ty_param_substs = vec(); @@ -5995,7 +5957,7 @@ fn trans_item(@crate_ctxt cx, &ast.item item) { alt (item.node) { case (ast.item_fn(?name, ?f, ?tps, ?fid, ?ann)) { auto sub_cx = extend_path(cx, name); - trans_fn(sub_cx, f, fid, none[TypeRef], tps, ann); + trans_fn(sub_cx, f, fid, none[tup(TypeRef, @ty.t)], tps, ann); } case (ast.item_obj(?name, ?ob, ?tps, ?oid, ?ann)) { auto sub_cx = @rec(obj_typarams=tps, @@ -6803,7 +6765,7 @@ fn trans_vec_append_glue(@crate_ctxt cx) { llenv=C_null(T_ptr(T_nil())), llretptr=C_null(T_ptr(T_nil())), mutable llallocas = llallocas, - mutable llself=none[ValueRef], + mutable llself=none[self_vt], mutable lliterbody=none[ValueRef], llargs=new_def_hash[ValueRef](), llobjfields=new_def_hash[ValueRef](), diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 10cbd6d5..e105c7a9 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -2110,6 +2110,18 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr { ast.expr_call(f_1, args_1, ann)); } + case (ast.expr_call_self(?ident, ?args, _)) { + // FIXME: What's to check here? + + // FIXME: These two lines are ripped off from the expr_call case; + // what should they be really? + auto rt_1 = plain_ty(ty.ty_nil); + auto ann = triv_ann(rt_1); + + ret @fold.respan[ast.expr_](expr.span, + ast.expr_call_self(ident, args, ann)); + } + case (ast.expr_spawn(?dom, ?name, ?f, ?args, _)) { auto result = check_call(fcx, f, args); auto f_1 = result._0; diff --git a/src/comp/pretty/pprust.rs b/src/comp/pretty/pprust.rs index 28f64c89..7e0fb6cb 100644 --- a/src/comp/pretty/pprust.rs +++ b/src/comp/pretty/pprust.rs @@ -454,9 +454,9 @@ impure fn print_expr(ps s, &@ast.expr expr) { commasep_exprs(s, args); pclose(s); } - case (ast.expr_call_self(?func,?args,_)) { + case (ast.expr_call_self(?ident,?args,_)) { wrd(s.s, "self."); - print_expr(s, func); + print_ident(s, ident); popen(s); commasep_exprs(s, args); pclose(s); @@ -723,6 +723,10 @@ impure fn print_decl(ps s, @ast.decl decl) { end(s.s); } +impure fn print_ident(ps s, ast.ident ident) { + wrd(s.s, ident); +} + impure fn print_for_decl(ps s, @ast.decl decl) { alt (decl.node) { case (ast.decl_local(?loc)) { -- cgit v1.2.3 From 4fc8de196977a0e5bb4f733f7aaeb1162e880eaa Mon Sep 17 00:00:00 2001 From: Lindsey Kuper Date: Tue, 5 Apr 2011 16:17:47 -0700 Subject: Last pieces of self-call support. The last few pieces of the hack that lets us use trans.trans_call() to translate self-calls, plus a fix for the parser buy that was preventing self-call expressions from getting past parsing. test/run-pass/obj-self.rs works now (as in it actually prints "hi!" twice!). --- src/comp/front/parser.rs | 2 +- src/comp/middle/trans.rs | 35 ++++++++++++++++++++++++++++++----- src/comp/middle/ty.rs | 6 ++++++ 3 files changed, 37 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index 31e470be..27fdc7fe 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -899,7 +899,7 @@ impure fn parse_bottom_expr(parser p) -> @ast.expr { some(token.COMMA), pf, p); hi = es.span; - auto ex = ast.expr_call_self(e, es.node, ast.ann_none); + ex = ast.expr_call_self(e, es.node, ast.ann_none); } case (_) { diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index b61aa244..6fcd7b37 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -3605,20 +3605,23 @@ type generic_info = rec(@ty.t item_type, type lval_result = rec(result res, bool is_mem, option.t[generic_info] generic, - option.t[ValueRef] llobj); + option.t[ValueRef] llobj, + option.t[@ty.t] method_ty); fn lval_mem(@block_ctxt cx, ValueRef val) -> lval_result { ret rec(res=res(cx, val), is_mem=true, generic=none[generic_info], - llobj=none[ValueRef]); + llobj=none[ValueRef], + method_ty=none[@ty.t]); } fn lval_val(@block_ctxt cx, ValueRef val) -> lval_result { ret rec(res=res(cx, val), is_mem=false, generic=none[generic_info], - llobj=none[ValueRef]); + llobj=none[ValueRef], + method_ty=none[@ty.t]); } fn trans_external_path(@block_ctxt cx, ast.def_id did, @@ -3813,7 +3816,10 @@ fn trans_field(@block_ctxt cx, &ast.span sp, ValueRef v, @ty.t t0, C_int(ix as int))); auto lvo = lval_mem(r.bcx, v); - ret rec(llobj = some[ValueRef](r.val) with lvo); + let @ty.t fn_ty = ty.method_ty_to_fn_ty(methods.(ix)); + ret rec(llobj = some[ValueRef](r.val), + method_ty = some[@ty.t](fn_ty) + with lvo); } case (_) { cx.fcx.ccx.sess.unimpl("field variant in trans_field"); } } @@ -4426,6 +4432,11 @@ fn trans_call(@block_ctxt cx, @ast.expr f, option.t[ValueRef] lliterbody, vec[@ast.expr] args, &ast.ann ann) -> result { + + // NB: 'f' isn't necessarily a function; it might be an entire self-call + // expression because of the hack that allows us to process self-calls + // with trans_call. + auto f_res = trans_lval(cx, f); auto faddr = f_res.res.val; auto llenv = C_null(T_opaque_closure_ptr(cx.fcx.ccx.tn)); @@ -4449,7 +4460,21 @@ fn trans_call(@block_ctxt cx, @ast.expr f, llenv = bcx.build.Load(llclosure); } } - auto fn_ty = ty.expr_ty(f); + + let @ty.t fn_ty; + alt (f_res.method_ty) { + case (some[@ty.t](?meth)) { + // self-call + fn_ty = meth; + } + + case (_) { + fn_ty = ty.expr_ty(f); + + } + + } + auto ret_ty = ty.ann_to_type(ann); auto args_res = trans_args(f_res.res.bcx, llenv, f_res.llobj, diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 24bd647f..f83bece7 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -26,6 +26,12 @@ type method = rec(ast.proto proto, type mt = rec(@t ty, ast.mutability mut); +// Convert from method type to function type. Pretty easy; we just drop +// 'ident'. +fn method_ty_to_fn_ty(method m) -> @ty.t { + ret plain_ty(ty_fn(m.proto, m.inputs, m.output)); +} + // NB: If you change this, you'll probably want to change the corresponding // AST structure in front/ast.rs as well. type t = rec(sty struct, option.t[str] cname); -- cgit v1.2.3 From 86d4601827812b4b069e44feec1b1ea64cd34f4e Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Mon, 4 Apr 2011 14:31:49 -0700 Subject: More work on typestate. Sketched out code for computing and checking prestates and poststates. Still a long ways away. --- src/comp/middle/typeck.rs | 39 ++- src/comp/middle/typestate_check.rs | 518 ++++++++++++++++++++++++++++++++----- src/comp/rustc.rc | 2 + src/comp/util/typestate_ann.rs | 29 ++- 4 files changed, 508 insertions(+), 80 deletions(-) (limited to 'src') diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index e105c7a9..ab0262f1 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -23,6 +23,7 @@ import middle.ty.ty_to_str; import middle.ty.type_is_integral; import middle.ty.type_is_scalar; import middle.ty.ty_params_opt_and_ty; +import middle.ty.ty_nil; import std._str; import std._uint; @@ -62,6 +63,12 @@ fn triv_ann(@ty.t t) -> ann { ret ast.ann_type(t, none[vec[@ty.t]], none[@ts_ann]); } +// Used to fill in the annotation for things that have uninteresting +// types +fn boring_ann() -> ann { + ret triv_ann(plain_ty(ty_nil)); +} + // Replaces parameter types inside a type with type variables. fn generalize_ty(@crate_ctxt cx, @ty.t t) -> @ty.t { state obj ty_generalizer(@crate_ctxt cx, @@ -1361,7 +1368,7 @@ fn demand_expr_full(&@fn_ctxt fcx, @ty.t expected, @ast.expr e, ann_to_type(ann), adk); e_1 = ast.expr_ext(p, args, body, expanded, triv_ann(t)); } - /* FIXME: this should probably check the type annotations */ + /* FIXME: should this check the type annotations? */ case (ast.expr_fail(_)) { e_1 = e.node; } case (ast.expr_log(_,_)) { e_1 = e.node; } case (ast.expr_break(_)) { e_1 = e.node; } @@ -1771,16 +1778,19 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr { ann)); } - case (ast.expr_fail(_)) { // ??? ignoring ann - ret expr; + case (ast.expr_fail(_)) { + ret @fold.respan[ast.expr_](expr.span, + ast.expr_fail(boring_ann())); } case (ast.expr_break(_)) { - ret expr; + ret @fold.respan[ast.expr_](expr.span, + ast.expr_break(boring_ann())); } case (ast.expr_cont(_)) { - ret expr; + ret @fold.respan[ast.expr_](expr.span, + ast.expr_cont(boring_ann())); } case (ast.expr_ret(?expr_opt, _)) { @@ -1792,14 +1802,16 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr { + "returning non-nil"); } - ret expr; + ret @fold.respan[ast.expr_] + (expr.span, + ast.expr_ret(none[@ast.expr], boring_ann())); } case (some[@ast.expr](?e)) { auto expr_0 = check_expr(fcx, e); auto expr_1 = demand_expr(fcx, fcx.ret_ty, expr_0); ret @fold.respan[ast.expr_] - (expr.span, ast.expr_ret(some(expr_1), ann_none)); + (expr.span, ast.expr_ret(some(expr_1), boring_ann())); } } } @@ -1813,14 +1825,16 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr { + "putting non-nil"); } - ret expr; + ret @fold.respan[ast.expr_] + (expr.span, ast.expr_put(none[@ast.expr], + boring_ann())); } case (some[@ast.expr](?e)) { auto expr_0 = check_expr(fcx, e); auto expr_1 = demand_expr(fcx, fcx.ret_ty, expr_0); ret @fold.respan[ast.expr_] - (expr.span, ast.expr_put(some(expr_1), ann_none)); + (expr.span, ast.expr_put(some(expr_1), boring_ann())); } } } @@ -1831,20 +1845,21 @@ fn check_expr(&@fn_ctxt fcx, @ast.expr expr) -> @ast.expr { auto expr_0 = check_expr(fcx, e); auto expr_1 = demand_expr(fcx, fcx.ret_ty, expr_0); ret @fold.respan[ast.expr_](expr.span, - ast.expr_be(expr_1, ann_none)); + ast.expr_be(expr_1, + boring_ann())); } case (ast.expr_log(?e,_)) { auto expr_t = check_expr(fcx, e); ret @fold.respan[ast.expr_] - (expr.span, ast.expr_log(expr_t, ann_none)); + (expr.span, ast.expr_log(expr_t, boring_ann())); } case (ast.expr_check_expr(?e, _)) { auto expr_t = check_expr(fcx, e); demand(fcx, expr.span, plain_ty(ty.ty_bool), expr_ty(expr_t)); ret @fold.respan[ast.expr_] - (expr.span, ast.expr_check_expr(expr_t, ann_none)); + (expr.span, ast.expr_check_expr(expr_t, boring_ann())); } case (ast.expr_assign(?lhs, ?rhs, _)) { diff --git a/src/comp/middle/typestate_check.rs b/src/comp/middle/typestate_check.rs index 361d70ae..295c4f1b 100644 --- a/src/comp/middle/typestate_check.rs +++ b/src/comp/middle/typestate_check.rs @@ -20,6 +20,8 @@ import front.ast.expr; import front.ast.expr_call; import front.ast.expr_path; import front.ast.expr_log; +import front.ast.expr_block; +import front.ast.expr_lit; import front.ast.path; import front.ast.crate_directive; import front.ast.fn_decl; @@ -42,6 +44,12 @@ import front.ast.ann_none; import front.ast.ann_type; import front.ast._obj; import front.ast._mod; +import front.ast.crate; +import front.ast.module; +import front.ast.mod_index_entry; +import front.ast.mie_item; +import front.ast.item_fn; +import front.ast.def_local; import middle.fold; import middle.fold.respan; @@ -50,6 +58,7 @@ import util.common; import util.common.span; import util.common.spanned; import util.common.new_str_hash; +import util.common.new_def_hash; import util.typestate_ann; import util.typestate_ann.ts_ann; import util.typestate_ann.empty_pre_post; @@ -57,9 +66,14 @@ import util.typestate_ann.true_precond; import util.typestate_ann.true_postcond; import util.typestate_ann.postcond; import util.typestate_ann.precond; +import util.typestate_ann.poststate; +import util.typestate_ann.prestate; import util.typestate_ann.pre_and_post; import util.typestate_ann.get_pre; import util.typestate_ann.get_post; +import util.typestate_ann.implies; +import util.typestate_ann.pre_and_post_state; +import util.typestate_ann.empty_states; import middle.ty; import middle.ty.ann_to_type; @@ -91,6 +105,8 @@ import std.list.cons; import std.list.nil; import std.list.foldl; import std.list.find; +import std._uint; +import std.bitv; import util.typestate_ann; import util.typestate_ann.difference; @@ -98,21 +114,134 @@ import util.typestate_ann.union; import util.typestate_ann.pps_len; import util.typestate_ann.require_and_preserve; -/**********************************************************************/ -/* mapping from variable name to bit number */ -type fn_info = std.map.hashmap[ident, uint]; +/**** debugging junk ****/ +fn log_expr(@expr e) -> () { + let str_writer s = string_writer(); + auto out_ = mkstate(s.get_writer(), 80u); + auto out = @rec(s=out_, + comments=option.none[vec[front.lexer.cmnt]], + mutable cur_cmnt=0u); + + print_expr(out, e); + log(s.get_str()); +} + +fn log_cond(vec[uint] v) -> () { + auto res = ""; + for (uint i in v) { + if (i == 0u) { + res += "0"; + } + else { + res += "1"; + } + } + log(res); +} +fn log_pp(&pre_and_post pp) -> () { + auto p1 = bitv.to_vec(pp.precondition); + auto p2 = bitv.to_vec(pp.postcondition); + log("pre:"); + log_cond(p1); + log("post:"); + log_cond(p2); +} -fn bit_num(ident v, fn_info m) -> uint { +fn print_ident(&ident i) -> () { + log(" " + i + " "); +} + +fn print_idents(vec[ident] idents) -> () { + if(len[ident](idents) == 0u) { + ret; + } + else { + log("an ident: " + pop[ident](idents)); + print_idents(idents); + } +} +/**********************************************************************/ +/* mapping from variable name (def_id is assumed to be for a local + variable in a given function) to bit number */ +type fn_info = std.map.hashmap[def_id, uint]; +/* mapping from function name to fn_info map */ +type _fn_info_map = std.map.hashmap[def_id, fn_info]; + +fn bit_num(def_id v, fn_info m) -> uint { + check (m.contains_key(v)); ret m.get(v); } + +fn var_is_local(def_id v, fn_info m) -> bool { + ret (m.contains_key(v)); +} + fn num_locals(fn_info m) -> uint { ret m.size(); } +fn find_locals(_fn f) -> vec[def_id] { + auto res = _vec.alloc[def_id](0u); + + for each (@tup(ident, block_index_entry) p + in f.body.node.index.items()) { + alt (p._1) { + case (ast.bie_local(?loc)) { + res += vec(loc.id); + } + case (_) { } + } + } + + ret res; +} + +fn add_var(def_id v, uint next, fn_info tbl) -> uint { + tbl.insert(v, next); + // log(v + " |-> " + _uint.to_str(next, 10u)); + ret (next + 1u); +} + +/* builds a table mapping each local var defined in f + to a bit number in the precondition/postcondition vectors */ fn mk_fn_info(_fn f) -> fn_info { - ret new_str_hash[uint](); /* FIXME: actually implement this */ + auto res = new_def_hash[uint](); + let uint next = 0u; + let vec[ast.arg] f_args = f.decl.inputs; + + for (ast.arg v in f_args) { + next = add_var(v.id, next, res); + } + + let vec[def_id] locals = find_locals(f); + for (def_id v in locals) { + next = add_var(v, next, res); + } + + ret res; } -/**********************************************************************/ + +/* extends mk_fn_info to an item, side-effecting the map fi from + function IDs to fn_info maps */ +fn mk_fn_info_item_fn(&_fn_info_map fi, &span sp, ident i, &ast._fn f, + vec[ast.ty_param] ty_params, def_id id, ann a) -> @item { + fi.insert(id, mk_fn_info(f)); + ret @respan(sp, item_fn(i, f, ty_params, id, a)); +} + +/* initializes the global fn_info_map (mapping each function ID, including + nested locally defined functions, onto a mapping from local variable name + to bit number) */ +fn mk_f_to_fn_info(@ast.crate c) -> _fn_info_map { + auto res = new_def_hash[fn_info](); + + auto fld = fold.new_identity_fold[_fn_info_map](); + fld = @rec(fold_item_fn = bind mk_fn_info_item_fn(_,_,_,_,_,_,_) with *fld); + fold.fold_crate[_fn_info_map](res, fld, c); + + ret res; +} +/**** Helpers ****/ fn expr_ann(&expr e) -> ann { alt(e.node) { case (ast.expr_vec(_,_,?a)) { @@ -214,8 +343,53 @@ fn expr_ann(&expr e) -> ann { } } -fn expr_pp(&@expr e) -> pre_and_post { - alt (expr_ann(*e)) { +/* returns ann_none if this is the sort + of statement where an ann doesn't make sense */ +fn stmt_ann(&stmt s) -> ann { + alt (s.node) { + case (stmt_decl(?d)) { + alt (d.node) { + case (decl_local(?l)) { + ret l.ann; + } + case (decl_item(?i)) { + ret ann_none; /* ????? */ + } + } + } + case (stmt_expr(?e)) { + ret expr_ann(*e); + } + case (_) { + ret ann_none; + } + } +} + +/* fails if e has no annotation */ +fn expr_pp(&expr e) -> pre_and_post { + alt (expr_ann(e)) { + case (ann_none) { + log "expr_pp: the impossible happened (no annotation)"; + fail; + } + case (ann_type(_, _, ?maybe_pp)) { + alt (maybe_pp) { + case (none[@ts_ann]) { + log "expr_pp: the impossible happened (no pre/post)"; + fail; + } + case (some[@ts_ann](?p)) { + ret p.conditions; + } + } + } + } +} + +/* fails if e has no annotation */ +fn expr_states(&expr e) -> pre_and_post_state { + alt (expr_ann(e)) { case (ann_none) { log "expr_pp: the impossible happened (no annotation)"; fail; @@ -227,7 +401,45 @@ fn expr_pp(&@expr e) -> pre_and_post { fail; } case (some[@ts_ann](?p)) { - ret *p; + ret p.states; + } + } + } + } +} + +/* fails if no annotation */ +fn stmt_pp(&stmt s) -> pre_and_post { + alt (stmt_ann(s)) { + case (ann_none) { + fail; + } + case (ann_type(_, _, ?maybe_pp)) { + alt (maybe_pp) { + case (none[@ts_ann]) { + fail; + } + case (some[@ts_ann](?p)) { + ret p.conditions; + } + } + } + } +} + +/* fails if no annotation */ +fn stmt_states(&stmt s) -> pre_and_post_state { + alt (stmt_ann(s)) { + case (ann_none) { + fail; + } + case (ann_type(_, _, ?maybe_pp)) { + alt (maybe_pp) { + case (none[@ts_ann]) { + fail; + } + case (some[@ts_ann](?p)) { + ret p.states; } } } @@ -235,21 +447,49 @@ fn expr_pp(&@expr e) -> pre_and_post { } fn expr_precond(&expr e) -> precond { - ret (expr_pp(@e)).precondition; + ret (expr_pp(e)).precondition; } -fn expr_postcond(&@expr e) -> postcond { +fn expr_postcond(&expr e) -> postcond { ret (expr_pp(e)).postcondition; } -fn with_pp(ann a, @pre_and_post p) -> ann { +fn expr_prestate(&expr e) -> prestate { + ret (expr_states(e)).prestate; +} + +fn expr_poststate(&expr e) -> poststate { + ret (expr_states(e)).poststate; +} + +fn stmt_precond(&stmt s) -> precond { + ret (stmt_pp(s)).precondition; +} + +fn stmt_postcond(&stmt s) -> postcond { + ret (stmt_pp(s)).postcondition; +} + +fn stmt_prestate(&stmt s) -> prestate { + ret (stmt_states(s)).prestate; +} + +fn stmt_poststate(&stmt s) -> poststate { + ret (stmt_states(s)).poststate; +} + +/* returns a new annotation where the pre_and_post is p */ +fn with_pp(ann a, pre_and_post p) -> ann { alt (a) { case (ann_none) { log("with_pp: the impossible happened"); fail; /* shouldn't happen b/c code is typechecked */ } case (ann_type(?t, ?ps, _)) { - ret (ann_type(t, ps, some[@ts_ann](p))); + ret (ann_type(t, ps, + some[@ts_ann] + (@rec(conditions=p, + states=empty_states(pps_len(p)))))); } } } @@ -276,9 +516,14 @@ fn seq_preconds(uint num_vars, vec[pre_and_post] pps) -> precond { } fn union_postconds_go(postcond first, &vec[postcond] rest) -> postcond { - auto other = rest.(0); - union(first, other); - union_postconds_go(first, slice[postcond](rest, 1u, len[postcond](rest))); + auto sz = _vec.len[postcond](rest); + + if (sz > 0u) { + auto other = rest.(0); + union(first, other); + union_postconds_go(first, slice[postcond](rest, 1u, len[postcond](rest))); + } + ret first; } @@ -288,19 +533,7 @@ fn union_postconds(&vec[postcond] pcs) -> postcond { be union_postconds_go(pcs.(0), pcs); } -fn print_ident(&ident i) -> () { - log(" " + i + " "); -} - -fn print_idents(vec[ident] idents) -> () { - if(len[ident](idents) == 0u) { - ret; - } - else { - log("an ident: " + pop[ident](idents)); - print_idents(idents); - } -} +/******* AST-traversing code ********/ fn find_pre_post_mod(&_mod m) -> _mod { ret m; /* FIXME */ @@ -314,26 +547,29 @@ fn find_pre_post_obj(_obj o) -> _obj { ret o; /* FIXME */ } -impure fn find_pre_post_item(fn_info enclosing, &item i) -> item { +fn find_pre_post_item(_fn_info_map fm, fn_info enclosing, &item i) -> item { alt (i.node) { case (ast.item_const(?id, ?t, ?e, ?di, ?a)) { auto e_pp = find_pre_post_expr(enclosing, *e); + log("1"); ret (respan(i.span, - ast.item_const(id, t, e_pp, di, - with_pp(a, @expr_pp(e_pp))))); + ast.item_const(id, t, e_pp, di, a))); } case (ast.item_fn(?id, ?f, ?ps, ?di, ?a)) { - auto f_pp = find_pre_post_fn(f); + check (fm.contains_key(di)); + auto f_pp = find_pre_post_fn(fm, fm.get(di), f); ret (respan(i.span, ast.item_fn(id, f_pp, ps, di, a))); } case (ast.item_mod(?id, ?m, ?di)) { auto m_pp = find_pre_post_mod(m); + log("3"); ret (respan(i.span, ast.item_mod(id, m_pp, di))); } case (ast.item_native_mod(?id, ?nm, ?di)) { auto n_pp = find_pre_post_native_mod(nm); + log("4"); ret (respan(i.span, ast.item_native_mod(id, n_pp, di))); } @@ -345,17 +581,23 @@ impure fn find_pre_post_item(fn_info enclosing, &item i) -> item { } case (ast.item_obj(?id, ?o, ?ps, ?di, ?a)) { auto o_pp = find_pre_post_obj(o); + log("5"); ret (respan(i.span, ast.item_obj(id, o_pp, ps, di, a))); } } } -impure fn find_pre_post_expr(&fn_info enclosing, &expr e) -> @expr { +fn find_pre_post_expr(&fn_info enclosing, &expr e) -> @expr { auto num_local_vars = num_locals(enclosing); fn do_rand_(fn_info enclosing, &@expr e) -> @expr { - be find_pre_post_expr(enclosing, *e); + log("for rand " ); + log_expr(e); + log("pp = "); + auto res = find_pre_post_expr(enclosing, *e); + log_pp(expr_pp(*res)); + ret res; } auto do_rand = bind do_rand_(enclosing,_); @@ -363,40 +605,78 @@ impure fn find_pre_post_expr(&fn_info enclosing, &expr e) -> @expr { alt(e.node) { case(expr_call(?oper, ?rands, ?a)) { auto pp_oper = find_pre_post_expr(enclosing, *oper); + log("pp_oper ="); + log_pp(expr_pp(*pp_oper)); auto f = do_rand; auto pp_rands = _vec.map[@expr, @expr](f, rands); - auto g = expr_pp; - auto pps = _vec.map[@expr, pre_and_post] - (g, pp_rands); - _vec.push[pre_and_post](pps, expr_pp(pp_oper)); + fn pp_one(&@expr e) -> pre_and_post { + be expr_pp(*e); + } + auto g = pp_one; + auto pps = _vec.map[@expr, pre_and_post](g, pp_rands); + _vec.push[pre_and_post](pps, expr_pp(*pp_oper)); auto h = get_post; auto res_postconds = _vec.map[pre_and_post, postcond](h, pps); auto res_postcond = union_postconds(res_postconds); - let @pre_and_post pp = - @rec(precondition=seq_preconds(num_local_vars, pps), + let pre_and_post pp = + rec(precondition=seq_preconds(num_local_vars, pps), postcondition=res_postcond); let ann a_res = with_pp(a, pp); + log("result for call"); + log_expr(@e); + log("is:"); + log_pp(pp); ret (@respan(e.span, expr_call(pp_oper, pp_rands, a_res))); } case(expr_path(?p, ?maybe_def, ?a)) { - check (len[ident](p.node.idents) > 0u); - auto referent = p.node.idents.(0); - auto i = bit_num(referent, enclosing); + auto df; + alt (maybe_def) { + case (none[def]) + { log("expr_path should have a def"); fail; } + case (some[def](?d)) { df = d; } + } + auto res = empty_pre_post(num_local_vars); - require_and_preserve(i, *res); + + alt (df) { + case (def_local(?d_id)) { + auto i = bit_num(d_id, enclosing); + require_and_preserve(i, res); + } + case (_) { /* nothing to check */ } + } + + // Otherwise, variable is global, so it must be initialized + log("pre/post for:\n"); + log_expr(@e); + log("is"); + log_pp(res); ret (@respan (e.span, expr_path(p, maybe_def, with_pp(a, res)))); } - case(expr_log(?e, ?a)) { - auto e_pp = find_pre_post_expr(enclosing, *e); + case(expr_log(?arg, ?a)) { + log("log"); + auto e_pp = find_pre_post_expr(enclosing, *arg); + log("pre/post for: "); + log_expr(arg); + log("is"); + log_pp(expr_pp(*e_pp)); ret (@respan(e.span, - expr_log(e_pp, with_pp(a, @expr_pp(e_pp))))); + expr_log(e_pp, with_pp(a, expr_pp(*e_pp))))); + } + case (expr_block(?b, ?a)) { + log("block!"); + fail; + } + case (expr_lit(?l, ?a)) { + ret @respan(e.span, + expr_lit(l, with_pp(a, empty_pre_post(num_local_vars)))); } case(_) { log("this sort of expr isn't implemented!"); @@ -405,8 +685,8 @@ impure fn find_pre_post_expr(&fn_info enclosing, &expr e) -> @expr { } } -impure fn find_pre_post_for_each_stmt(&fn_info enclosing, &ast.stmt s) - -> ast.stmt { +fn find_pre_post_for_each_stmt(_fn_info_map fm, &fn_info enclosing, + &ast.stmt s) -> ast.stmt { auto num_local_vars = num_locals(enclosing); alt(s.node) { @@ -418,7 +698,7 @@ impure fn find_pre_post_for_each_stmt(&fn_info enclosing, &ast.stmt s) let @expr r = find_pre_post_expr(enclosing, *an_init.expr); let init_op o = an_init.op; let initializer a_i = rec(op=o, expr=r); - let ann res_ann = with_pp(alocal.ann, @expr_pp(r)); + let ann res_ann = with_pp(alocal.ann, expr_pp(*r)); let @local res_local = @rec(ty=alocal.ty, infer=alocal.infer, ident=alocal.ident, init=some[initializer](a_i), @@ -443,24 +723,26 @@ impure fn find_pre_post_for_each_stmt(&fn_info enclosing, &ast.stmt s) } } case(decl_item(?anitem)) { - auto res_item = find_pre_post_item(enclosing, *anitem); + auto res_item = find_pre_post_item(fm, enclosing, *anitem); ret (respan(s.span, stmt_decl(@respan(adecl.span, decl_item(@res_item))))); } } } case(stmt_expr(?e)) { + log_expr(e); let @expr e_pp = find_pre_post_expr(enclosing, *e); ret (respan(s.span, stmt_expr(e_pp))); } } } -fn find_pre_post_block(fn_info enclosing, block b) -> block { - fn do_one_(fn_info i, &@stmt s) -> @stmt { - ret (@find_pre_post_for_each_stmt(i, *s)); +fn find_pre_post_block(&_fn_info_map fm, &fn_info enclosing, block b) + -> block { + fn do_one_(_fn_info_map fm, fn_info i, &@stmt s) -> @stmt { + ret (@find_pre_post_for_each_stmt(fm, i, *s)); } - auto do_one = bind do_one_(enclosing, _); + auto do_one = bind do_one_(fm, enclosing, _); auto ss = _vec.map[@stmt, @stmt](do_one, b.node.stmts); fn do_inner_(fn_info i, &@expr e) -> @expr { @@ -472,24 +754,134 @@ fn find_pre_post_block(fn_info enclosing, block b) -> block { ret respan(b.span, b_res); } -fn find_pre_post_fn(&_fn f) -> _fn { - let fn_info fi = mk_fn_info(f); +fn find_pre_post_fn(&_fn_info_map fm, &fn_info fi, &_fn f) -> _fn { ret rec(decl=f.decl, proto=f.proto, - body=find_pre_post_block(fi, f.body)); + body=find_pre_post_block(fm, fi, f.body)); } -fn check_item_fn(&@() ignore, &span sp, ident i, &ast._fn f, +fn check_item_fn(&_fn_info_map fm, &span sp, ident i, &ast._fn f, vec[ast.ty_param] ty_params, def_id id, ann a) -> @item { - auto res_f = find_pre_post_fn(f); + check (fm.contains_key(id)); + auto res_f = find_pre_post_fn(fm, fm.get(id), f); ret @respan(sp, ast.item_fn(i, res_f, ty_params, id, a)); } +/* Returns a pair of a new function, with possibly a changed pre- or + post-state, and a boolean flag saying whether the function's pre- or + poststate changed */ +fn find_pre_post_state_fn(fn_info f_info, &ast._fn f) -> tup(bool, ast._fn) { + log ("Implement find_pre_post_state_fn!"); + fail; +} + +fn fixed_point_states(fn_info f_info, + fn (fn_info, &ast._fn) -> tup(bool, ast._fn) f, + &ast._fn start) -> ast._fn { + auto next = f(f_info, start); + + if (next._0) { + // something changed + be fixed_point_states(f_info, f, next._1); + } + else { + // we're done! + ret next._1; + } +} + +fn check_states_expr(fn_info enclosing, &expr e) -> () { + let precond prec = expr_precond(e); + let postcond postc = expr_postcond(e); + let prestate pres = expr_prestate(e); + let poststate posts = expr_poststate(e); + + if (!implies(pres, prec)) { + log("check_states_expr: unsatisfied precondition"); + fail; + } + if (!implies(posts, postc)) { + log("check_states_expr: unsatisfied postcondition"); + fail; + } +} + +fn check_states_stmt(fn_info enclosing, &stmt s) -> () { + alt (stmt_ann(s)) { + case (ann_none) { + // Statement doesn't require an annotation -- do nothing + ret; + } + case (ann_type(_,_,?m_pp)) { + let precond prec = stmt_precond(s); + let postcond postc = stmt_postcond(s); + let prestate pres = stmt_prestate(s); + let poststate posts = stmt_poststate(s); + + if (!implies(pres, prec)) { + log("check_states_stmt: unsatisfied precondition"); + fail; + } + if (!implies(posts, postc)) { + log("check_states_stmt: unsatisfied postcondition"); + fail; + } + } + } +} + +fn check_states_against_conditions(fn_info enclosing, &ast._fn f) -> () { + fn do_one_(fn_info i, &@stmt s) -> () { + check_states_stmt(i, *s); + } + auto do_one = bind do_one_(enclosing, _); + + _vec.map[@stmt, ()](do_one, f.body.node.stmts); + fn do_inner_(fn_info i, &@expr e) -> () { + check_states_expr(i, *e); + } + auto do_inner = bind do_inner_(enclosing, _); + option.map[@expr, ()](do_inner, f.body.node.expr); + +} + +fn check_item_fn_state(&_fn_info_map f_info_map, &span sp, ident i, + &ast._fn f, vec[ast.ty_param] ty_params, def_id id, + ann a) -> @item { + + /* Look up the var-to-bit-num map for this function */ + check(f_info_map.contains_key(id)); + auto f_info = f_info_map.get(id); + + /* Compute the pre- and post-states for this function */ + auto g = find_pre_post_state_fn; + auto res_f = fixed_point_states(f_info, g, f); + + /* Now compare each expr's pre-state to its precondition + and post-state to its postcondition */ + check_states_against_conditions(f_info, res_f); + + /* Rebuild the same function */ + ret @respan(sp, ast.item_fn(i, res_f, ty_params, id, a)); +} + fn check_crate(@ast.crate crate) -> @ast.crate { - auto fld = fold.new_identity_fold[@()](); + /* Build the global map from function id to var-to-bit-num-map */ + auto fn_info_map = mk_f_to_fn_info(crate); + + /* Compute the pre and postcondition for every subexpression */ + auto fld = fold.new_identity_fold[_fn_info_map](); fld = @rec(fold_item_fn = bind check_item_fn(_,_,_,_,_,_,_) with *fld); + auto with_pre_postconditions = fold.fold_crate[_fn_info_map] + (fn_info_map, fld, crate); + + auto fld1 = fold.new_identity_fold[_fn_info_map](); + + fld1 = @rec(fold_item_fn = bind check_item_fn_state(_,_,_,_,_,_,_) + with *fld1); - ret fold.fold_crate[@()](@(), fld, crate); + ret fold.fold_crate[_fn_info_map](fn_info_map, fld1, + with_pre_postconditions); } diff --git a/src/comp/rustc.rc b/src/comp/rustc.rc index 952ea7e8..47a37f33 100644 --- a/src/comp/rustc.rc +++ b/src/comp/rustc.rc @@ -62,6 +62,8 @@ auth middle.typestate_check.log_expr = impure; auth lib.llvm = unsafe; auth pretty.pprust = impure; auth middle.typestate_check.find_pre_post_block = impure; +auth middle.typestate_check.find_pre_post_expr = impure; +auth util.typestate_ann.implies = impure; mod lib { alt (target_os) { diff --git a/src/comp/util/typestate_ann.rs b/src/comp/util/typestate_ann.rs index a4698c5d..071f5513 100644 --- a/src/comp/util/typestate_ann.rs +++ b/src/comp/util/typestate_ann.rs @@ -12,12 +12,21 @@ type precond = bitv.t; /* 1 means "this variable must be initialized" type postcond = bitv.t; /* 1 means "this variable is initialized" 0 means "don't know about this variable */ +type prestate = bitv.t; /* 1 means "this variable is definitely initialized" + 0 means "don't know whether this variable is + initialized" */ +type poststate = bitv.t; /* 1 means "this variable is definitely initialized" + 0 means "don't know whether this variable is + initialized" */ + /* named thus so as not to confuse with prestate and poststate */ type pre_and_post = rec(precond precondition, postcond postcondition); /* FIXME: once it's implemented: */ // : ((*.precondition).nbits == (*.postcondition).nbits); -type ts_ann = pre_and_post; +type pre_and_post_state = rec(prestate prestate, poststate poststate); + +type ts_ann = rec(pre_and_post conditions, pre_and_post_state states); fn true_precond(uint num_vars) -> precond { be bitv.create(num_vars, false); @@ -27,11 +36,16 @@ fn true_postcond(uint num_vars) -> postcond { be true_precond(num_vars); } -fn empty_pre_post(uint num_vars) -> @pre_and_post { - ret(@rec(precondition=true_precond(num_vars), +fn empty_pre_post(uint num_vars) -> pre_and_post { + ret(rec(precondition=true_precond(num_vars), postcondition=true_postcond(num_vars))); } +fn empty_states(uint num_vars) -> pre_and_post_state { + ret(rec(prestate=true_precond(num_vars), + poststate=true_postcond(num_vars))); +} + fn get_pre(&pre_and_post p) -> precond { ret p.precondition; } @@ -57,5 +71,10 @@ fn pps_len(&pre_and_post p) -> uint { impure fn require_and_preserve(uint i, &pre_and_post p) -> () { // sets the ith bit in p's pre and post bitv.set(p.precondition, i, true); - bitv.set(p.postcondition, i, false); -} \ No newline at end of file + bitv.set(p.postcondition, i, true); +} + +fn implies(bitv.t a, bitv.t b) -> bool { + bitv.difference(b, a); + ret (bitv.equal(b, bitv.create(b.nbits, false))); +} -- cgit v1.2.3 From 83829906274f643a75623f1f32f3f04ecbaeb5e5 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Tue, 5 Apr 2011 17:11:43 -0700 Subject: Add new minimal test for current blocker on bootstrapping. --- src/test/run-pass/tag-and-generic-obj.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/test/run-pass/tag-and-generic-obj.rs (limited to 'src') diff --git a/src/test/run-pass/tag-and-generic-obj.rs b/src/test/run-pass/tag-and-generic-obj.rs new file mode 100644 index 00000000..2098d1d0 --- /dev/null +++ b/src/test/run-pass/tag-and-generic-obj.rs @@ -0,0 +1,12 @@ +// xfail-stage0 + +tag colour { red; green; } + +obj foo[T]() { + fn meth(&T x) { + } +} + +fn main() { + foo[colour]().meth(red); +} \ No newline at end of file -- cgit v1.2.3 From 52abd912c06f57a410af7c6b59a78b772ac44368 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Tue, 5 Apr 2011 21:08:13 -0700 Subject: Brute force and ignorance workaround for tag-and-generic-obj; un-XFAIL it. --- src/comp/middle/trans.rs | 3 +++ src/test/run-pass/tag-and-generic-obj.rs | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 6fcd7b37..980c88db 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -4409,6 +4409,9 @@ fn trans_args(@block_ctxt cx, } } + val = bcx.build.PointerCast(val, lldestty); + } else if (mode == ast.alias) { + auto lldestty = arg_tys.(i); val = bcx.build.PointerCast(val, lldestty); } diff --git a/src/test/run-pass/tag-and-generic-obj.rs b/src/test/run-pass/tag-and-generic-obj.rs index 2098d1d0..dbbc212e 100644 --- a/src/test/run-pass/tag-and-generic-obj.rs +++ b/src/test/run-pass/tag-and-generic-obj.rs @@ -1,5 +1,3 @@ -// xfail-stage0 - tag colour { red; green; } obj foo[T]() { -- cgit v1.2.3 From 5e98cd94722bd69fd70606ed83c60dcd54d5e61e Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Wed, 6 Apr 2011 04:18:12 +0000 Subject: Remove reference to nonexistent ast.module from typestate_check.rs, stage1 doesn't like it. --- src/comp/middle/typestate_check.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/comp/middle/typestate_check.rs b/src/comp/middle/typestate_check.rs index 295c4f1b..64a17a7d 100644 --- a/src/comp/middle/typestate_check.rs +++ b/src/comp/middle/typestate_check.rs @@ -45,7 +45,6 @@ import front.ast.ann_type; import front.ast._obj; import front.ast._mod; import front.ast.crate; -import front.ast.module; import front.ast.mod_index_entry; import front.ast.mie_item; import front.ast.item_fn; -- cgit v1.2.3 From 36d75d6391873b34a1f4e10c34d3d58c54a453c5 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Wed, 6 Apr 2011 08:32:58 -0700 Subject: Minimal testcase for next bootstrap blocker. --- src/test/run-pass/lib-option.rs | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/test/run-pass/lib-option.rs (limited to 'src') diff --git a/src/test/run-pass/lib-option.rs b/src/test/run-pass/lib-option.rs new file mode 100644 index 00000000..5add8dbd --- /dev/null +++ b/src/test/run-pass/lib-option.rs @@ -0,0 +1,6 @@ +// xfail-stage0 +use std; + +fn main() { + auto x = std.option.some[int](10); +} \ No newline at end of file -- cgit v1.2.3