From 247db704a97d36fa1bbf27a67295391045e661ac Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 13 Apr 2012 19:07:47 -0700 Subject: [PATCH] integrate simple notion of borrowing into trans --- src/rustc/middle/infer.rs | 1 + src/rustc/middle/trans/base.rs | 81 ++++++++++++++++++++++---- src/rustc/middle/ty.rs | 9 ++- src/rustc/middle/typeck.rs | 10 ++-- src/test/run-pass/regions-borrow-at.rs | 7 +-- 5 files changed, 85 insertions(+), 23 deletions(-) diff --git a/src/rustc/middle/infer.rs b/src/rustc/middle/infer.rs index 513cd524d72b..6e48fb2f112f 100644 --- a/src/rustc/middle/infer.rs +++ b/src/rustc/middle/infer.rs @@ -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() } diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index 92fad70a642f..7b6c5450eedb 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -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"); + } } } diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index d5a3169f1b5c..0210edb60fb2 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -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 { diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs index 49c2b0adc38d..77e2dfcb44c8 100644 --- a/src/rustc/middle/typeck.rs +++ b/src/rustc/middle/typeck.rs @@ -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; diff --git a/src/test/run-pass/regions-borrow-at.rs b/src/test/run-pass/regions-borrow-at.rs index 73007014665a..18c7222dfa64 100644 --- a/src/test/run-pass/regions-borrow-at.rs +++ b/src/test/run-pass/regions-borrow-at.rs @@ -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; }