Saner approach to lvalues and callable values in trans

LValues no longer carry information about generics and objs, instead
there's an extended form of lvalue, lval_maybe_callee, only used by
call and bind, which holds this info.

This makes it possible to take the value of a method and get a working
closure, and will (with some more work) allow us to call statically
known functions without loading from their pair.

Closes #435
Closes #758
This commit is contained in:
Marijn Haverbeke 2011-09-16 16:27:34 +02:00
parent d9c664e3fa
commit 575aae407b
3 changed files with 220 additions and 197 deletions

View File

@ -2048,7 +2048,7 @@ fn copy_val_no_check(cx: @block_ctxt, action: copy_action, dst: ValueRef,
// doesn't need to be dropped.
fn move_val(cx: @block_ctxt, action: copy_action, dst: ValueRef,
src: lval_result, t: ty::t) -> @block_ctxt {
let src_val = src.res.val;
let src_val = src.val;
let tcx = bcx_tcx(cx);
if ty::type_is_scalar(tcx, t) || ty::type_is_native(tcx, t) {
if src.is_mem { src_val = Load(cx, src_val); }
@ -2060,7 +2060,7 @@ fn move_val(cx: @block_ctxt, action: copy_action, dst: ValueRef,
if src.is_mem { src_val = Load(cx, src_val); }
if action == DROP_EXISTING { cx = drop_ty(cx, dst, t); }
Store(cx, src_val, dst);
if src.is_mem { ret zero_alloca(cx, src.res.val, t).bcx; }
if src.is_mem { ret zero_alloca(cx, src.val, t).bcx; }
// If we're here, it must be a temporary.
ret revoke_clean(cx, src_val, t);
@ -2083,7 +2083,7 @@ fn move_val_if_temp(cx: @block_ctxt, action: copy_action, dst: ValueRef,
// Lvals in memory are not temporaries. Copy them.
if src.is_mem {
ret copy_val(cx, action, dst, load_if_immediate(cx, src.res.val, t),
ret copy_val(cx, action, dst, load_if_immediate(cx, src.val, t),
t);
}
ret move_val(cx, action, dst, src, t);
@ -2165,8 +2165,8 @@ fn trans_unary(cx: @block_ctxt, op: ast::unop, e: @ast::expr,
}
ast::box(_) {
let lv = trans_lval(cx, e);
let box_ty = node_id_type(bcx_ccx(lv.res.bcx), id);
let sub = trans_malloc_boxed(lv.res.bcx, e_ty);
let box_ty = node_id_type(bcx_ccx(lv.bcx), id);
let sub = trans_malloc_boxed(lv.bcx, e_ty);
let body = sub.body;
add_clean_temp(cx, sub.box, box_ty);
@ -2562,7 +2562,7 @@ fn build_environment(bcx: @block_ctxt, lltydescs: [ValueRef],
bcx = bound.bcx;
if copying {
bcx = move_val_if_temp(bcx, INIT, bound.val, lv, bound_tys[i]);
} else { Store(bcx, lv.res.val, bound.val); }
} else { Store(bcx, lv.val, bound.val); }
i += 1u;
}
@ -2766,8 +2766,8 @@ fn trans_for_each(cx: @block_ctxt, local: @ast::local, seq: @ast::expr,
ast::expr_call(f, args) {
let pair =
create_real_fn_pair(cx, iter_body_llty, lliterbody, llenv.ptr);
r = trans_call(cx, f, some(pair), args, seq.id).res;
ret rslt(r.bcx, C_nil());
let r = trans_call(cx, f, some(pair), args, seq.id);
ret rslt(r.res.bcx, C_nil());
}
}
}
@ -2813,24 +2813,26 @@ type generic_info =
static_tis: [option::t<@tydesc_info>],
tydescs: [ValueRef]};
type lval_result =
{res: result,
is_mem: bool,
generic: option::t<generic_info>,
llobj: option::t<ValueRef>};
type lval_result = {bcx: @block_ctxt,
val: ValueRef,
is_mem: bool};
tag callee_env { some_env(ValueRef); null_env; is_closure; }
type lval_maybe_callee = {bcx: @block_ctxt,
val: ValueRef,
is_mem: bool,
env: callee_env,
generic: option::t<generic_info>};
fn lval_mem(cx: @block_ctxt, val: ValueRef) -> lval_result {
ret {res: rslt(cx, val),
is_mem: true,
generic: none::<generic_info>,
llobj: none::<ValueRef>};
fn lval_mem(bcx: @block_ctxt, val: ValueRef) -> lval_result {
ret {bcx: bcx, val: val, is_mem: true};
}
fn lval_val(bcx: @block_ctxt, val: ValueRef) -> lval_result {
ret {bcx: bcx, val: val, is_mem: false};
}
fn lval_val(cx: @block_ctxt, val: ValueRef) -> lval_result {
ret {res: rslt(cx, val),
is_mem: false,
generic: none::<generic_info>,
llobj: none::<ValueRef>};
fn lval_no_env(bcx: @block_ctxt, val: ValueRef, is_mem: bool)
-> lval_maybe_callee {
ret {bcx: bcx, val: val, is_mem: is_mem, env: is_closure, generic: none};
}
fn trans_external_path(cx: @block_ctxt, did: ast::def_id,
@ -2841,35 +2843,31 @@ fn trans_external_path(cx: @block_ctxt, did: ast::def_id,
type_of_ty_param_kinds_and_ty(lcx, cx.sp, tpt));
}
fn lval_generic_fn(cx: @block_ctxt, tpt: ty::ty_param_kinds_and_ty,
fn_id: ast::def_id, id: ast::node_id) -> lval_result {
let lv;
if fn_id.crate == ast::local_crate {
fn lval_static_fn(bcx: @block_ctxt, tpt: ty::ty_param_kinds_and_ty,
fn_id: ast::def_id, id: ast::node_id) -> lval_maybe_callee {
let val = if fn_id.crate == ast::local_crate {
// Internal reference.
assert (bcx_ccx(cx).fn_pairs.contains_key(fn_id.node));
lv = lval_val(cx, bcx_ccx(cx).fn_pairs.get(fn_id.node));
assert (bcx_ccx(bcx).fn_pairs.contains_key(fn_id.node));
bcx_ccx(bcx).fn_pairs.get(fn_id.node)
} else {
// External reference.
lv = lval_val(cx, trans_external_path(cx, fn_id, tpt));
}
let tys = ty::node_id_to_type_params(bcx_tcx(cx), id);
trans_external_path(bcx, fn_id, tpt)
};
let tys = ty::node_id_to_type_params(bcx_tcx(bcx), id);
let gen = none;
if std::vec::len::<ty::t>(tys) != 0u {
let bcx = lv.res.bcx;
let tydescs: [ValueRef] = [];
let tis: [option::t<@tydesc_info>] = [];
for t: ty::t in tys {
let tydescs = [], tis = [];
for t in tys {
// TODO: Doesn't always escape.
let ti = none::<@tydesc_info>;
let ti = none;
let td = get_tydesc(bcx, t, true, tps_normal, ti).result;
tis += [ti];
bcx = td.bcx;
tydescs += [td.val];
}
let gen = {item_type: tpt.ty, static_tis: tis, tydescs: tydescs};
lv = {res: rslt(bcx, lv.res.val), generic: some(gen) with lv};
gen = some({item_type: tpt.ty, static_tis: tis, tydescs: tydescs});
}
ret lv;
ret {bcx: bcx, val: val, is_mem: true, env: is_closure, generic: gen};
}
fn lookup_discriminant(lcx: @local_ctxt, vid: ast::def_id) -> ValueRef {
@ -2922,21 +2920,25 @@ fn trans_local_var(cx: @block_ctxt, def: ast::def) -> lval_result {
}
}
fn trans_var(cx: @block_ctxt, sp: span, def: ast::def, id: ast::node_id) ->
lval_result {
fn trans_path(cx: @block_ctxt, p: ast::path, id: ast::node_id)
-> lval_maybe_callee {
ret trans_var(cx, p.span, bcx_tcx(cx).def_map.get(id), id);
}
fn trans_var(cx: @block_ctxt, sp: span, def: ast::def, id: ast::node_id)
-> lval_maybe_callee {
let ccx = bcx_ccx(cx);
alt def {
ast::def_fn(did, _) | ast::def_native_fn(did) {
let tyt = ty::lookup_item_type(ccx.tcx, did);
ret lval_generic_fn(cx, tyt, did, id);
ret lval_static_fn(cx, tyt, did, id);
}
ast::def_variant(tid, vid) {
let v_tyt = ty::lookup_item_type(ccx.tcx, vid);
alt ty::struct(ccx.tcx, v_tyt.ty) {
ty::ty_fn(_, _, _, _, _) {
// N-ary variant.
ret lval_generic_fn(cx, v_tyt, vid, id);
ret lval_static_fn(cx, v_tyt, vid, id);
}
_ {
// Nullary variant.
@ -2952,43 +2954,44 @@ fn trans_var(cx: @block_ctxt, sp: span, def: ast::def, id: ast::node_id) ->
let lldiscrimptr = GEP(bcx, lltagptr, [C_int(0), C_int(0)]);
Store(bcx, lldiscrim, lldiscrimptr);
}
ret lval_val(bcx, lltagptr);
ret lval_no_env(bcx, lltagptr, false);
}
}
}
ast::def_const(did) {
if did.crate == ast::local_crate {
assert (ccx.consts.contains_key(did.node));
ret lval_mem(cx, ccx.consts.get(did.node));
ret lval_no_env(cx, ccx.consts.get(did.node), true);
} else {
let tp = ty::node_id_to_monotype(ccx.tcx, id);
let k: [ast::kind] = [];
ret lval_val(cx,
load_if_immediate(cx,
trans_external_path(cx, did,
{kinds: k,
ty: tp}),
tp));
let val = trans_external_path(cx, did, {kinds: k, ty: tp});
ret lval_no_env(cx, load_if_immediate(cx, val, tp), false);
}
}
_ { ret trans_local_var(cx, def); }
_ {
let loc = trans_local_var(cx, def);
ret lval_no_env(loc.bcx, loc.val, loc.is_mem);
}
}
}
fn trans_path(cx: @block_ctxt, p: ast::path, id: ast::node_id) ->
lval_result {
ret trans_var(cx, p.span, bcx_tcx(cx).def_map.get(id), id);
fn trans_field(cx: @block_ctxt, sp: span, base: @ast::expr,
field: ast::ident) -> lval_maybe_callee {
let {bcx, val} = trans_expr(cx, base);
ret trans_field_inner(bcx, sp, val, ty::expr_ty(bcx_tcx(cx), base),
field);
}
fn trans_field(cx: @block_ctxt, sp: span, v: ValueRef, t0: ty::t,
field: ast::ident) -> lval_result {
fn trans_field_inner(cx: @block_ctxt, sp: span, v: ValueRef, t0: ty::t,
field: ast::ident) -> lval_maybe_callee {
let r = autoderef(cx, v, t0);
let t = r.ty;
alt ty::struct(bcx_tcx(cx), t) {
ty::ty_rec(fields) {
let ix: uint = ty::field_idx(bcx_ccx(cx).sess, sp, field, fields);
let v = GEP_tup_like(r.bcx, t, r.val, [0, ix as int]);
ret lval_mem(v.bcx, v.val);
ret lval_no_env(v.bcx, v.val, true);
}
ty::ty_obj(methods) {
let ix: uint = ty::method_idx(bcx_ccx(cx).sess, sp, field, methods);
@ -3012,9 +3015,9 @@ fn trans_field(cx: @block_ctxt, sp: span, v: ValueRef, t0: ty::t,
type_of_fn(ccx, sp, ty::ty_fn_proto(tcx, fn_ty),
true, ret_ref, ty::ty_fn_args(tcx, fn_ty),
ret_ty, 0u);
v = PointerCast(r.bcx, v, T_ptr(T_ptr(ll_fn_ty)));
let lvo = lval_mem(r.bcx, v);
ret {llobj: some::<ValueRef>(r.val) with lvo};
v = Load(r.bcx, PointerCast(r.bcx, v, T_ptr(T_ptr(ll_fn_ty))));
ret {bcx: r.bcx, val: v, is_mem: true,
env: some_env(r.val), generic: none};
}
_ { bcx_ccx(cx).sess.unimpl("field variant in trans_field"); }
}
@ -3069,16 +3072,38 @@ fn trans_index(cx: @block_ctxt, sp: span, base: @ast::expr, idx: @ast::expr,
ret lval_mem(next_cx, elt);
}
// The additional bool returned indicates whether it's mem (that is
// represented as an alloca or heap, hence needs a 'load' to be used as an
// immediate).
fn trans_lval_gen(cx: @block_ctxt, e: @ast::expr) -> lval_result {
fn trans_callee(cx: @block_ctxt, e: @ast::expr) -> lval_maybe_callee {
alt e.node {
ast::expr_path(p) { ret trans_path(cx, p, e.id); }
ast::expr_field(base, ident) {
let r = trans_expr(cx, base);
let t = ty::expr_ty(bcx_tcx(cx), base);
ret trans_field(r.bcx, e.span, r.val, t, ident);
ret trans_field(cx, e.span, base, ident);
}
ast::expr_self_method(ident) {
alt cx.fcx.llself {
some(pair) {
ret trans_field_inner(cx, e.span, pair.v, pair.t, ident);
}
}
}
_ {
let lv = trans_lval(cx, e);
ret lval_no_env(lv.bcx, lv.val, lv.is_mem);
}
}
}
// The additional bool returned indicates whether it's mem (that is
// represented as an alloca or heap, hence needs a 'load' to be used as an
// immediate).
fn trans_lval(cx: @block_ctxt, e: @ast::expr) -> lval_result {
alt e.node {
ast::expr_path(p) {
let v = trans_path(cx, p, e.id);
ret lval_maybe_callee_to_lval(v, ty::expr_ty(bcx_tcx(cx), e));
}
ast::expr_field(base, ident) {
let f = trans_field(cx, e.span, base, ident);
ret lval_maybe_callee_to_lval(f, ty::expr_ty(bcx_tcx(cx), e));
}
ast::expr_index(base, idx) {
ret trans_index(cx, e.span, base, idx, e.id);
@ -3110,13 +3135,6 @@ fn trans_lval_gen(cx: @block_ctxt, e: @ast::expr) -> lval_result {
};
ret lval_mem(sub.bcx, val);
}
ast::expr_self_method(ident) {
alt copy cx.fcx.llself {
some(pair) {
ret trans_field(cx, e.span, pair.v, pair.t, ident);
}
}
}
ast::expr_call(f, args) {
let {res: {bcx, val}, by_ref} =
trans_call(cx, f, none, args, e.id);
@ -3124,25 +3142,38 @@ fn trans_lval_gen(cx: @block_ctxt, e: @ast::expr) -> lval_result {
else { ret lval_val(bcx, val); }
}
_ {
ret {res: trans_expr(cx, e),
is_mem: false,
generic: none,
llobj: none};
let res = trans_expr(cx, e);
ret lval_val(res.bcx, res.val);
}
}
}
fn trans_lval(cx: @block_ctxt, e: @ast::expr) -> lval_result {
let lv = trans_lval_gen(cx, e);
alt lv.generic {
fn maybe_add_env(bcx: @block_ctxt, c: lval_maybe_callee)
-> (bool, ValueRef) {
if c.env == is_closure {
(c.is_mem, c.val)
} else {
let env = alt c.env {
null_env. { C_null(T_opaque_closure_ptr(*bcx_ccx(bcx))) }
some_env(e) { e }
};
let llfnty = llvm::LLVMGetElementType(val_ty(c.val));
(false, create_real_fn_pair(bcx, llfnty, c.val, env))
}
}
fn lval_maybe_callee_to_lval(c: lval_maybe_callee, ty: ty::t) -> lval_result {
alt c.generic {
some(gi) {
let t = ty::expr_ty(bcx_tcx(cx), e);
let n_args = std::vec::len(ty::ty_fn_args(bcx_tcx(cx), t));
let n_args = std::vec::len(ty::ty_fn_args(bcx_tcx(c.bcx), ty));
let args = std::vec::init_elt(none::<@ast::expr>, n_args);
let bound = trans_bind_1(lv.res.bcx, e, lv, args, e.id);
ret lval_val(bound.bcx, bound.val);
let {bcx, val} = trans_bind_1(c.bcx, ty, c, args, ty);
ret lval_val(bcx, val);
}
none. {
let (is_mem, val) = maybe_add_env(c.bcx, c);
ret {bcx: c.bcx, val: val, is_mem: is_mem};
}
none. { ret lv; }
}
}
@ -3294,24 +3325,26 @@ fn trans_bind_thunk(cx: @local_ctxt, sp: span, incoming_fty: ty::t,
// creating. (In our running example, target is the function f.) Pick
// out the pointer to the target function from the environment. The
// target function lives in the first binding spot.
let (lltarget, starting_idx) =
alt target_fn {
some(lltarget) { (lltarget, 0) }
none. {
let lltarget =
GEP_tup_like(bcx, closure_ty, llclosure,
[0, abi::box_rc_field_body,
abi::closure_elt_bindings, 0]);
bcx = lltarget.bcx;;
(lltarget.val, 1)
}
};
let (lltargetfn, lltargetenv, starting_idx) = alt target_fn {
some(fptr) {
(fptr, C_null(T_opaque_closure_ptr(*bcx_ccx(bcx))), 0)
}
none. {
let {bcx: cx, val: pair} =
GEP_tup_like(bcx, closure_ty, llclosure,
[0, abi::box_rc_field_body,
abi::closure_elt_bindings, 0]);
let lltargetenv =
Load(cx, GEP(cx, pair, [C_int(0), C_int(abi::fn_field_box)]));
let lltargetfn = Load
(cx, GEP(cx, pair, [C_int(0), C_int(abi::fn_field_code)]));
bcx = cx;
(lltargetfn, lltargetenv, 1)
}
};
// And then, pick out the target function's own environment. That's what
// we'll use as the environment the thunk gets.
let lltargetclosure =
GEP(bcx, lltarget, [C_int(0), C_int(abi::fn_field_box)]);
lltargetclosure = Load(bcx, lltargetclosure);
// Get f's return type, which will also be the return type of the entire
// bind expression.
@ -3331,7 +3364,7 @@ fn trans_bind_thunk(cx: @local_ctxt, sp: span, incoming_fty: ty::t,
}
// Set up the three implicit arguments to the thunk.
let llargs: [ValueRef] = [llretptr, fcx.lltaskptr, lltargetclosure];
let llargs: [ValueRef] = [llretptr, fcx.lltaskptr, lltargetenv];
// Copy in the type parameters.
let i: uint = 0u;
@ -3356,10 +3389,6 @@ fn trans_bind_thunk(cx: @local_ctxt, sp: span, incoming_fty: ty::t,
let out_arg = outgoing_args[outgoing_arg_index];
let llout_arg_ty = llout_arg_tys[outgoing_arg_index];
alt arg {
// Arg provided at binding time; thunk copies it from
// closure.
some(e) {
@ -3378,8 +3407,6 @@ fn trans_bind_thunk(cx: @local_ctxt, sp: span, incoming_fty: ty::t,
b += 1;
}
// Arg will be provided when the thunk is invoked.
none. {
let arg: ValueRef = llvm::LLVMGetParam(llthunk, a);
@ -3393,18 +3420,13 @@ fn trans_bind_thunk(cx: @local_ctxt, sp: span, incoming_fty: ty::t,
outgoing_arg_index += 1u;
}
let lltargetfn =
GEP(bcx, lltarget, [C_int(0), C_int(abi::fn_field_code)]);
// Cast the outgoing function to the appropriate type.
// This is necessary because the type of the function that we have
// in the closure does not know how many type descriptors the function
// needs to take.
let lltargetty =
type_of_fn_from_ty(bcx_ccx(bcx), sp, outgoing_fty, ty_param_count);
lltargetfn = PointerCast(bcx, lltargetfn, T_ptr(T_ptr(lltargetty)));
lltargetfn = Load(bcx, lltargetfn);
lltargetfn = PointerCast(bcx, lltargetfn, T_ptr(lltargetty));
FastCall(bcx, lltargetfn, llargs);
build_return(bcx);
finish_fn(fcx, lltop);
@ -3413,19 +3435,20 @@ fn trans_bind_thunk(cx: @local_ctxt, sp: span, incoming_fty: ty::t,
fn trans_bind(cx: @block_ctxt, f: @ast::expr, args: [option::t<@ast::expr>],
id: ast::node_id) -> result {
let f_res = trans_lval_gen(cx, f);
ret trans_bind_1(cx, f, f_res, args, id);
let f_res = trans_callee(cx, f);
ret trans_bind_1(cx, ty::expr_ty(bcx_tcx(cx), f), f_res, args,
ty::node_id_to_type(bcx_tcx(cx), id));
}
fn trans_bind_1(cx: @block_ctxt, f: @ast::expr, f_res: lval_result,
args: [option::t<@ast::expr>], id: ast::node_id) -> result {
fn trans_bind_1(cx: @block_ctxt, outgoing_fty: ty::t,
f_res: lval_maybe_callee,
args: [option::t<@ast::expr>], pair_ty: ty::t) -> result {
let bound: [@ast::expr] = [];
for argopt: option::t<@ast::expr> in args {
alt argopt { none. { } some(e) { bound += [e]; } }
}
// Figure out which tydescs we need to pass, if any.
let outgoing_fty: ty::t = ty::expr_ty(bcx_tcx(cx), f);
let outgoing_fty_real; // the type with typarams still in it
let lltydescs: [ValueRef];
alt f_res.generic {
@ -3439,10 +3462,15 @@ fn trans_bind_1(cx: @block_ctxt, f: @ast::expr, f_res: lval_result,
let ty_param_count = std::vec::len(lltydescs);
if std::vec::len(bound) == 0u && ty_param_count == 0u {
// Trivial 'binding': just return the static pair-ptr.
ret f_res.res;
// Trivial 'binding': just return the closure
let lv = lval_maybe_callee_to_lval(f_res, pair_ty);
ret rslt(lv.bcx, lv.val);
}
let bcx = f_res.res.bcx;
let bcx = f_res.bcx;
let (is_mem, closure) = alt f_res.env {
null_env. { (true, none) }
_ { let (mem, cl) = maybe_add_env(cx, f_res); (mem, some(cl)) }
};
// FIXME: should follow from a precondition on trans_bind_1
let ccx = bcx_ccx(cx);
@ -3450,22 +3478,24 @@ fn trans_bind_1(cx: @block_ctxt, f: @ast::expr, f_res: lval_result,
// Arrange for the bound function to live in the first binding spot
// if the function is not statically known.
let (bound_tys, bound_vals, target_res) =
if f_res.is_mem {
// Cast the function we are binding to be the type that the
// closure will expect it to have. The type the closure knows
// about has the type parameters substituted with the real types.
let sp = cx.sp;
let llclosurety = T_ptr(type_of(ccx, sp, outgoing_fty));
let src_loc = PointerCast(bcx, f_res.res.val, llclosurety);
let bound_f = {res: {bcx: bcx, val: src_loc} with f_res};
([outgoing_fty], [bound_f], none)
} else { ([], [], some(f_res.res.val)) };
let (bound_tys, bound_vals, target_res) = alt closure {
some(cl) {
// Cast the function we are binding to be the type that the
// closure will expect it to have. The type the closure knows
// about has the type parameters substituted with the real types.
let sp = cx.sp;
let llclosurety = T_ptr(type_of(ccx, sp, outgoing_fty));
let src_loc = PointerCast(bcx, cl, llclosurety);
let bound_f = {bcx: bcx, val: src_loc, is_mem: is_mem};
([outgoing_fty], [bound_f], none)
}
none. { ([], [], some(f_res.val)) }
};
// Translate the bound expressions.
for e: @ast::expr in bound {
let lv = trans_lval(bcx, e);
bcx = lv.res.bcx;
bcx = lv.bcx;
bound_vals += [lv];
bound_tys += [ty::expr_ty(bcx_tcx(cx), e)];
}
@ -3476,8 +3506,6 @@ fn trans_bind_1(cx: @block_ctxt, f: @ast::expr, f_res: lval_result,
bcx = closure.bcx;
// Make thunk
// The type of the entire bind expression.
let pair_ty = node_id_type(bcx_ccx(cx), id);
let llthunk =
trans_bind_thunk(cx.fcx.lcx, cx.sp, pair_ty, outgoing_fty_real, args,
closure.ptrty, ty_param_count, target_res);
@ -3497,8 +3525,8 @@ fn trans_arg_expr(cx: @block_ctxt, arg: ty::arg, lldestty0: TypeRef,
let e_ty = ty::expr_ty(ccx.tcx, e);
let is_bot = ty::type_is_bot(ccx.tcx, e_ty);
let lv = trans_lval(cx, e);
let bcx = lv.res.bcx;
let val = lv.res.val;
let bcx = lv.bcx;
let val = lv.val;
if is_bot {
// For values of type _|_, we generate an
// "undef" value, as such a value should never
@ -3537,8 +3565,8 @@ fn trans_arg_expr(cx: @block_ctxt, arg: ty::arg, lldestty0: TypeRef,
if lv.is_mem {
// Use actual ty, not declared ty -- anything else doesn't make
// sense if declared ty is a ty param
to_zero += [{v: lv.res.val, t: e_ty}];
} else { to_revoke += [{v: lv.res.val, t: e_ty}]; }
to_zero += [{v: lv.val, t: e_ty}];
} else { to_revoke += [{v: lv.val, t: e_ty}]; }
}
ret rslt(bcx, val);
}
@ -3677,27 +3705,23 @@ fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
let by_ref = ast_util::ret_by_ref(ty::ty_fn_ret_style(bcx_tcx(in_cx),
fn_expr_ty));
let cx = new_scope_block_ctxt(in_cx, "call");
let f_res = trans_lval_gen(cx, f);
let bcx = f_res.res.bcx;
let f_res = trans_callee(cx, f);
let bcx = f_res.bcx;
let faddr = f_res.res.val;
let llenv = C_null(T_opaque_closure_ptr(*bcx_ccx(cx)));
alt f_res.llobj {
some(ob) {
// It's a vtbl entry.
faddr = Load(bcx, faddr);
llenv = ob;
}
none. {
// It's a closure. We have to autoderef.
let faddr = f_res.val;
let llenv = alt f_res.env {
null_env. { C_null(T_opaque_closure_ptr(*bcx_ccx(cx))) }
some_env(e) { e }
is_closure. {
// It's a closure. Have to fetch the elements
if f_res.is_mem { faddr = load_if_immediate(bcx, faddr, fn_expr_ty); }
let pair = faddr;
faddr = GEP(bcx, pair, [C_int(0), C_int(abi::fn_field_code)]);
faddr = Load(bcx, faddr);
let llclosure = GEP(bcx, pair, [C_int(0), C_int(abi::fn_field_box)]);
llenv = Load(bcx, llclosure);
Load(bcx, llclosure)
}
}
};
let ret_ty = ty::node_id_to_type(bcx_tcx(cx), id);
let args_res =
@ -3861,7 +3885,7 @@ fn trans_tup(cx: @block_ctxt, elts: [@ast::expr], id: ast::node_id) ->
for e in elts {
let e_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e);
let src = trans_lval(bcx, e);
bcx = src.res.bcx;
bcx = src.bcx;
let dst_res = GEP_tup_like(bcx, t, tup_val, [0, i]);
bcx = move_val_if_temp(dst_res.bcx, INIT, dst_res.val, src, e_ty);
i += 1;
@ -3899,7 +3923,7 @@ fn trans_rec(cx: @block_ctxt, fields: [ast::field],
expr_provided = true;
let lv = trans_lval(bcx, f.node.expr);
bcx =
move_val_if_temp(lv.res.bcx, INIT, dst_res.val, lv, e_ty);
move_val_if_temp(lv.bcx, INIT, dst_res.val, lv, e_ty);
break;
}
}
@ -3979,13 +4003,13 @@ fn trans_expr_out(cx: @block_ctxt, e: @ast::expr, output: out_method) ->
ast::expr_copy(a) {
let e_ty = ty::expr_ty(bcx_tcx(cx), a);
let lv = trans_lval(cx, a);
let bcx = lv.res.bcx;
if !lv.is_mem { ret lv.res; }
let bcx = lv.bcx;
if !lv.is_mem { ret {bcx: lv.bcx, val: lv.val}; }
let r = if type_is_immediate(bcx_ccx(cx), e_ty) {
rslt(bcx, Load(bcx, lv.res.val))
rslt(bcx, Load(bcx, lv.val))
} else {
let {bcx, val: dest} = alloc_ty(bcx, e_ty);
bcx = copy_val(bcx, INIT, dest, lv.res.val, e_ty);
bcx = copy_val(bcx, INIT, dest, lv.val, e_ty);
rslt(bcx, dest)
};
add_clean_temp(bcx, r.val, e_ty);
@ -3994,43 +4018,43 @@ fn trans_expr_out(cx: @block_ctxt, e: @ast::expr, output: out_method) ->
ast::expr_move(dst, src) {
let lhs_res = trans_lval(cx, dst);
assert (lhs_res.is_mem);
// FIXME Fill in lhs_res.res.bcx.sp
// FIXME Fill in lhs_res.bcx.sp
let rhs_res = trans_lval(lhs_res.res.bcx, src);
let rhs_res = trans_lval(lhs_res.bcx, src);
let t = ty::expr_ty(bcx_tcx(cx), src);
// FIXME: calculate copy init-ness in typestate.
let bcx =
move_val(rhs_res.res.bcx, DROP_EXISTING, lhs_res.res.val, rhs_res,
move_val(rhs_res.bcx, DROP_EXISTING, lhs_res.val, rhs_res,
t);
ret rslt(bcx, C_nil());
}
ast::expr_assign(dst, src) {
let lhs_res = trans_lval(cx, dst);
assert (lhs_res.is_mem);
// FIXME Fill in lhs_res.res.bcx.sp
let rhs = trans_lval(lhs_res.res.bcx, src);
// FIXME Fill in lhs_res.bcx.sp
let rhs = trans_lval(lhs_res.bcx, src);
let t = ty::expr_ty(bcx_tcx(cx), src);
// FIXME: calculate copy init-ness in typestate.
let bcx =
move_val_if_temp(rhs.res.bcx, DROP_EXISTING, lhs_res.res.val, rhs,
move_val_if_temp(rhs.bcx, DROP_EXISTING, lhs_res.val, rhs,
t);
ret rslt(bcx, C_nil());
}
ast::expr_swap(dst, src) {
let lhs_res = trans_lval(cx, dst);
assert (lhs_res.is_mem);
// FIXME Fill in lhs_res.res.bcx.sp
// FIXME Fill in lhs_res.bcx.sp
let rhs_res = trans_lval(lhs_res.res.bcx, src);
let rhs_res = trans_lval(lhs_res.bcx, src);
let t = ty::expr_ty(bcx_tcx(cx), src);
let {bcx: bcx, val: tmp_alloc} = alloc_ty(rhs_res.res.bcx, t);
let {bcx: bcx, val: tmp_alloc} = alloc_ty(rhs_res.bcx, t);
// Swap through a temporary.
bcx = move_val(bcx, INIT, tmp_alloc, lhs_res, t);
bcx = move_val(bcx, INIT, lhs_res.res.val, rhs_res, t);
bcx = move_val(bcx, INIT, lhs_res.val, rhs_res, t);
bcx =
move_val(bcx, INIT, rhs_res.res.val, lval_mem(bcx, tmp_alloc), t);
move_val(bcx, INIT, rhs_res.val, lval_mem(bcx, tmp_alloc), t);
ret rslt(bcx, C_nil());
}
ast::expr_assign_op(op, dst, src) {
@ -4045,8 +4069,8 @@ fn trans_expr_out(cx: @block_ctxt, e: @ast::expr, output: out_method) ->
alt src.node {
ast::expr_vec(args, _) {
let bcx =
tvec::trans_append_literal(lhs_res.res.bcx,
lhs_res.res.val, t, args);
tvec::trans_append_literal(lhs_res.bcx,
lhs_res.val, t, args);
ret rslt(bcx, C_nil());
}
_ { }
@ -4055,24 +4079,24 @@ fn trans_expr_out(cx: @block_ctxt, e: @ast::expr, output: out_method) ->
_ { }
}
// FIXME Fill in lhs_res.res.bcx.sp
let rhs_res = trans_expr(lhs_res.res.bcx, src);
// FIXME Fill in lhs_res.bcx.sp
let rhs_res = trans_expr(lhs_res.bcx, src);
if ty::type_is_sequence(tcx, t) {
alt op {
ast::add. {
ret tvec::trans_append(rhs_res.bcx, t, lhs_res.res.val,
ret tvec::trans_append(rhs_res.bcx, t, lhs_res.val,
rhs_res.val);
}
_ { }
}
}
let lhs_val = load_if_immediate(rhs_res.bcx, lhs_res.res.val, t);
let lhs_val = load_if_immediate(rhs_res.bcx, lhs_res.val, t);
let v =
trans_eager_binop(rhs_res.bcx, op, lhs_val, t, rhs_res.val, t);
// FIXME: calculate copy init-ness in typestate.
// This is always a temporary, so can always be safely moved
let bcx =
move_val(v.bcx, DROP_EXISTING, lhs_res.res.val,
move_val(v.bcx, DROP_EXISTING, lhs_res.val,
lval_val(v.bcx, v.val), t);
ret rslt(bcx, C_nil());
}
@ -4127,9 +4151,9 @@ fn trans_expr_out(cx: @block_ctxt, e: @ast::expr, output: out_method) ->
ast::expr_path(_) | ast::expr_unary(ast::deref., _) {
let t = ty::expr_ty(bcx_tcx(cx), e);
let sub = trans_lval(cx, e);
let v = sub.res.val;
if sub.is_mem { v = load_if_immediate(sub.res.bcx, v, t); }
ret rslt(sub.res.bcx, v);
let v = sub.val;
if sub.is_mem { v = load_if_immediate(sub.bcx, v, t); }
ret rslt(sub.bcx, v);
}
ast::expr_unary(op, x) {
ret trans_unary(cx, op, x, e.id);
@ -4419,10 +4443,10 @@ fn trans_ret(cx: @block_ctxt, e: option::t<@ast::expr>) -> result {
some(x) {
let t = ty::expr_ty(bcx_tcx(cx), x);
let lv = trans_lval(cx, x);
bcx = lv.res.bcx;
bcx = lv.bcx;
if ast_util::ret_by_ref(cx.fcx.ret_style) {
assert lv.is_mem;
Store(bcx, lv.res.val, cx.fcx.llretptr);
Store(bcx, lv.val, cx.fcx.llretptr);
} else {
let is_local = alt x.node {
ast::expr_path(p) {
@ -4491,11 +4515,11 @@ fn init_local(bcx: @block_ctxt, local: @ast::local) -> @block_ctxt {
// the value.
ty = node_id_type(bcx_ccx(bcx), init.expr.id);
let sub = trans_lval(bcx, init.expr);
bcx = move_val_if_temp(sub.res.bcx, INIT, llptr, sub, ty);
bcx = move_val_if_temp(sub.bcx, INIT, llptr, sub, ty);
}
ast::init_move. {
let sub = trans_lval(bcx, init.expr);
bcx = move_val(sub.res.bcx, INIT, llptr, sub, ty);
bcx = move_val(sub.bcx, INIT, llptr, sub, ty);
}
}
}
@ -4545,9 +4569,8 @@ fn init_ref_local(bcx: @block_ctxt, local: @ast::local) -> @block_ctxt {
let init_expr = option::get(local.node.init).expr;
let val = trans_lval(bcx, init_expr);
assert val.is_mem;
ret trans_alt::bind_irrefutable_pat(val.res.bcx, local.node.pat,
val.res.val,
bcx.fcx.lllocals, false);
ret trans_alt::bind_irrefutable_pat(val.bcx, local.node.pat,
val.val, bcx.fcx.lllocals, false);
}
fn zero_alloca(cx: @block_ctxt, llptr: ValueRef, t: ty::t) -> result {
@ -4813,7 +4836,7 @@ fn trans_block(cx: @block_ctxt, b: ast::blk, output: out_method) -> result {
if is_terminated(bcx) || ty::type_is_bot(ccx.tcx, r_ty) { ret r; }
} else {
let lv = trans_lval(bcx, e);
r = lv.res;
r = {bcx: lv.bcx, val: lv.val};
bcx = r.bcx;
if is_terminated(bcx) || ty::type_is_bot(ccx.tcx, r_ty) { ret r; }
alt output {

View File

@ -117,7 +117,7 @@ fn trans_vec(bcx: @block_ctxt, args: [@ast::expr], id: ast::node_id) ->
let i = 0u;
for e in args {
let lv = trans_lval(bcx, e);
bcx = lv.res.bcx;
bcx = lv.bcx;
let lleltptr =
if ty::type_has_dynamic_size(bcx_tcx(bcx), unit_ty) {
InBoundsGEP(bcx, dataptr, [Mul(bcx, C_uint(i), llunitsz)])

View File

@ -1,6 +1,6 @@
// Test case for issue #435.
obj foo() {
fn add5(n: int) -> int { ret n + 5; }
obj foo(x: int) {
fn add5(n: int) -> int { ret n + x; }
}
fn add5(n: int) -> int { ret n + 5; }
@ -10,7 +10,7 @@ fn main() {
assert (add5(7) == 12);
assert (fiveplusseven() == 12);
let my_foo = foo();
let my_foo = foo(5);
let fiveplusseven_too = bind my_foo.add5(7);
assert (my_foo.add5(7) == 12);
assert (fiveplusseven_too() == 12);