aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile1
-rw-r--r--src/comp/middle/trans.rs115
-rw-r--r--src/comp/middle/ty.rs3
3 files changed, 100 insertions, 19 deletions
diff --git a/src/Makefile b/src/Makefile
index 551a7001..edbe9e29 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -480,6 +480,7 @@ TEST_XFAILS_RUSTC := $(filter-out \
foreach-simple.rs \
fun-call-variants.rs \
fun-indirect-call.rs \
+ generic-bind.rs \
generic-derived-type.rs \
generic-fn.rs \
generic-fn-infer.rs \
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index 6a19a6e5..30f3cdc4 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -373,11 +373,12 @@ fn T_typaram_ptr(type_names tn) -> TypeRef {
fn T_closure_ptr(type_names tn,
TypeRef lltarget_ty,
- TypeRef llbindings_ty) -> TypeRef {
+ TypeRef llbindings_ty,
+ uint n_ty_params) -> TypeRef {
ret T_ptr(T_box(T_struct(vec(T_ptr(T_tydesc(tn)),
lltarget_ty,
- llbindings_ty)
- // FIXME: add captured typarams.
+ llbindings_ty,
+ T_captured_tydescs(tn, n_ty_params))
)));
}
@@ -388,7 +389,8 @@ fn T_opaque_closure_ptr(type_names tn) -> TypeRef {
}
auto t = T_closure_ptr(tn, T_struct(vec(T_ptr(T_nil()),
T_ptr(T_nil()))),
- T_nil());
+ T_nil(),
+ 0u);
tn.associate(s, t);
ret t;
}
@@ -2747,7 +2749,8 @@ fn trans_bind_thunk(@crate_ctxt cx,
@ty.t outgoing_fty,
vec[option.t[@ast.expr]] args,
TypeRef llclosure_ty,
- vec[@ty.t] bound_tys) -> ValueRef {
+ vec[@ty.t] bound_tys,
+ uint ty_param_count) -> ValueRef {
// Construct a thunk-call with signature incoming_fty, and that copies
// args forward into a call to outgoing_fty.
@@ -2755,9 +2758,6 @@ fn trans_bind_thunk(@crate_ctxt cx,
let TypeRef llthunk_ty = get_pair_fn_ty(type_of(cx, incoming_fty));
let ValueRef llthunk = decl_fastcall_fn(cx.llmod, s, llthunk_ty);
- // FIXME: handle ty params properly.
- let vec[ast.ty_param] ty_params = vec();
-
auto fcx = new_fn_ctxt(cx, s, llthunk);
auto bcx = new_top_block_ctxt(fcx);
@@ -2779,11 +2779,33 @@ fn trans_bind_thunk(@crate_ctxt cx,
vec(C_int(0),
C_int(abi.fn_field_box)));
lltargetclosure = bcx.build.Load(lltargetclosure);
- let vec[ValueRef] llargs = vec(fcx.llretptr,
+
+ auto outgoing_ret_ty = ty.ty_fn_ret(outgoing_fty);
+ auto outgoing_arg_tys = ty.ty_fn_args(outgoing_fty);
+
+ auto llretptr = fcx.llretptr;
+ if (ty.type_has_dynamic_size(outgoing_ret_ty)) {
+ llretptr = bcx.build.PointerCast(llretptr, T_typaram_ptr(cx.tn));
+ }
+
+ let vec[ValueRef] llargs = vec(llretptr,
fcx.lltaskptr,
lltargetclosure);
- let uint a = 0u;
+
+ // Copy in the type parameters.
+ let uint i = 0u;
+ while (i < ty_param_count) {
+ auto lltyparam_ptr =
+ bcx.build.GEP(llbody, vec(C_int(0),
+ C_int(abi.closure_elt_ty_params),
+ C_int(i as int)));
+ llargs += vec(bcx.build.Load(lltyparam_ptr));
+ i += 1u;
+ }
+
+ let uint a = 2u + i; // retptr, task ptr, env come first
let int b = 0;
+ let uint outgoing_arg_index = 0u;
for (option.t[@ast.expr] arg in args) {
alt (arg) {
@@ -2800,10 +2822,19 @@ fn trans_bind_thunk(@crate_ctxt cx,
// Arg will be provided when the thunk is invoked.
case (none[@ast.expr]) {
let ValueRef passed_arg = llvm.LLVMGetParam(llthunk, a);
+ if (ty.type_has_dynamic_size(outgoing_arg_tys.
+ (outgoing_arg_index).ty)) {
+ // Cast to a generic typaram pointer in order to make a
+ // type-compatible call.
+ passed_arg = bcx.build.PointerCast(passed_arg,
+ T_typaram_ptr(cx.tn));
+ }
llargs += passed_arg;
a += 1u;
}
}
+
+ outgoing_arg_index += 0u;
}
// FIXME: turn this call + ret into a tail call.
@@ -2811,6 +2842,7 @@ fn trans_bind_thunk(@crate_ctxt cx,
vec(C_int(0),
C_int(abi.fn_field_code)));
lltargetfn = bcx.build.Load(lltargetfn);
+
auto r = bcx.build.FastCall(lltargetfn, llargs);
bcx.build.RetVoid();
@@ -2835,7 +2867,23 @@ fn trans_bind(@block_ctxt cx, @ast.expr f,
}
}
}
- if (_vec.len[@ast.expr](bound) == 0u) {
+
+ // Figure out which tydescs we need to pass, if any.
+ // FIXME: typestate botch
+ let @ty.t outgoing_fty = ty.plain_ty(ty.ty_nil);
+ let vec[ValueRef] lltydescs = vec();
+ alt (f_res.generic) {
+ case (none[generic_info]) {
+ outgoing_fty = ty.expr_ty(f);
+ }
+ case (some[generic_info](?ginfo)) {
+ outgoing_fty = ginfo.item_type;
+ lltydescs = ginfo.tydescs;
+ }
+ }
+ auto ty_param_count = _vec.len[ValueRef](lltydescs);
+
+ if (_vec.len[@ast.expr](bound) == 0u && ty_param_count == 0u) {
// Trivial 'binding': just return the static pair-ptr.
ret f_res.res;
} else {
@@ -2846,20 +2894,27 @@ fn trans_bind(@block_ctxt cx, @ast.expr f,
// Translate the bound expressions.
let vec[@ty.t] bound_tys = vec();
let vec[ValueRef] bound_vals = vec();
+ auto i = 0u;
for (@ast.expr e in bound) {
auto arg = trans_expr(bcx, e);
bcx = arg.bcx;
+
append[ValueRef](bound_vals, arg.val);
append[@ty.t](bound_tys, ty.expr_ty(e));
+
+ i += 1u;
}
+ // Get the type of the bound function.
+ let TypeRef lltarget_ty = type_of(bcx.fcx.ccx, outgoing_fty);
+
// Synthesize a closure type.
let @ty.t bindings_ty = plain_ty(ty.ty_tup(bound_tys));
- let TypeRef lltarget_ty = type_of(bcx.fcx.ccx, ty.expr_ty(f));
let TypeRef llbindings_ty = type_of(bcx.fcx.ccx, bindings_ty);
let TypeRef llclosure_ty = T_closure_ptr(cx.fcx.ccx.tn,
lltarget_ty,
- llbindings_ty);
+ llbindings_ty,
+ ty_param_count);
// Malloc a box for the body.
auto r = trans_malloc_inner(bcx, llclosure_ty);
@@ -2888,19 +2943,40 @@ fn trans_bind(@block_ctxt cx, @ast.expr f,
bcx.build.GEP(closure,
vec(C_int(0),
C_int(abi.closure_elt_target)));
- bcx.build.Store(bcx.build.Load(f_res.res.val), bound_target);
+ auto src = bcx.build.Load(f_res.res.val);
+ bcx.build.Store(src, bound_target);
// Copy expr values into boxed bindings.
- let int i = 0;
+ i = 0u;
auto bindings =
bcx.build.GEP(closure,
vec(C_int(0),
C_int(abi.closure_elt_bindings)));
for (ValueRef v in bound_vals) {
auto bound = bcx.build.GEP(bindings,
- vec(C_int(0),C_int(i)));
+ vec(C_int(0), C_int(i as int)));
bcx = copy_ty(r.bcx, INIT, bound, v, bound_tys.(i)).bcx;
- i += 1;
+ i += 1u;
+ }
+
+ // If necessary, copy tydescs describing type parameters into the
+ // appropriate slot in the closure.
+ alt (f_res.generic) {
+ case (none[generic_info]) { /* nothing to do */ }
+ case (some[generic_info](?ginfo)) {
+ auto ty_params_slot =
+ bcx.build.GEP(closure,
+ vec(C_int(0),
+ C_int(abi.closure_elt_ty_params)));
+ auto i = 0;
+ for (ValueRef td in ginfo.tydescs) {
+ auto ty_param_slot = bcx.build.GEP(ty_params_slot,
+ vec(C_int(0),
+ C_int(i)));
+ bcx.build.Store(td, ty_param_slot);
+ i += 1;
+ }
+ }
}
// Make thunk and store thunk-ptr in outer pair's code slot.
@@ -2910,8 +2986,9 @@ fn trans_bind(@block_ctxt cx, @ast.expr f,
let @ty.t pair_ty = node_ann_type(cx.fcx.ccx, ann);
let ValueRef llthunk =
- trans_bind_thunk(cx.fcx.ccx, pair_ty, ty.expr_ty(f),
- args, llclosure_ty, bound_tys);
+ trans_bind_thunk(cx.fcx.ccx, pair_ty, outgoing_fty,
+ args, llclosure_ty, bound_tys,
+ ty_param_count);
bcx.build.Store(llthunk, pair_code);
diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs
index 0f277329..5535879e 100644
--- a/src/comp/middle/ty.rs
+++ b/src/comp/middle/ty.rs
@@ -598,12 +598,14 @@ fn ty_fn_args(@t fty) -> vec[arg] {
case (ty.ty_fn(_, ?a, _)) { ret a; }
case (ty.ty_native_fn(?a, _)) { ret a; }
}
+ fail;
}
fn ty_fn_proto(@t fty) -> ast.proto {
alt (fty.struct) {
case (ty.ty_fn(?p, _, _)) { ret p; }
}
+ fail;
}
fn ty_fn_ret(@t fty) -> @t {
@@ -611,6 +613,7 @@ fn ty_fn_ret(@t fty) -> @t {
case (ty.ty_fn(_, _, ?r)) { ret r; }
case (ty.ty_native_fn(_, ?r)) { ret r; }
}
+ fail;
}
fn is_fn_ty(@t fty) -> bool {