From 022363a6747c50007a991aef82621b70441d25d9 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 8 Jul 2011 14:28:46 +0200 Subject: [PATCH] Auto-bind generic functions when their value is taken in non-call context trans::trans_lval will now autobind if the given expression was the name of a generic functions. Those callees (trans_call and trans_bind) that are interested in the generics information call trans_lval_gen now. --- src/comp/middle/trans.rs | 32 ++++++++++++++++++++++++++++---- src/test/run-pass/autobind.rs | 13 +++++++++++++ 2 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 src/test/run-pass/autobind.rs diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 899a74f573ef..02ff9e77cb41 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -5201,7 +5201,7 @@ fn trans_index(&@block_ctxt cx, &span sp, &@ast::expr base, &@ast::expr idx, // 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(&@block_ctxt cx, &@ast::expr e) -> lval_result { +fn trans_lval_gen(&@block_ctxt cx, &@ast::expr e) -> lval_result { alt (e.node) { case (ast::expr_path(?p)) { ret trans_path(cx, p, e.id); } case (ast::expr_field(?base, ?ident)) { @@ -5263,6 +5263,23 @@ fn trans_lval(&@block_ctxt cx, &@ast::expr e) -> lval_result { } } +fn trans_lval(&@block_ctxt cx, &@ast::expr e) -> lval_result { + auto lv = trans_lval_gen(cx, e); + alt (lv.generic) { + case (some(?gi)) { + auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e); + auto n_args = + std::ivec::len(ty::ty_fn_args(cx.fcx.lcx.ccx.tcx, t)); + auto args = std::ivec::init_elt(none[@ast::expr], n_args); + auto bound = trans_bind_1(lv.res.bcx, e, lv, args, e.id); + ret lval_val(bound.bcx, bound.val); + } + case (none) { + ret lv; + } + } +} + fn int_cast(&@block_ctxt bcx, TypeRef lldsttype, TypeRef llsrctype, ValueRef llsrc, bool signed) -> ValueRef { if (llvm::LLVMGetIntTypeWidth(lldsttype) > @@ -5489,7 +5506,12 @@ fn trans_bind_thunk(&@local_ctxt cx, &span sp, &ty::t incoming_fty, fn trans_bind(&@block_ctxt cx, &@ast::expr f, &(option::t[@ast::expr])[] args, ast::node_id id) -> result { - auto f_res = trans_lval(cx, f); + auto f_res = trans_lval_gen(cx, f); + ret trans_bind_1(cx, f, f_res, args, id); +} + +fn trans_bind_1(&@block_ctxt cx, &@ast::expr f, &lval_result f_res, + &(option::t[@ast::expr])[] args, ast::node_id id) -> result { if (f_res.is_mem) { cx.fcx.lcx.ccx.sess.unimpl("re-binding existing function"); } else { @@ -5839,7 +5861,7 @@ fn trans_call(&@block_ctxt cx, &@ast::expr f, &option::t[ValueRef] lliterbody, // expression because of the hack that allows us to process self-calls // with trans_call. - auto f_res = trans_lval(cx, f); + auto f_res = trans_lval_gen(cx, f); let ty::t fn_ty; alt (f_res.method_ty) { case (some(?meth)) { @@ -6361,7 +6383,9 @@ fn trans_expr_out(&@block_ctxt cx, &@ast::expr e, out_method output) -> auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e); auto sub = trans_lval(cx, e); - ret rslt(sub.res.bcx, load_if_immediate(sub.res.bcx, sub.res.val, t)); + auto v = sub.res.val; + if (sub.is_mem) { v = load_if_immediate(sub.res.bcx, v, t); } + ret rslt(sub.res.bcx, v); } fn with_out_method(fn(&out_method) -> result work, @block_ctxt cx, diff --git a/src/test/run-pass/autobind.rs b/src/test/run-pass/autobind.rs new file mode 100644 index 000000000000..98cda76a0c19 --- /dev/null +++ b/src/test/run-pass/autobind.rs @@ -0,0 +1,13 @@ +fn f[T](&T[] x) -> T { + ret x.(0); +} + +fn g(fn(&int[]) -> int act) -> int { + ret act(~[1, 2, 3]); +} + +fn main() { + assert g(f) == 1; + let fn(&str[]) -> str f1 = f; + assert f1(~["x", "y", "z"]) == "x"; +}