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.
This commit is contained in:
Marijn Haverbeke 2011-07-08 14:28:46 +02:00
parent faec0d7799
commit 022363a674
2 changed files with 41 additions and 4 deletions

View file

@ -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,

View file

@ -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";
}