]> git.lizzy.rs Git - rust.git/blob - src/comp/middle/trans_closure.rs
831a5b4e41e8b3d12c545e0c5cd26a9f4fd68691
[rust.git] / src / comp / middle / trans_closure.rs
1 import syntax::ast;
2 import syntax::ast_util;
3 import lib::llvm::llvm;
4 import llvm::{ValueRef, TypeRef};
5 import trans_common::*;
6 import trans_build::*;
7 import trans::*;
8 import middle::freevars::{get_freevars, freevar_info};
9 import option::{some, none};
10 import back::abi;
11 import syntax::codemap::span;
12 import back::link::{
13     mangle_internal_name_by_path,
14     mangle_internal_name_by_path_and_seq};
15 import trans::{
16     trans_shared_malloc,
17     type_of_inner,
18     size_of,
19     node_id_type,
20     INIT,
21     trans_shared_free,
22     drop_ty,
23     new_sub_block_ctxt,
24     load_if_immediate,
25     dest
26 };
27
28 // ___Good to know (tm)__________________________________________________
29 //
30 // The layout of a closure environment in memory is
31 // roughly as follows:
32 //
33 // struct closure_box {
34 //    unsigned ref_count; // only used for sharid environments
35 //    struct closure {
36 //      type_desc *tydesc;         // descriptor for the "struct closure" type
37 //      type_desc *bound_tdescs[]; // bound descriptors
38 //      struct {
39 //          upvar1_t upvar1;
40 //          ...
41 //          upvarN_t upvarN;
42 //      } bound_data;
43 //   };
44 // };
45 //
46 // NB: this struct is defined in the code in trans_common::T_closure()
47 // and mk_closure_ty() below.  The former defines the LLVM version and
48 // the latter the Rust equivalent.  It occurs to me that these could
49 // perhaps be unified, but currently they are not.
50 //
51 // Note that the closure carries a type descriptor that describes
52 // itself.  Trippy.  This is needed because the precise types of the
53 // closed over data are lost in the closure type (`fn(T)->U`), so if
54 // we need to take/drop, we must know what data is in the upvars and
55 // so forth.
56 //
57 // The allocation strategy for this closure depends on the closure
58 // type.  For a sendfn, the closure (and the referenced type
59 // descriptors) will be allocated in the exchange heap.  For a fn, the
60 // closure is allocated in the task heap and is reference counted.
61 // For a block, the closure is allocated on the stack.  Note that in
62 // all cases we allocate space for a ref count just to make our lives
63 // easier when upcasting to block(T)->U, in the shape code, and so
64 // forth.
65 //
66 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
67
68 tag environment_value {
69     // Evaluate expr and store result in env (used for bind).
70     env_expr(@ast::expr);
71
72     // Copy the value from this llvm ValueRef into the environment.
73     env_copy(ValueRef, ty::t, lval_kind);
74
75     // Move the value from this llvm ValueRef into the environment.
76     env_move(ValueRef, ty::t, lval_kind);
77
78     // Access by reference (used for blocks).
79     env_ref(ValueRef, ty::t, lval_kind);
80 }
81
82 // Given a closure ty, emits a corresponding tuple ty
83 fn mk_closure_ty(tcx: ty::ctxt,
84                  ck: ty::closure_kind,
85                  ty_params: [fn_ty_param],
86                  bound_data_ty: ty::t)
87     -> ty::t {
88     let tydesc_ty = alt ck {
89       ty::closure_block. | ty::closure_shared. { ty::mk_type(tcx) }
90       ty::closure_send. { ty::mk_send_type(tcx) }
91     };
92     let param_ptrs = [];
93     for tp in ty_params {
94         param_ptrs += [tydesc_ty];
95         option::may(tp.dicts) {|dicts|
96             for dict in dicts { param_ptrs += [tydesc_ty]; }
97         }
98     }
99     ty::mk_tup(tcx, [tydesc_ty, ty::mk_tup(tcx, param_ptrs), bound_data_ty])
100 }
101
102 fn shared_opaque_closure_box_ty(tcx: ty::ctxt) -> ty::t {
103     let opaque_closure_ty = ty::mk_opaque_closure(tcx);
104     ret ty::mk_imm_box(tcx, opaque_closure_ty);
105 }
106
107 fn send_opaque_closure_box_ty(tcx: ty::ctxt) -> ty::t {
108     let opaque_closure_ty = ty::mk_opaque_closure(tcx);
109     let tup_ty = ty::mk_tup(tcx, [ty::mk_int(tcx), opaque_closure_ty]);
110     ret ty::mk_uniq(tcx, {ty: tup_ty, mut: ast::imm});
111 }
112
113 type closure_result = {
114     llbox: ValueRef,  // llvalue of boxed environment
115     box_ty: ty::t,    // type of boxed environment
116     bcx: @block_ctxt  // final bcx
117 };
118
119 // Given a block context and a list of tydescs and values to bind
120 // construct a closure out of them. If copying is true, it is a
121 // heap allocated closure that copies the upvars into environment.
122 // Otherwise, it is stack allocated and copies pointers to the upvars.
123 fn store_environment(
124     bcx: @block_ctxt, lltyparams: [fn_ty_param],
125     bound_values: [environment_value],
126     ck: ty::closure_kind)
127     -> closure_result {
128
129     fn dummy_environment_box(bcx: @block_ctxt, r: result)
130         -> (@block_ctxt, ValueRef, ValueRef) {
131         // Prevent glue from trying to free this.
132         let ccx = bcx_ccx(bcx);
133         let ref_cnt = GEPi(bcx, r.val, [0, abi::box_rc_field_refcnt]);
134         Store(r.bcx, C_int(ccx, 2), ref_cnt);
135         let closure = GEPi(r.bcx, r.val, [0, abi::box_rc_field_body]);
136         (r.bcx, closure, r.val)
137     }
138
139     fn maybe_clone_tydesc(bcx: @block_ctxt,
140                           ck: ty::closure_kind,
141                           td: ValueRef) -> ValueRef {
142         ret alt ck {
143           ty::closure_block. | ty::closure_shared. {
144             td
145           }
146           ty::closure_send. {
147             Call(bcx, bcx_ccx(bcx).upcalls.create_shared_type_desc, [td])
148           }
149         };
150     }
151
152     //let ccx = bcx_ccx(bcx);
153     let tcx = bcx_tcx(bcx);
154
155     // First, synthesize a tuple type containing the types of all the
156     // bound expressions.
157     // bindings_ty = [bound_ty1, bound_ty2, ...]
158     let bound_tys = [];
159     for bv in bound_values {
160         bound_tys += [alt bv {
161             env_copy(_, t, _) { t }
162             env_move(_, t, _) { t }
163             env_ref(_, t, _) { t }
164             env_expr(e) { ty::expr_ty(tcx, e) }
165         }];
166     }
167     let bound_data_ty = ty::mk_tup(tcx, bound_tys);
168     let closure_ty =
169         mk_closure_ty(tcx, ck, lltyparams, bound_data_ty);
170
171     let temp_cleanups = [];
172
173     // Allocate a box that can hold something closure-sized.
174     //
175     // For now, no matter what kind of closure we have, we always allocate
176     // space for a ref cnt in the closure.  If the closure is a block or
177     // unique closure, this ref count isn't really used: we initialize it to 2
178     // so that it will never drop to zero.  This is a hack and could go away
179     // but then we'd have to modify the code to do the right thing when
180     // casting from a shared closure to a block.
181     let (bcx, closure, box) = alt ck {
182       ty::closure_shared. {
183         let r = trans::trans_malloc_boxed(bcx, closure_ty);
184         add_clean_free(bcx, r.box, false);
185         temp_cleanups += [r.box];
186         (r.bcx, r.body, r.box)
187       }
188       ty::closure_send. {
189         // Dummy up a box in the exchange heap.
190         let tup_ty = ty::mk_tup(tcx, [ty::mk_int(tcx), closure_ty]);
191         let box_ty = ty::mk_uniq(tcx, {ty: tup_ty, mut: ast::imm});
192         check trans_uniq::type_is_unique_box(bcx, box_ty);
193         let r = trans_uniq::alloc_uniq(bcx, box_ty);
194         add_clean_free(bcx, r.val, true);
195         temp_cleanups += [r.val];
196         dummy_environment_box(bcx, r)
197       }
198       ty::closure_block. {
199         // Dummy up a box on the stack,
200         let ty = ty::mk_tup(tcx, [ty::mk_int(tcx), closure_ty]);
201         let r = trans::alloc_ty(bcx, ty);
202         dummy_environment_box(bcx, r)
203       }
204     };
205
206     // Store bindings tydesc.
207     alt ck {
208       ty::closure_shared. | ty::closure_send. {
209         let bound_tydesc = GEPi(bcx, closure, [0, abi::closure_elt_tydesc]);
210         let ti = none;
211
212         // NDM I believe this is the correct value,
213         // but using it exposes bugs and limitations
214         // in the shape code.  Therefore, I am using
215         // tps_normal, which is what we used before.
216         //
217         // let tps = tps_fn(vec::len(lltyparams));
218
219         let tps = tps_normal;
220         let {result:closure_td, _} =
221             trans::get_tydesc(bcx, closure_ty, true, tps, ti);
222         trans::lazily_emit_tydesc_glue(bcx, abi::tydesc_field_take_glue, ti);
223         trans::lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, ti);
224         trans::lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti);
225         bcx = closure_td.bcx;
226         let td = maybe_clone_tydesc(bcx, ck, closure_td.val);
227         Store(bcx, td, bound_tydesc);
228       }
229       ty::closure_block. { /* skip this for blocks, not really relevant */ }
230     }
231
232     check type_is_tup_like(bcx, closure_ty);
233     let box_ty = ty::mk_imm_box(bcx_tcx(bcx), closure_ty);
234
235     // If necessary, copy tydescs describing type parameters into the
236     // appropriate slot in the closure.
237     let {bcx:bcx, val:ty_params_slot} =
238         GEP_tup_like_1(bcx, closure_ty, closure,
239                        [0, abi::closure_elt_ty_params]);
240     let off = 0;
241
242     for tp in lltyparams {
243         let cloned_td = maybe_clone_tydesc(bcx, ck, tp.desc);
244         Store(bcx, cloned_td, GEPi(bcx, ty_params_slot, [0, off]));
245         off += 1;
246         option::may(tp.dicts, {|dicts|
247             for dict in dicts {
248                 let cast = PointerCast(bcx, dict, val_ty(cloned_td));
249                 Store(bcx, cast, GEPi(bcx, ty_params_slot, [0, off]));
250                 off += 1;
251             }
252         });
253     }
254
255     // Copy expr values into boxed bindings.
256     // Silly check
257     vec::iteri(bound_values) { |i, bv|
258         let bound = trans::GEP_tup_like_1(bcx, box_ty, box,
259                                           [0, abi::box_rc_field_body,
260                                            abi::closure_elt_bindings,
261                                            i as int]);
262         bcx = bound.bcx;
263         alt bv {
264           env_expr(e) {
265             bcx = trans::trans_expr_save_in(bcx, e, bound.val);
266             add_clean_temp_mem(bcx, bound.val, bound_tys[i]);
267             temp_cleanups += [bound.val];
268           }
269           env_copy(val, ty, owned.) {
270             let val1 = load_if_immediate(bcx, val, ty);
271             bcx = trans::copy_val(bcx, INIT, bound.val, val1, ty);
272           }
273           env_copy(val, ty, owned_imm.) {
274             bcx = trans::copy_val(bcx, INIT, bound.val, val, ty);
275           }
276           env_copy(_, _, temporary.) {
277             fail "Cannot capture temporary upvar";
278           }
279           env_move(val, ty, kind) {
280             let src = {bcx:bcx, val:val, kind:kind};
281             bcx = move_val(bcx, INIT, bound.val, src, ty);
282           }
283           env_ref(val, ty, owned.) {
284             Store(bcx, val, bound.val);
285           }
286           env_ref(val, ty, owned_imm.) {
287             let addr = do_spill_noroot(bcx, val);
288             Store(bcx, addr, bound.val);
289           }
290           env_ref(_, _, temporary.) {
291             fail "Cannot capture temporary upvar";
292           }
293         }
294     }
295     for cleanup in temp_cleanups { revoke_clean(bcx, cleanup); }
296
297     ret {llbox: box, box_ty: box_ty, bcx: bcx};
298 }
299
300 // Given a context and a list of upvars, build a closure. This just
301 // collects the upvars and packages them up for store_environment.
302 fn build_closure(bcx0: @block_ctxt,
303                  cap_vars: [capture::capture_var],
304                  ck: ty::closure_kind)
305     -> closure_result {
306     // If we need to, package up the iterator body to call
307     let env_vals = [];
308     let bcx = bcx0;
309     let tcx = bcx_tcx(bcx);
310
311     // Package up the captured upvars
312     vec::iter(cap_vars) { |cap_var|
313         let lv = trans_local_var(bcx, cap_var.def);
314         let nid = ast_util::def_id_of_def(cap_var.def).node;
315         let ty = ty::node_id_to_monotype(tcx, nid);
316         alt cap_var.mode {
317           capture::cap_ref. {
318             assert ck == ty::closure_block;
319             ty = ty::mk_mut_ptr(tcx, ty);
320             env_vals += [env_ref(lv.val, ty, lv.kind)];
321           }
322           capture::cap_copy. {
323             env_vals += [env_copy(lv.val, ty, lv.kind)];
324           }
325           capture::cap_move. {
326             env_vals += [env_move(lv.val, ty, lv.kind)];
327           }
328           capture::cap_drop. {
329             bcx = drop_ty(bcx, lv.val, ty);
330           }
331         }
332     }
333     ret store_environment(bcx, copy bcx.fcx.lltyparams, env_vals, ck);
334 }
335
336 // Given an enclosing block context, a new function context, a closure type,
337 // and a list of upvars, generate code to load and populate the environment
338 // with the upvars and type descriptors.
339 fn load_environment(enclosing_cx: @block_ctxt,
340                     fcx: @fn_ctxt,
341                     boxed_closure_ty: ty::t,
342                     cap_vars: [capture::capture_var],
343                     ck: ty::closure_kind) {
344     let bcx = new_raw_block_ctxt(fcx, fcx.llloadenv);
345
346     let ccx = bcx_ccx(bcx);
347     let sp = bcx.sp;
348     check (type_has_static_size(ccx, boxed_closure_ty));
349     let llty = type_of(ccx, sp, boxed_closure_ty);
350     let llclosure = PointerCast(bcx, fcx.llenv, llty);
351
352     // Populate the type parameters from the environment. We need to
353     // do this first because the tydescs are needed to index into
354     // the bindings if they are dynamically sized.
355     let lltydescs = GEPi(bcx, llclosure,
356                          [0, abi::box_rc_field_body,
357                           abi::closure_elt_ty_params]);
358     let off = 0;
359     for tp in copy enclosing_cx.fcx.lltyparams {
360         let tydesc = Load(bcx, GEPi(bcx, lltydescs, [0, off]));
361         off += 1;
362         let dicts = option::map(tp.dicts, {|dicts|
363             let rslt = [];
364             for dict in dicts {
365                 let dict = Load(bcx, GEPi(bcx, lltydescs, [0, off]));
366                 rslt += [PointerCast(bcx, dict, T_ptr(T_dict()))];
367                 off += 1;
368             }
369             rslt
370         });
371         fcx.lltyparams += [{desc: tydesc, dicts: dicts}];
372     }
373
374     // Populate the upvars from the environment.
375     let path = [0, abi::box_rc_field_body, abi::closure_elt_bindings];
376     let i = 0u;
377     vec::iter(cap_vars) { |cap_var|
378         alt cap_var.mode {
379           capture::cap_drop. { /* ignore */ }
380           _ {
381             check type_is_tup_like(bcx, boxed_closure_ty);
382             let upvarptr = GEP_tup_like(
383                 bcx, boxed_closure_ty, llclosure, path + [i as int]);
384             bcx = upvarptr.bcx;
385             let llupvarptr = upvarptr.val;
386             alt ck {
387               ty::closure_block. { llupvarptr = Load(bcx, llupvarptr); }
388               ty::closure_send. | ty::closure_shared. { }
389             }
390             let def_id = ast_util::def_id_of_def(cap_var.def);
391             fcx.llupvars.insert(def_id.node, llupvarptr);
392             i += 1u;
393           }
394         }
395     }
396 }
397
398 fn trans_expr_fn(bcx: @block_ctxt,
399                  proto: ast::proto,
400                  decl: ast::fn_decl,
401                  body: ast::blk,
402                  sp: span,
403                  id: ast::node_id,
404                  cap_clause: ast::capture_clause,
405                  dest: dest) -> @block_ctxt {
406     if dest == ignore { ret bcx; }
407     let ccx = bcx_ccx(bcx), bcx = bcx;
408     let fty = node_id_type(ccx, id);
409     let llfnty = type_of_fn_from_ty(ccx, sp, fty, []);
410     let sub_cx = extend_path(bcx.fcx.lcx, ccx.names.next("anon"));
411     let s = mangle_internal_name_by_path(ccx, sub_cx.path);
412     let llfn = decl_internal_cdecl_fn(ccx.llmod, s, llfnty);
413     register_fn(ccx, sp, sub_cx.path, "anon fn", [], id);
414
415     let trans_closure_env = lambda(ck: ty::closure_kind) -> ValueRef {
416         let cap_vars = capture::compute_capture_vars(
417             ccx.tcx, id, proto, cap_clause);
418         let {llbox, box_ty, bcx} = build_closure(bcx, cap_vars, ck);
419         trans_closure(sub_cx, sp, decl, body, llfn, no_self, [], id, {|fcx|
420             load_environment(bcx, fcx, box_ty, cap_vars, ck);
421         });
422         llbox
423     };
424
425     let closure = alt proto {
426       ast::proto_block. { trans_closure_env(ty::closure_block) }
427       ast::proto_shared(_) { trans_closure_env(ty::closure_shared) }
428       ast::proto_send. { trans_closure_env(ty::closure_send) }
429       ast::proto_bare. {
430         let closure = C_null(T_opaque_boxed_closure_ptr(ccx));
431         trans_closure(sub_cx, sp, decl, body, llfn, no_self, [],
432                       id, {|_fcx|});
433         closure
434       }
435     };
436     fill_fn_pair(bcx, get_dest_addr(dest), llfn, closure);
437     ret bcx;
438 }
439
440 fn trans_bind(cx: @block_ctxt, f: @ast::expr, args: [option::t<@ast::expr>],
441               id: ast::node_id, dest: dest) -> @block_ctxt {
442     let f_res = trans_callee(cx, f);
443     ret trans_bind_1(cx, ty::expr_ty(bcx_tcx(cx), f), f_res, args,
444                      ty::node_id_to_type(bcx_tcx(cx), id), dest);
445 }
446
447 fn trans_bind_1(cx: @block_ctxt, outgoing_fty: ty::t,
448                 f_res: lval_maybe_callee,
449                 args: [option::t<@ast::expr>], pair_ty: ty::t,
450                 dest: dest) -> @block_ctxt {
451     let bound: [@ast::expr] = [];
452     for argopt: option::t<@ast::expr> in args {
453         alt argopt { none. { } some(e) { bound += [e]; } }
454     }
455     let bcx = f_res.bcx;
456     if dest == ignore {
457         for ex in bound { bcx = trans_expr(bcx, ex, ignore); }
458         ret bcx;
459     }
460
461     // Figure out which tydescs we need to pass, if any.
462     let (outgoing_fty_real, lltydescs, param_bounds) = alt f_res.generic {
463       none. { (outgoing_fty, [], @[]) }
464       some(ginfo) {
465         let tds = [], orig = 0u;
466         vec::iter2(ginfo.tydescs, *ginfo.param_bounds) {|td, bounds|
467             tds += [td];
468             for bound in *bounds {
469                 alt bound {
470                   ty::bound_iface(_) {
471                     let dict = trans_impl::get_dict(
472                         bcx, option::get(ginfo.origins)[orig]);
473                     tds += [PointerCast(bcx, dict.val, val_ty(td))];
474                     orig += 1u;
475                     bcx = dict.bcx;
476                   }
477                   _ {}
478                 }
479             }
480         }
481         lazily_emit_all_generic_info_tydesc_glues(cx, ginfo);
482         (ginfo.item_type, tds, ginfo.param_bounds)
483       }
484     };
485
486     if vec::len(bound) == 0u && vec::len(lltydescs) == 0u {
487         // Trivial 'binding': just return the closure
488         let lv = lval_maybe_callee_to_lval(f_res, pair_ty);
489         bcx = lv.bcx;
490         ret memmove_ty(bcx, get_dest_addr(dest), lv.val, pair_ty);
491     }
492     let closure = alt f_res.env {
493       null_env. { none }
494       _ { let (_, cl) = maybe_add_env(cx, f_res); some(cl) }
495     };
496
497     // FIXME: should follow from a precondition on trans_bind_1
498     let ccx = bcx_ccx(cx);
499     check (type_has_static_size(ccx, outgoing_fty));
500
501     // Arrange for the bound function to live in the first binding spot
502     // if the function is not statically known.
503     let (env_vals, target_res) = alt closure {
504       some(cl) {
505         // Cast the function we are binding to be the type that the
506         // closure will expect it to have. The type the closure knows
507         // about has the type parameters substituted with the real types.
508         let sp = cx.sp;
509         let llclosurety = T_ptr(type_of(ccx, sp, outgoing_fty));
510         let src_loc = PointerCast(bcx, cl, llclosurety);
511         ([env_copy(src_loc, pair_ty, owned)], none)
512       }
513       none. { ([], some(f_res.val)) }
514     };
515
516     // Actually construct the closure
517     let {llbox, box_ty, bcx} = store_environment(
518         bcx, vec::map(lltydescs, {|d| {desc: d, dicts: none}}),
519         env_vals + vec::map(bound, {|x| env_expr(x)}),
520         ty::closure_shared);
521
522     // Make thunk
523     let llthunk =
524         trans_bind_thunk(cx.fcx.lcx, cx.sp, pair_ty, outgoing_fty_real, args,
525                          box_ty, *param_bounds, target_res);
526
527     // Fill the function pair
528     fill_fn_pair(bcx, get_dest_addr(dest), llthunk.val, llbox);
529     ret bcx;
530 }
531
532 fn make_fn_glue(
533     cx: @block_ctxt,
534     v: ValueRef,
535     t: ty::t,
536     glue_fn: fn(@block_ctxt, v: ValueRef, t: ty::t) -> @block_ctxt)
537     -> @block_ctxt {
538     let bcx = cx;
539     let tcx = bcx_tcx(cx);
540
541     let fn_env = lambda(blk: block(@block_ctxt, ValueRef) -> @block_ctxt)
542         -> @block_ctxt {
543         let box_cell_v = GEPi(cx, v, [0, abi::fn_field_box]);
544         let box_ptr_v = Load(cx, box_cell_v);
545         let inner_cx = new_sub_block_ctxt(cx, "iter box");
546         let next_cx = new_sub_block_ctxt(cx, "next");
547         let null_test = IsNull(cx, box_ptr_v);
548         CondBr(cx, null_test, next_cx.llbb, inner_cx.llbb);
549         inner_cx = blk(inner_cx, box_cell_v);
550         Br(inner_cx, next_cx.llbb);
551         ret next_cx;
552     };
553
554     ret alt ty::struct(tcx, t) {
555       ty::ty_native_fn(_, _) | ty::ty_fn({proto: ast::proto_bare., _}) {
556         bcx
557       }
558       ty::ty_fn({proto: ast::proto_block., _}) {
559         bcx
560       }
561       ty::ty_fn({proto: ast::proto_send., _}) {
562         fn_env({ |bcx, box_cell_v|
563             let box_ty = trans_closure::send_opaque_closure_box_ty(tcx);
564             glue_fn(bcx, box_cell_v, box_ty)
565         })
566       }
567       ty::ty_fn({proto: ast::proto_shared(_), _}) {
568         fn_env({ |bcx, box_cell_v|
569             let box_ty = trans_closure::shared_opaque_closure_box_ty(tcx);
570             glue_fn(bcx, box_cell_v, box_ty)
571         })
572       }
573       _ { fail "make_fn_glue invoked on non-function type" }
574     };
575 }
576
577 fn call_opaque_closure_glue(bcx: @block_ctxt,
578                             v: ValueRef,     // ptr to an opaque closure
579                             field: int) -> @block_ctxt {
580     let ccx = bcx_ccx(bcx);
581     let v = PointerCast(bcx, v, T_ptr(T_opaque_closure(ccx)));
582     let tydescptr = GEPi(bcx, v, [0, abi::closure_elt_tydesc]);
583     let tydesc = Load(bcx, tydescptr);
584     let ti = none;
585     call_tydesc_glue_full(bcx, v, tydesc, field, ti);
586     ret bcx;
587 }
588
589 // pth is cx.path
590 fn trans_bind_thunk(cx: @local_ctxt,
591                     sp: span,
592                     incoming_fty: ty::t,
593                     outgoing_fty: ty::t,
594                     args: [option::t<@ast::expr>],
595                     boxed_closure_ty: ty::t,
596                     param_bounds: [ty::param_bounds],
597                     target_fn: option::t<ValueRef>)
598     -> {val: ValueRef, ty: TypeRef} {
599     // If we supported constraints on record fields, we could make the
600     // constraints for this function:
601     /*
602     : returns_non_ty_var(ccx, outgoing_fty),
603       type_has_static_size(ccx, incoming_fty) ->
604     */
605     // but since we don't, we have to do the checks at the beginning.
606     let ccx = cx.ccx;
607     check type_has_static_size(ccx, incoming_fty);
608
609     // Here we're not necessarily constructing a thunk in the sense of
610     // "function with no arguments".  The result of compiling 'bind f(foo,
611     // bar, baz)' would be a thunk that, when called, applies f to those
612     // arguments and returns the result.  But we're stretching the meaning of
613     // the word "thunk" here to also mean the result of compiling, say, 'bind
614     // f(foo, _, baz)', or any other bind expression that binds f and leaves
615     // some (or all) of the arguments unbound.
616
617     // Here, 'incoming_fty' is the type of the entire bind expression, while
618     // 'outgoing_fty' is the type of the function that is having some of its
619     // arguments bound.  If f is a function that takes three arguments of type
620     // int and returns int, and we're translating, say, 'bind f(3, _, 5)',
621     // then outgoing_fty is the type of f, which is (int, int, int) -> int,
622     // and incoming_fty is the type of 'bind f(3, _, 5)', which is int -> int.
623
624     // Once translated, the entire bind expression will be the call f(foo,
625     // bar, baz) wrapped in a (so-called) thunk that takes 'bar' as its
626     // argument and that has bindings of 'foo' to 3 and 'baz' to 5 and a
627     // pointer to 'f' all saved in its environment.  So, our job is to
628     // construct and return that thunk.
629
630     // Give the thunk a name, type, and value.
631     let s: str = mangle_internal_name_by_path_and_seq(ccx, cx.path, "thunk");
632     let llthunk_ty: TypeRef = get_pair_fn_ty(type_of(ccx, sp, incoming_fty));
633     let llthunk: ValueRef = decl_internal_cdecl_fn(ccx.llmod, s, llthunk_ty);
634
635     // Create a new function context and block context for the thunk, and hold
636     // onto a pointer to the first block in the function for later use.
637     let fcx = new_fn_ctxt(cx, sp, llthunk);
638     let bcx = new_top_block_ctxt(fcx);
639     let lltop = bcx.llbb;
640     // Since we might need to construct derived tydescs that depend on
641     // our bound tydescs, we need to load tydescs out of the environment
642     // before derived tydescs are constructed. To do this, we load them
643     // in the load_env block.
644     let l_bcx = new_raw_block_ctxt(fcx, fcx.llloadenv);
645
646     // The 'llenv' that will arrive in the thunk we're creating is an
647     // environment that will contain the values of its arguments and a pointer
648     // to the original function.  So, let's create one of those:
649
650     // The llenv pointer needs to be the correct size.  That size is
651     // 'boxed_closure_ty', which was determined by trans_bind.
652     check (type_has_static_size(ccx, boxed_closure_ty));
653     let llclosure_ptr_ty = type_of(ccx, sp, boxed_closure_ty);
654     let llclosure = PointerCast(l_bcx, fcx.llenv, llclosure_ptr_ty);
655
656     // "target", in this context, means the function that's having some of its
657     // arguments bound and that will be called inside the thunk we're
658     // creating.  (In our running example, target is the function f.)  Pick
659     // out the pointer to the target function from the environment. The
660     // target function lives in the first binding spot.
661     let (lltargetfn, lltargetenv, starting_idx) = alt target_fn {
662       some(fptr) {
663         (fptr, llvm::LLVMGetUndef(T_opaque_boxed_closure_ptr(ccx)), 0)
664       }
665       none. {
666         // Silly check
667         check type_is_tup_like(bcx, boxed_closure_ty);
668         let {bcx: cx, val: pair} =
669             GEP_tup_like(bcx, boxed_closure_ty, llclosure,
670                          [0, abi::box_rc_field_body,
671                           abi::closure_elt_bindings, 0]);
672         let lltargetenv =
673             Load(cx, GEPi(cx, pair, [0, abi::fn_field_box]));
674         let lltargetfn = Load
675             (cx, GEPi(cx, pair, [0, abi::fn_field_code]));
676         bcx = cx;
677         (lltargetfn, lltargetenv, 1)
678       }
679     };
680
681     // And then, pick out the target function's own environment.  That's what
682     // we'll use as the environment the thunk gets.
683
684     // Get f's return type, which will also be the return type of the entire
685     // bind expression.
686     let outgoing_ret_ty = ty::ty_fn_ret(cx.ccx.tcx, outgoing_fty);
687
688     // Get the types of the arguments to f.
689     let outgoing_args = ty::ty_fn_args(cx.ccx.tcx, outgoing_fty);
690
691     // The 'llretptr' that will arrive in the thunk we're creating also needs
692     // to be the correct type.  Cast it to f's return type, if necessary.
693     let llretptr = fcx.llretptr;
694     let ccx = cx.ccx;
695     if ty::type_contains_params(ccx.tcx, outgoing_ret_ty) {
696         check non_ty_var(ccx, outgoing_ret_ty);
697         let llretty = type_of_inner(ccx, sp, outgoing_ret_ty);
698         llretptr = PointerCast(bcx, llretptr, T_ptr(llretty));
699     }
700
701     // Set up the three implicit arguments to the thunk.
702     let llargs: [ValueRef] = [llretptr, lltargetenv];
703
704     // Copy in the type parameters.
705     check type_is_tup_like(l_bcx, boxed_closure_ty);
706     let {bcx: l_bcx, val: param_record} =
707         GEP_tup_like(l_bcx, boxed_closure_ty, llclosure,
708                      [0, abi::box_rc_field_body, abi::closure_elt_ty_params]);
709     let off = 0;
710     for param in param_bounds {
711         let dsc = Load(l_bcx, GEPi(l_bcx, param_record, [0, off])),
712             dicts = none;
713         llargs += [dsc];
714         off += 1;
715         for bound in *param {
716             alt bound {
717               ty::bound_iface(_) {
718                 let dict = Load(l_bcx, GEPi(l_bcx, param_record, [0, off]));
719                 dict = PointerCast(l_bcx, dict, T_ptr(T_dict()));
720                 llargs += [dict];
721                 off += 1;
722                 dicts = some(alt dicts {
723                   none. { [dict] }
724                   some(ds) { ds + [dict] }
725                 });
726               }
727               _ {}
728             }
729         }
730         fcx.lltyparams += [{desc: dsc, dicts: dicts}];
731     }
732
733     let a: uint = 2u; // retptr, env come first
734     let b: int = starting_idx;
735     let outgoing_arg_index: uint = 0u;
736     let llout_arg_tys: [TypeRef] =
737         type_of_explicit_args(cx.ccx, sp, outgoing_args);
738     for arg: option::t<@ast::expr> in args {
739         let out_arg = outgoing_args[outgoing_arg_index];
740         let llout_arg_ty = llout_arg_tys[outgoing_arg_index];
741         alt arg {
742           // Arg provided at binding time; thunk copies it from
743           // closure.
744           some(e) {
745             // Silly check
746             check type_is_tup_like(bcx, boxed_closure_ty);
747             let bound_arg =
748                 GEP_tup_like(bcx, boxed_closure_ty, llclosure,
749                              [0, abi::box_rc_field_body,
750                               abi::closure_elt_bindings, b]);
751             bcx = bound_arg.bcx;
752             let val = bound_arg.val;
753             if out_arg.mode == ast::by_val { val = Load(bcx, val); }
754             if out_arg.mode == ast::by_copy {
755                 let {bcx: cx, val: alloc} = alloc_ty(bcx, out_arg.ty);
756                 bcx = memmove_ty(cx, alloc, val, out_arg.ty);
757                 bcx = take_ty(bcx, alloc, out_arg.ty);
758                 val = alloc;
759             }
760             // If the type is parameterized, then we need to cast the
761             // type we actually have to the parameterized out type.
762             if ty::type_contains_params(cx.ccx.tcx, out_arg.ty) {
763                 val = PointerCast(bcx, val, llout_arg_ty);
764             }
765             llargs += [val];
766             b += 1;
767           }
768
769           // Arg will be provided when the thunk is invoked.
770           none. {
771             let arg: ValueRef = llvm::LLVMGetParam(llthunk, a);
772             if ty::type_contains_params(cx.ccx.tcx, out_arg.ty) {
773                 arg = PointerCast(bcx, arg, llout_arg_ty);
774             }
775             llargs += [arg];
776             a += 1u;
777           }
778         }
779         outgoing_arg_index += 1u;
780     }
781
782     // Cast the outgoing function to the appropriate type.
783     // This is necessary because the type of the function that we have
784     // in the closure does not know how many type descriptors the function
785     // needs to take.
786     let ccx = bcx_ccx(bcx);
787
788     let lltargetty =
789         type_of_fn_from_ty(ccx, sp, outgoing_fty, param_bounds);
790     lltargetfn = PointerCast(bcx, lltargetfn, T_ptr(lltargetty));
791     Call(bcx, lltargetfn, llargs);
792     build_return(bcx);
793     finish_fn(fcx, lltop);
794     ret {val: llthunk, ty: llthunk_ty};
795 }