diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index bcdb31fb39d0d..bc2b002dca25d 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -5394,6 +5394,11 @@ fn trans_bind_thunk(&@local_ctxt cx, &span sp, &ty::t incoming_fty, auto fcx = new_fn_ctxt(cx, sp, llthunk); auto bcx = new_top_block_ctxt(fcx); auto lltop = bcx.llbb; + // Since we might need to construct derived tydescs that depend on + // our bound tydescs, we need to load tydescs out of the environment + // before derived tydescs are constructed. To do this, we load them + // in the copy_args block. + auto copy_args_bcx = new_raw_block_ctxt(fcx, fcx.llcopyargs); // The 'llenv' that will arrive in the thunk we're creating is an // environment that will contain the values of its arguments and a pointer @@ -5403,7 +5408,8 @@ fn trans_bind_thunk(&@local_ctxt cx, &span sp, &ty::t incoming_fty, // 'closure_ty', which was determined by trans_bind. auto llclosure_ptr_ty = type_of(cx.ccx, sp, ty::mk_imm_box(cx.ccx.tcx, closure_ty)); - auto llclosure = bcx.build.PointerCast(fcx.llenv, llclosure_ptr_ty); + auto llclosure = copy_args_bcx.build.PointerCast(fcx.llenv, + llclosure_ptr_ty); // "target", in this context, means the function that's having some of its // arguments bound and that will be called inside the thunk we're @@ -5442,11 +5448,11 @@ fn trans_bind_thunk(&@local_ctxt cx, &span sp, &ty::t incoming_fty, let uint i = 0u; while (i < ty_param_count) { auto lltyparam_ptr = - GEP_tup_like(bcx, closure_ty, llclosure, + GEP_tup_like(copy_args_bcx, closure_ty, llclosure, ~[0, abi::box_rc_field_body, abi::closure_elt_ty_params, i as int]); - bcx = lltyparam_ptr.bcx; - auto td = bcx.build.Load(lltyparam_ptr.val); + copy_args_bcx = lltyparam_ptr.bcx; + auto td = copy_args_bcx.build.Load(lltyparam_ptr.val); llargs += ~[td]; fcx.lltydescs += ~[td]; i += 1u; @@ -5480,8 +5486,12 @@ fn trans_bind_thunk(&@local_ctxt cx, &span sp, &ty::t incoming_fty, bcx = copy_ty(bcx, val, e_ty).bcx; val = bcx.build.Load(val); } - } else if (ty::type_contains_params(cx.ccx.tcx, out_arg.ty)) { - assert (out_arg.mode != ty::mo_val); + } + // If the type is parameterized, then we need to cast the + // type we actually have to the parameterized out type. + if (ty::type_contains_params(cx.ccx.tcx, out_arg.ty)) { + // FIXME: (#642) This works for boxes and alias params + // but does not work for bare functions. val = bcx.build.PointerCast(val, llout_arg_ty); } llargs += ~[val]; diff --git a/src/test/run-pass/fixed-point-bind-box.rs b/src/test/run-pass/fixed-point-bind-box.rs new file mode 100644 index 0000000000000..d53e4655c07c9 --- /dev/null +++ b/src/test/run-pass/fixed-point-bind-box.rs @@ -0,0 +1,20 @@ +// xfail-stage0 + +fn fix_help[A,B](@fn (@fn (&A) -> B, &A) -> B f, &A x) -> B { + ret f(@bind fix_help(f, _), x); +} + +fn fix[A,B](@fn (@fn (&A) -> B, &A) -> B f) -> (@fn(&A) -> B) { + ret @bind fix_help(f, _); +} + +fn fact_(@fn (&int) -> int f, &int n) -> int { + // fun fact 0 = 1 + ret if (n == 0) { 1 } else { n*f(n-1) }; +} + +fn main() { + auto fact = fix(@fact_); + assert(fact(5) == 120); + assert(fact(2) == 2); +}