From b4d6589e7387a7c7df0841f51f0fa5ef831883d9 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 23 Feb 2011 10:58:43 -0800 Subject: Implement type descriptor binding. Un-XFAIL test/run-pass/generic-bind.rs. --- src/Makefile | 1 + src/comp/middle/trans.rs | 115 +++++++++++++++++++++++++++++++++++++++-------- src/comp/middle/ty.rs | 3 ++ 3 files changed, 100 insertions(+), 19 deletions(-) (limited to 'src') 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 { -- cgit v1.2.3