Skip to content

Commit 7b1b5d5

Browse files
msullivanmarijnh
authored andcommitted
Implement autoderef for function calls.
This is important since we are going to be making functions noncopyable soon, which means we'll be seeing a lot of boxed functions. (*f)(...) is really just too heavyweight. Doing the autodereferencing was a very little bit tricky since trans_call works with an *lval* of the function whereas existing autoderef code was not for lvals.
1 parent ee45d54 commit 7b1b5d5

File tree

5 files changed

+69
-23
lines changed

5 files changed

+69
-23
lines changed

src/comp/middle/alias.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -663,7 +663,7 @@ fn def_is_local(&ast::def d, bool objfields_count) -> bool {
663663
}
664664

665665
fn fty_args(&ctx cx, ty::t fty) -> ty::arg[] {
666-
ret alt (ty::struct(*cx.tcx, fty)) {
666+
ret alt (ty::struct(*cx.tcx, ty::type_autoderef(*cx.tcx, fty))) {
667667
case (ty::ty_fn(_, ?args, _, _, _)) { args }
668668
case (ty::ty_native_fn(_, ?args, _)) { args }
669669
};

src/comp/middle/trans.rs

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4099,12 +4099,18 @@ fn trans_eager_binop(&@block_ctxt cx, ast::binop op, &ty::t intype,
40994099
}
41004100
}
41014101

4102-
fn autoderef(&@block_ctxt cx, ValueRef v, &ty::t t) -> result {
4102+
fn autoderef_lval(&@block_ctxt cx, ValueRef v, &ty::t t, bool is_lval)
4103+
-> result {
41034104
let ValueRef v1 = v;
41044105
let ty::t t1 = t;
41054106
while (true) {
41064107
alt (ty::struct(cx.fcx.lcx.ccx.tcx, t1)) {
41074108
case (ty::ty_box(?mt)) {
4109+
// If we are working with an lval, we want to
4110+
// unconditionally load at the top of the loop
4111+
// to get rid of the extra indirection
4112+
if (is_lval) { v1 = cx.build.Load(v1); }
4113+
41084114
auto body =
41094115
cx.build.GEP(v1,
41104116
[C_int(0), C_int(abi::box_rc_field_body)]);
@@ -4118,14 +4124,22 @@ fn autoderef(&@block_ctxt cx, ValueRef v, &ty::t t) -> result {
41184124
auto llty = type_of(cx.fcx.lcx.ccx, cx.sp, mt.ty);
41194125
v1 = cx.build.PointerCast(body, T_ptr(llty));
41204126
} else { v1 = body; }
4121-
v1 = load_if_immediate(cx, v1, t1);
4127+
4128+
// But if we aren't working with an lval, we get rid of
4129+
// a layer of indirection at the bottom of the loop so
4130+
// that it is gone when we return...
4131+
if (!is_lval) { v1 = load_if_immediate(cx, v1, t1); }
41224132
}
41234133
case (_) { break; }
41244134
}
41254135
}
41264136
ret rslt(cx, v1);
41274137
}
41284138

4139+
fn autoderef(&@block_ctxt cx, ValueRef v, &ty::t t) -> result {
4140+
ret autoderef_lval(cx, v, t, false);
4141+
}
4142+
41294143
fn trans_binary(&@block_ctxt cx, ast::binop op, &@ast::expr a, &@ast::expr b)
41304144
-> result {
41314145

@@ -5637,17 +5651,33 @@ fn trans_call(&@block_ctxt cx, &@ast::expr f, &option::t[ValueRef] lliterbody,
56375651
// with trans_call.
56385652

56395653
auto f_res = trans_lval(cx, f);
5654+
let ty::t fn_ty;
5655+
alt (f_res.method_ty) {
5656+
case (some(?meth)) {
5657+
// self-call
5658+
fn_ty = meth;
5659+
}
5660+
case (_) {
5661+
fn_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, f);
5662+
}
5663+
}
5664+
5665+
auto bcx = f_res.res.bcx;
5666+
56405667
auto faddr = f_res.res.val;
56415668
auto llenv = C_null(T_opaque_closure_ptr(cx.fcx.lcx.ccx.tn));
56425669
alt (f_res.llobj) {
56435670
case (some(_)) {
56445671
// It's a vtbl entry.
5645-
faddr = f_res.res.bcx.build.Load(faddr);
5672+
faddr = bcx.build.Load(faddr);
56465673
}
56475674
case (none) {
5648-
// It's a closure.
5649-
auto bcx = f_res.res.bcx;
5650-
auto pair = faddr;
5675+
// It's a closure. We have to autoderef.
5676+
auto res = autoderef_lval(bcx, f_res.res.val, fn_ty, true);
5677+
bcx = res.bcx;
5678+
fn_ty = ty::type_autoderef(bcx.fcx.lcx.ccx.tcx, fn_ty);
5679+
5680+
auto pair = res.val;
56515681
faddr =
56525682
bcx.build.GEP(pair, [C_int(0), C_int(abi::fn_field_code)]);
56535683
faddr = bcx.build.Load(faddr);
@@ -5656,19 +5686,12 @@ fn trans_call(&@block_ctxt cx, &@ast::expr f, &option::t[ValueRef] lliterbody,
56565686
llenv = bcx.build.Load(llclosure);
56575687
}
56585688
}
5659-
let ty::t fn_ty;
5660-
alt (f_res.method_ty) {
5661-
case (some(?meth)) {
5662-
// self-call
5663-
fn_ty = meth;
5664-
}
5665-
case (_) { fn_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, f); }
5666-
}
5689+
56675690
auto ret_ty = ty::node_id_to_type(cx.fcx.lcx.ccx.tcx, id);
56685691
auto args_res =
5669-
trans_args(f_res.res.bcx, llenv, f_res.llobj, f_res.generic,
5692+
trans_args(bcx, llenv, f_res.llobj, f_res.generic,
56705693
lliterbody, args, fn_ty);
5671-
auto bcx = args_res._0;
5694+
bcx = args_res._0;
56725695
auto llargs = args_res._1;
56735696
auto llretslot = args_res._2;
56745697
/*

src/comp/middle/typeck.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,17 +1336,21 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
13361336
// expressions.
13371337

13381338
fn check_call_or_bind(&@fn_ctxt fcx, &span sp, &@ast::expr f,
1339-
&vec[option::t[@ast::expr]] args) {
1339+
&vec[option::t[@ast::expr]] args, bool is_call) {
13401340
// Check the function.
13411341

13421342
check_expr(fcx, f);
13431343
// Get the function type.
13441344

13451345
auto fty = expr_ty(fcx.ccx.tcx, f);
1346-
// Grab the argument types and the return type.
13471346

1347+
// We want to autoderef calls but not binds
1348+
auto fty_stripped =
1349+
if (is_call) { strip_boxes(fcx, sp, fty) } else { fty };
1350+
1351+
// Grab the argument types and the return type.
13481352
auto arg_tys;
1349-
alt (structure_of(fcx, sp, fty)) {
1353+
alt (structure_of(fcx, sp, fty_stripped)) {
13501354
case (ty::ty_fn(_, ?arg_tys_0, _, _, _)) { arg_tys = arg_tys_0; }
13511355
case (ty::ty_native_fn(_, ?arg_tys_0, _)) { arg_tys = arg_tys_0; }
13521356
case (_) {
@@ -1410,7 +1414,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
14101414
}
14111415
// Call the generic checker.
14121416

1413-
check_call_or_bind(fcx, sp, f, args_opt_0);
1417+
check_call_or_bind(fcx, sp, f, args_opt_0, true);
14141418
}
14151419
// A generic function for checking for or for-each loops
14161420

@@ -1806,7 +1810,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
18061810
case (ast::expr_bind(?f, ?args)) {
18071811
// Call the generic checker.
18081812

1809-
check_call_or_bind(fcx, expr.span, f, args);
1813+
check_call_or_bind(fcx, expr.span, f, args, false);
18101814
// Pull the argument and return types out.
18111815

18121816
auto proto_1;
@@ -1855,7 +1859,8 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
18551859
// Pull the return type out of the type of the function.
18561860

18571861
auto rt_1;
1858-
auto fty = ty::expr_ty(fcx.ccx.tcx, f);
1862+
auto fty = strip_boxes(fcx, expr.span,
1863+
ty::expr_ty(fcx.ccx.tcx, f));
18591864
alt (structure_of(fcx, expr.span, fty)) {
18601865
case (ty::ty_fn(_, _, ?rt, _, _)) { rt_1 = rt; }
18611866
case (ty::ty_native_fn(_, _, ?rt)) { rt_1 = rt; }
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// error-pattern: mismatched types
2+
3+
fn add1(int i) -> int { ret i+1; }
4+
fn main() {
5+
auto f = @add1;
6+
auto g = bind f(5);
7+
}

src/test/run-pass/auto-deref-fn.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// xfail-stage0
2+
3+
fn add1(int i) -> int { ret i+1; }
4+
fn main() {
5+
auto f = @add1;
6+
auto g = @f;
7+
auto h = @@@add1;
8+
assert(f(5) == 6);
9+
assert(g(8) == 9);
10+
assert(h(0x1badd00d) == 0x1badd00e);
11+
}

0 commit comments

Comments
 (0)