integrate simple notion of borrowing into trans

This commit is contained in:
Niko Matsakis 2012-04-13 19:07:47 -07:00
parent 378996092e
commit 247db704a9
5 changed files with 85 additions and 23 deletions

View File

@ -844,6 +844,7 @@ impl assignment for infer_ctxt {
sub(self).contraregions(r_a, r_b).chain {|_r|
// if successful, add an entry indicating that
// borrowing occurred
#debug["borrowing expression #%?", a_node_id];
self.tcx.borrowings.insert(a_node_id, ());
uok()
}

View File

@ -313,8 +313,8 @@ fn shared_malloc(cx: block, llptr_ty: TypeRef, llsize: ValueRef)
//
// The runtime equivalent is box_body() in "rust_internal.h".
fn opaque_box_body(bcx: block,
body_t: ty::t,
boxptr: ValueRef) -> ValueRef {
body_t: ty::t,
boxptr: ValueRef) -> ValueRef {
let _icx = bcx.insn_ctxt("opaque_box_body");
let ccx = bcx.ccx();
let boxptr = PointerCast(bcx, boxptr, T_ptr(T_box_header(ccx)));
@ -2323,6 +2323,10 @@ fn trans_index(cx: block, ex: @ast::expr, base: @ast::expr,
ret lval_owned(bcx, PointerCast(bcx, elt, T_ptr(llunitty)));
}
fn expr_is_borrowed(bcx: block, e: @ast::expr) -> bool {
bcx.tcx().borrowings.contains_key(e.id)
}
fn expr_is_lval(bcx: block, e: @ast::expr) -> bool {
let ccx = bcx.ccx();
ty::expr_is_lval(ccx.maps.method_map, e)
@ -2553,6 +2557,7 @@ fn trans_arg_expr(cx: block, arg: ty::arg, lldestty: TypeRef, e: @ast::expr,
}
none { trans_temp_lval(cx, e) }
};
let lv = adapt_borrowed_value(lv, arg, e);
let mut bcx = lv.bcx;
let mut val = lv.val;
let arg_mode = ty::resolved_mode(ccx.tcx, arg.mode);
@ -2611,6 +2616,58 @@ fn trans_arg_expr(cx: block, arg: ty::arg, lldestty: TypeRef, e: @ast::expr,
ret rslt(bcx, val);
}
fn adapt_borrowed_value(lv: lval_result, arg: ty::arg,
e: @ast::expr) -> lval_result {
let bcx = lv.bcx;
if !expr_is_borrowed(bcx, e) { ret lv; }
let e_ty = expr_ty(bcx, e);
alt ty::get(e_ty).struct {
ty::ty_box(mt) {
let box_ptr = {
alt lv.kind {
temporary { lv.val }
owned { Load(bcx, lv.val) }
owned_imm { lv.val }
}
};
let body_ptr = GEPi(bcx, box_ptr, [0, abi::box_field_body]);
ret lval_temp(bcx, body_ptr);
}
ty::ty_uniq(_) {
ret lv; // no change needed at runtime (I think)
}
ty::ty_estr(ty::vstore_box) |
ty::ty_evec(_, ty::vstore_box) {
bcx.tcx().sess.span_unimpl(
e.span, #fmt["borrowing a value of type %s",
ty_to_str(bcx.tcx(), e_ty)]);
}
ty::ty_estr(ty::vstore_uniq) |
ty::ty_evec(_, ty::vstore_uniq) {
bcx.tcx().sess.span_unimpl(
e.span, #fmt["borrowing a value of type %s",
ty_to_str(bcx.tcx(), e_ty)]);
}
ty::ty_estr(ty::vstore_fixed(_)) |
ty::ty_evec(_, ty::vstore_fixed(_)) {
bcx.tcx().sess.span_unimpl(
e.span, #fmt["borrowing a value of type %s",
ty_to_str(bcx.tcx(), e_ty)]);
}
_ {
bcx.tcx().sess.span_bug(
e.span, #fmt["cannot borrow a value of type %s",
ty_to_str(bcx.tcx(), e_ty)]);
}
}
}
enum call_args {
arg_exprs([@ast::expr]),
arg_vals([ValueRef])
@ -3006,7 +3063,12 @@ fn trans_expr_save_in(bcx: block, e: @ast::expr, dest: ValueRef)
fn trans_temp_lval(bcx: block, e: @ast::expr) -> lval_result {
let _icx = bcx.insn_ctxt("trans_temp_lval");
let mut bcx = bcx;
if expr_is_lval(bcx, e) {
if expr_is_lval(bcx, e) && !expr_is_borrowed(bcx, e) {
// if the expression is borrowed, then are not actually passing the
// lvalue itself, but rather an adaptation of it. This is a bit of a
// hack, though, but it only needs to exist so long as we have
// reference modes and the like---otherwise, all potentially borrowed
// things will go directly through trans_expr() as they ought to.
ret trans_lval(bcx, e);
} else {
let ty = expr_ty(bcx, e);
@ -3047,12 +3109,6 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block {
let tcx = bcx.tcx();
debuginfo::update_source_pos(bcx, e.span);
#debug["trans_expr(e=%s,e.id=%d,dest=%s,ty=%s)",
expr_to_str(e),
e.id,
dest_str(bcx.ccx(), dest),
ty_to_str(tcx, expr_ty(bcx, e))];
if expr_is_lval(bcx, e) {
ret lval_to_dps(bcx, e, dest);
}
@ -3264,9 +3320,10 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block {
let bcx = trans_expr(bcx, val, save_in(ptr_val));
store_in_dest(bcx, ptr_val, dest)
}
_ { bcx.tcx().sess.span_bug(e.span, "trans_expr reached \
fall-through case"); }
_ {
bcx.tcx().sess.span_bug(e.span, "trans_expr reached \
fall-through case");
}
}
}

View File

@ -875,6 +875,13 @@ pure fn type_is_boxed(ty: t) -> bool {
}
}
pure fn type_is_region_ptr(ty: t) -> bool {
alt get(ty).struct {
ty_rptr(_, _) { true }
_ { false }
}
}
pure fn type_is_slice(ty: t) -> bool {
alt get(ty).struct {
ty_evec(_, vstore_slice(_)) | ty_estr(vstore_slice(_)) { true }
@ -924,7 +931,7 @@ pure fn type_is_scalar(ty: t) -> bool {
// FIXME maybe inline this for speed?
fn type_is_immediate(ty: t) -> bool {
ret type_is_scalar(ty) || type_is_boxed(ty) ||
type_is_unique(ty);
type_is_unique(ty) || type_is_region_ptr(ty);
}
fn type_needs_drop(cx: ctxt, ty: t) -> bool {

View File

@ -2581,7 +2581,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
// A generic function to factor out common logic from call and bind
// expressions.
fn check_call_or_bind(
fcx: @fn_ctxt, sp: span, call_expr_id: ast::node_id, fty: ty::t,
fcx: @fn_ctxt, sp: span, fty: ty::t,
args: [option<@ast::expr>]) -> {fty: ty::t, bot: bool} {
let fty = universally_quantify_before_call(fcx, region_env(), fty);
@ -2680,8 +2680,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
// Call the generic checker.
let fty = {
let args_opt = args.map { |arg| some(arg) };
let r = check_call_or_bind(fcx, sp, call_expr_id,
fn_ty, args_opt);
let r = check_call_or_bind(fcx, sp, fn_ty, args_opt);
bot |= r.bot;
r.fty
};
@ -2762,8 +2761,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
some(origin) {
let {fty: method_ty, bot: bot} = {
let method_ty = fcx.node_ty(callee_id);
check_call_or_bind(fcx, op_ex.span, op_ex.id,
method_ty, args)
check_call_or_bind(fcx, op_ex.span, method_ty, args)
};
fcx.ccx.method_map.insert(op_ex.id, origin);
some((ty::ty_fn_ret(method_ty), bot))
@ -3194,7 +3192,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
let {fty, bot: ccob_bot} = {
let fn_ty = fcx.expr_ty(f);
check_call_or_bind(fcx, expr.span, expr.id, fn_ty, args)
check_call_or_bind(fcx, expr.span, fn_ty, args)
};
bot |= ccob_bot;

View File

@ -1,11 +1,10 @@
// xfail-test it don't work yet
fn foo(x: &uint) -> uint {
*x
}
fn main() {
let p = @3u;
let p = @22u;
let r = foo(p);
assert r == 3u;
#debug["r=%u", r];
assert r == 22u;
}