]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/trans/callee.rs
Port regionck from oldvisit to <V:Visitor> trait API.
[rust.git] / src / librustc / middle / trans / callee.rs
1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 /*!
12  * Handles translation of callees as well as other call-related
13  * things.  Callees are a superset of normal rust values and sometimes
14  * have different representations.  In particular, top-level fn items
15  * and methods are represented as just a fn ptr and not a full
16  * closure.
17  */
18
19 use std::vec;
20
21 use back::abi;
22 use driver::session;
23 use lib::llvm::ValueRef;
24 use lib::llvm::llvm;
25 use metadata::csearch;
26 use middle::trans::base;
27 use middle::trans::base::*;
28 use middle::trans::build::*;
29 use middle::trans::callee;
30 use middle::trans::common;
31 use middle::trans::common::*;
32 use middle::trans::datum::*;
33 use middle::trans::datum::Datum;
34 use middle::trans::expr;
35 use middle::trans::glue;
36 use middle::trans::inline;
37 use middle::trans::meth;
38 use middle::trans::monomorphize;
39 use middle::trans::type_of;
40 use middle::ty;
41 use middle::subst::Subst;
42 use middle::typeck;
43 use middle::typeck::coherence::make_substs_for_receiver_types;
44 use util::ppaux::Repr;
45
46 use middle::trans::type_::Type;
47
48 use syntax::ast;
49 use syntax::ast_map;
50 use syntax::visit;
51 use syntax::visit::Visitor;
52
53 // Represents a (possibly monomorphized) top-level fn item or method
54 // item.  Note that this is just the fn-ptr and is not a Rust closure
55 // value (which is a pair).
56 pub struct FnData {
57     llfn: ValueRef,
58 }
59
60 pub struct MethodData {
61     llfn: ValueRef,
62     llself: ValueRef,
63     temp_cleanup: Option<ValueRef>,
64     self_mode: ty::SelfMode,
65 }
66
67 pub enum CalleeData {
68     Closure(Datum),
69     Fn(FnData),
70     Method(MethodData)
71 }
72
73 pub struct Callee {
74     bcx: @mut Block,
75     data: CalleeData
76 }
77
78 pub fn trans(bcx: @mut Block, expr: @ast::expr) -> Callee {
79     let _icx = push_ctxt("trans_callee");
80     debug!("callee::trans(expr=%s)", expr.repr(bcx.tcx()));
81
82     // pick out special kinds of expressions that can be called:
83     match expr.node {
84         ast::expr_path(_) => {
85             return trans_def(bcx, bcx.def(expr.id), expr);
86         }
87         _ => {}
88     }
89
90     // any other expressions are closures:
91     return datum_callee(bcx, expr);
92
93     fn datum_callee(bcx: @mut Block, expr: @ast::expr) -> Callee {
94         let DatumBlock {bcx, datum} = expr::trans_to_datum(bcx, expr);
95         match ty::get(datum.ty).sty {
96             ty::ty_bare_fn(*) => {
97                 let llval = datum.to_appropriate_llval(bcx);
98                 return Callee {bcx: bcx, data: Fn(FnData {llfn: llval})};
99             }
100             ty::ty_closure(*) => {
101                 return Callee {bcx: bcx, data: Closure(datum)};
102             }
103             _ => {
104                 bcx.tcx().sess.span_bug(
105                     expr.span,
106                     fmt!("Type of callee is neither bare-fn nor closure: %s",
107                          bcx.ty_to_str(datum.ty)));
108             }
109         }
110     }
111
112     fn fn_callee(bcx: @mut Block, fd: FnData) -> Callee {
113         return Callee {bcx: bcx, data: Fn(fd)};
114     }
115
116     fn trans_def(bcx: @mut Block, def: ast::def, ref_expr: @ast::expr) -> Callee {
117         match def {
118             ast::def_fn(did, _) | ast::def_static_method(did, None, _) => {
119                 fn_callee(bcx, trans_fn_ref(bcx, did, ref_expr.id))
120             }
121             ast::def_static_method(impl_did, Some(trait_did), _) => {
122                 fn_callee(bcx, meth::trans_static_method_callee(bcx, impl_did,
123                                                                 trait_did,
124                                                                 ref_expr.id))
125             }
126             ast::def_variant(tid, vid) => {
127                 // nullary variants are not callable
128                 assert!(ty::enum_variant_with_id(bcx.tcx(),
129                                                       tid,
130                                                       vid).args.len() > 0u);
131                 fn_callee(bcx, trans_fn_ref(bcx, vid, ref_expr.id))
132             }
133             ast::def_struct(def_id) => {
134                 fn_callee(bcx, trans_fn_ref(bcx, def_id, ref_expr.id))
135             }
136             ast::def_arg(*) |
137             ast::def_local(*) |
138             ast::def_binding(*) |
139             ast::def_upvar(*) |
140             ast::def_self(*) => {
141                 datum_callee(bcx, ref_expr)
142             }
143             ast::def_mod(*) | ast::def_foreign_mod(*) | ast::def_trait(*) |
144             ast::def_static(*) | ast::def_ty(*) | ast::def_prim_ty(*) |
145             ast::def_use(*) | ast::def_typaram_binder(*) |
146             ast::def_region(*) | ast::def_label(*) | ast::def_ty_param(*) |
147             ast::def_self_ty(*) | ast::def_method(*) => {
148                 bcx.tcx().sess.span_bug(
149                     ref_expr.span,
150                     fmt!("Cannot translate def %? \
151                           to a callable thing!", def));
152             }
153         }
154     }
155 }
156
157 pub fn trans_fn_ref_to_callee(bcx: @mut Block,
158                               def_id: ast::def_id,
159                               ref_id: ast::NodeId) -> Callee {
160     Callee {bcx: bcx,
161             data: Fn(trans_fn_ref(bcx, def_id, ref_id))}
162 }
163
164 pub fn trans_fn_ref(bcx: @mut Block,
165                     def_id: ast::def_id,
166                     ref_id: ast::NodeId) -> FnData {
167     /*!
168      *
169      * Translates a reference (with id `ref_id`) to the fn/method
170      * with id `def_id` into a function pointer.  This may require
171      * monomorphization or inlining. */
172
173     let _icx = push_ctxt("trans_fn_ref");
174
175     let type_params = node_id_type_params(bcx, ref_id);
176     let vtables = node_vtables(bcx, ref_id);
177     debug!("trans_fn_ref(def_id=%s, ref_id=%?, type_params=%s, vtables=%s)",
178            def_id.repr(bcx.tcx()), ref_id, type_params.repr(bcx.tcx()),
179            vtables.repr(bcx.tcx()));
180     trans_fn_ref_with_vtables(bcx, def_id, ref_id, type_params, vtables)
181 }
182
183 pub fn trans_fn_ref_with_vtables_to_callee(
184         bcx: @mut Block,
185         def_id: ast::def_id,
186         ref_id: ast::NodeId,
187         type_params: &[ty::t],
188         vtables: Option<typeck::vtable_res>)
189      -> Callee {
190     Callee {bcx: bcx,
191             data: Fn(trans_fn_ref_with_vtables(bcx, def_id, ref_id,
192                                                type_params, vtables))}
193 }
194
195 fn resolve_default_method_vtables(bcx: @mut Block,
196                                   impl_id: ast::def_id,
197                                   method: &ty::Method,
198                                   substs: &ty::substs,
199                                   impl_vtables: Option<typeck::vtable_res>)
200                           -> (typeck::vtable_res, typeck::vtable_param_res) {
201
202     // Get the vtables that the impl implements the trait at
203     let impl_res = ty::lookup_impl_vtables(bcx.tcx(), impl_id);
204
205     // Build up a param_substs that we are going to resolve the
206     // trait_vtables under.
207     let param_substs = Some(@param_substs {
208         tys: substs.tps.clone(),
209         self_ty: substs.self_ty,
210         vtables: impl_vtables,
211         self_vtables: None
212     });
213
214     let trait_vtables_fixed = resolve_vtables_under_param_substs(
215         bcx.tcx(), param_substs, impl_res.trait_vtables);
216
217     // Now we pull any vtables for parameters on the actual method.
218     let num_method_vtables = method.generics.type_param_defs.len();
219     let method_vtables = match impl_vtables {
220         Some(vtables) => {
221             let num_impl_type_parameters =
222                 vtables.len() - num_method_vtables;
223             vtables.tailn(num_impl_type_parameters).to_owned()
224         },
225         None => vec::from_elem(num_method_vtables, @~[])
226     };
227
228     let param_vtables = @(*trait_vtables_fixed + method_vtables);
229
230     let self_vtables = resolve_param_vtables_under_param_substs(
231         bcx.tcx(), param_substs, impl_res.self_vtables);
232
233     (param_vtables, self_vtables)
234 }
235
236
237 pub fn trans_fn_ref_with_vtables(
238         bcx: @mut Block,       //
239         def_id: ast::def_id,   // def id of fn
240         ref_id: ast::NodeId,  // node id of use of fn; may be zero if N/A
241         type_params: &[ty::t], // values for fn's ty params
242         vtables: Option<typeck::vtable_res>) // vtables for the call
243      -> FnData {
244     //!
245     //
246     // Translates a reference to a fn/method item, monomorphizing and
247     // inlining as it goes.
248     //
249     // # Parameters
250     //
251     // - `bcx`: the current block where the reference to the fn occurs
252     // - `def_id`: def id of the fn or method item being referenced
253     // - `ref_id`: node id of the reference to the fn/method, if applicable.
254     //   This parameter may be zero; but, if so, the resulting value may not
255     //   have the right type, so it must be cast before being used.
256     // - `type_params`: values for each of the fn/method's type parameters
257     // - `vtables`: values for each bound on each of the type parameters
258
259     let _icx = push_ctxt("trans_fn_ref_with_vtables");
260     let ccx = bcx.ccx();
261     let tcx = ccx.tcx;
262
263     debug!("trans_fn_ref_with_vtables(bcx=%s, def_id=%s, ref_id=%?, \
264             type_params=%s, vtables=%s)",
265            bcx.to_str(),
266            def_id.repr(bcx.tcx()),
267            ref_id,
268            type_params.repr(bcx.tcx()),
269            vtables.repr(bcx.tcx()));
270
271     assert!(type_params.iter().all(|t| !ty::type_needs_infer(*t)));
272
273     // Polytype of the function item (may have type params)
274     let fn_tpt = ty::lookup_item_type(tcx, def_id);
275
276     let substs = ty::substs { regions: ty::ErasedRegions,
277                               self_ty: None,
278                               tps: /*bad*/ type_params.to_owned() };
279
280     // We need to do a bunch of special handling for default methods.
281     // We need to modify the def_id and our substs in order to monomorphize
282     // the function.
283     let (is_default, def_id, substs, self_vtables, vtables) =
284         match ty::provided_source(tcx, def_id) {
285         None => (false, def_id, substs, None, vtables),
286         Some(source_id) => {
287             // There are two relevant substitutions when compiling
288             // default methods. First, there is the substitution for
289             // the type parameters of the impl we are using and the
290             // method we are calling. This substitution is the substs
291             // argument we already have.
292             // In order to compile a default method, though, we need
293             // to consider another substitution: the substitution for
294             // the type parameters on trait; the impl we are using
295             // implements the trait at some particular type
296             // parameters, and we need to substitute for those first.
297             // So, what we need to do is find this substitution and
298             // compose it with the one we already have.
299
300             let impl_id = ty::method(tcx, def_id).container_id;
301             let method = ty::method(tcx, source_id);
302             let trait_ref = ty::impl_trait_ref(tcx, impl_id)
303                 .expect("could not find trait_ref for impl with \
304                          default methods");
305
306             // Compute the first substitution
307             let first_subst = make_substs_for_receiver_types(
308                 tcx, impl_id, trait_ref, method);
309
310             // And compose them
311             let new_substs = first_subst.subst(tcx, &substs);
312
313
314             let (param_vtables, self_vtables) =
315                 resolve_default_method_vtables(bcx, impl_id,
316                                                method, &substs, vtables);
317
318             debug!("trans_fn_with_vtables - default method: \
319                     substs = %s, trait_subst = %s, \
320                     first_subst = %s, new_subst = %s, \
321                     vtables = %s, \
322                     self_vtable = %s, param_vtables = %s",
323                    substs.repr(tcx), trait_ref.substs.repr(tcx),
324                    first_subst.repr(tcx), new_substs.repr(tcx),
325                    vtables.repr(tcx),
326                    self_vtables.repr(tcx), param_vtables.repr(tcx));
327
328             (true, source_id,
329              new_substs, Some(self_vtables), Some(param_vtables))
330         }
331     };
332
333     // Check whether this fn has an inlined copy and, if so, redirect
334     // def_id to the local id of the inlined copy.
335     let def_id = {
336         if def_id.crate != ast::LOCAL_CRATE {
337             inline::maybe_instantiate_inline(ccx, def_id)
338         } else {
339             def_id
340         }
341     };
342
343     // We must monomorphise if the fn has type parameters, is a rust
344     // intrinsic, or is a default method.  In particular, if we see an
345     // intrinsic that is inlined from a different crate, we want to reemit the
346     // intrinsic instead of trying to call it in the other crate.
347     let must_monomorphise;
348     if type_params.len() > 0 || is_default {
349         must_monomorphise = true;
350     } else if def_id.crate == ast::LOCAL_CRATE {
351         let map_node = session::expect(
352             ccx.sess,
353             ccx.tcx.items.find(&def_id.node),
354             || fmt!("local item should be in ast map"));
355
356         match *map_node {
357             ast_map::node_foreign_item(_, abis, _, _) => {
358                 must_monomorphise = abis.is_intrinsic()
359             }
360             _ => {
361                 must_monomorphise = false;
362             }
363         }
364     } else {
365         must_monomorphise = false;
366     }
367
368     // Create a monomorphic verison of generic functions
369     if must_monomorphise {
370         // Should be either intra-crate or inlined.
371         assert_eq!(def_id.crate, ast::LOCAL_CRATE);
372
373         let (val, must_cast) =
374             monomorphize::monomorphic_fn(ccx, def_id, &substs,
375                                          vtables, self_vtables,
376                                          Some(ref_id));
377         let mut val = val;
378         if must_cast && ref_id != 0 {
379             // Monotype of the REFERENCE to the function (type params
380             // are subst'd)
381             let ref_ty = common::node_id_type(bcx, ref_id);
382
383             val = PointerCast(
384                 bcx, val, type_of::type_of_fn_from_ty(ccx, ref_ty).ptr_to());
385         }
386         return FnData {llfn: val};
387     }
388
389     // Find the actual function pointer.
390     let val = {
391         if def_id.crate == ast::LOCAL_CRATE {
392             // Internal reference.
393             get_item_val(ccx, def_id.node)
394         } else {
395             // External reference.
396             trans_external_path(ccx, def_id, fn_tpt.ty)
397         }
398     };
399
400     return FnData {llfn: val};
401 }
402
403 // ______________________________________________________________________
404 // Translating calls
405
406 pub fn trans_call(in_cx: @mut Block,
407                   call_ex: @ast::expr,
408                   f: @ast::expr,
409                   args: CallArgs,
410                   id: ast::NodeId,
411                   dest: expr::Dest)
412                   -> @mut Block {
413     let _icx = push_ctxt("trans_call");
414     trans_call_inner(in_cx,
415                      call_ex.info(),
416                      expr_ty(in_cx, f),
417                      node_id_type(in_cx, id),
418                      |cx| trans(cx, f),
419                      args,
420                      Some(dest),
421                      DontAutorefArg).bcx
422 }
423
424 pub fn trans_method_call(in_cx: @mut Block,
425                          call_ex: @ast::expr,
426                          callee_id: ast::NodeId,
427                          rcvr: @ast::expr,
428                          args: CallArgs,
429                          dest: expr::Dest)
430                          -> @mut Block {
431     let _icx = push_ctxt("trans_method_call");
432     debug!("trans_method_call(call_ex=%s, rcvr=%s)",
433            call_ex.repr(in_cx.tcx()),
434            rcvr.repr(in_cx.tcx()));
435     trans_call_inner(
436         in_cx,
437         call_ex.info(),
438         node_id_type(in_cx, callee_id),
439         expr_ty(in_cx, call_ex),
440         |cx| {
441             match cx.ccx().maps.method_map.find_copy(&call_ex.id) {
442                 Some(origin) => {
443                     debug!("origin for %s: %s",
444                            call_ex.repr(in_cx.tcx()),
445                            origin.repr(in_cx.tcx()));
446
447                     meth::trans_method_callee(cx,
448                                               callee_id,
449                                               rcvr,
450                                               origin)
451                 }
452                 None => {
453                     cx.tcx().sess.span_bug(call_ex.span, "method call expr wasn't in method map")
454                 }
455             }
456         },
457         args,
458         Some(dest),
459         DontAutorefArg).bcx
460 }
461
462 pub fn trans_lang_call(bcx: @mut Block,
463                        did: ast::def_id,
464                        args: &[ValueRef],
465                        dest: Option<expr::Dest>)
466     -> Result {
467     let fty = if did.crate == ast::LOCAL_CRATE {
468         ty::node_id_to_type(bcx.ccx().tcx, did.node)
469     } else {
470         csearch::get_type(bcx.ccx().tcx, did).ty
471     };
472     let rty = ty::ty_fn_ret(fty);
473     callee::trans_call_inner(bcx,
474                              None,
475                              fty,
476                              rty,
477                              |bcx| {
478                                 trans_fn_ref_with_vtables_to_callee(bcx,
479                                                                     did,
480                                                                     0,
481                                                                     [],
482                                                                     None)
483                              },
484                              ArgVals(args),
485                              dest,
486                              DontAutorefArg)
487 }
488
489 pub fn trans_lang_call_with_type_params(bcx: @mut Block,
490                                         did: ast::def_id,
491                                         args: &[ValueRef],
492                                         type_params: &[ty::t],
493                                         dest: expr::Dest)
494     -> @mut Block {
495     let fty;
496     if did.crate == ast::LOCAL_CRATE {
497         fty = ty::node_id_to_type(bcx.tcx(), did.node);
498     } else {
499         fty = csearch::get_type(bcx.tcx(), did).ty;
500     }
501
502     let rty = ty::ty_fn_ret(fty);
503     return callee::trans_call_inner(
504         bcx, None, fty, rty,
505         |bcx| {
506             let callee =
507                 trans_fn_ref_with_vtables_to_callee(bcx, did, 0,
508                                                     type_params,
509                                                     None);
510
511             let new_llval;
512             match callee.data {
513                 Fn(fn_data) => {
514                     let substituted = ty::subst_tps(callee.bcx.tcx(),
515                                                     type_params,
516                                                     None,
517                                                     fty);
518                     let llfnty = type_of::type_of(callee.bcx.ccx(),
519                                                       substituted);
520                     new_llval = PointerCast(callee.bcx, fn_data.llfn, llfnty);
521                 }
522                 _ => fail!()
523             }
524             Callee { bcx: callee.bcx, data: Fn(FnData { llfn: new_llval }) }
525         },
526         ArgVals(args), Some(dest), DontAutorefArg).bcx;
527 }
528
529
530 struct CalleeTranslationVisitor;
531
532 impl Visitor<@mut bool> for CalleeTranslationVisitor {
533
534     fn visit_item(&mut self, _:@ast::item, _:@mut bool) { }
535
536     fn visit_expr(&mut self, e:@ast::expr, cx:@mut bool) {
537
538             if !*cx {
539                 match e.node {
540                   ast::expr_ret(_) => *cx = true,
541                   _ => visit::walk_expr(self, e, cx),
542                 }
543             }
544     }
545
546 }
547
548 pub fn body_contains_ret(body: &ast::Block) -> bool {
549     let cx = @mut false;
550     let mut v = CalleeTranslationVisitor;
551     visit::walk_block(&mut v, body, cx);
552     *cx
553 }
554
555 // See [Note-arg-mode]
556 pub fn trans_call_inner(in_cx: @mut Block,
557                         call_info: Option<NodeInfo>,
558                         fn_expr_ty: ty::t,
559                         ret_ty: ty::t,
560                         get_callee: &fn(@mut Block) -> Callee,
561                         args: CallArgs,
562                         dest: Option<expr::Dest>,
563                         autoref_arg: AutorefArg)
564                         -> Result {
565     do base::with_scope_result(in_cx, call_info, "call") |cx| {
566         let callee = get_callee(cx);
567         let mut bcx = callee.bcx;
568         let ccx = cx.ccx();
569
570         let (llfn, llenv) = unsafe {
571             match callee.data {
572                 Fn(d) => {
573                     (d.llfn, llvm::LLVMGetUndef(Type::opaque_box(ccx).ptr_to().to_ref()))
574                 }
575                 Method(d) => {
576                     // Weird but true: we pass self in the *environment* slot!
577                     (d.llfn, d.llself)
578                 }
579                 Closure(d) => {
580                     // Closures are represented as (llfn, llclosure) pair:
581                     // load the requisite values out.
582                     let pair = d.to_ref_llval(bcx);
583                     let llfn = GEPi(bcx, pair, [0u, abi::fn_field_code]);
584                     let llfn = Load(bcx, llfn);
585                     let llenv = GEPi(bcx, pair, [0u, abi::fn_field_box]);
586                     let llenv = Load(bcx, llenv);
587                     (llfn, llenv)
588                 }
589             }
590         };
591
592         let llretslot = trans_ret_slot(bcx, fn_expr_ty, dest);
593
594         let mut llargs = ~[];
595
596         if !ty::type_is_immediate(bcx.tcx(), ret_ty) {
597             llargs.push(llretslot);
598         }
599
600         llargs.push(llenv);
601         bcx = trans_args(bcx, args, fn_expr_ty, autoref_arg, &mut llargs);
602
603         // Now that the arguments have finished evaluating, we need to revoke
604         // the cleanup for the self argument
605         match callee.data {
606             Method(d) => {
607                 for &v in d.temp_cleanup.iter() {
608                     revoke_clean(bcx, v);
609                 }
610             }
611             _ => {}
612         }
613
614         // Uncomment this to debug calls.
615         /*
616         printfln!("calling: %s", bcx.val_to_str(llfn));
617         for llarg in llargs.iter() {
618             printfln!("arg: %s", bcx.val_to_str(*llarg));
619         }
620         io::println("---");
621         */
622
623         // If the block is terminated, then one or more of the args
624         // has type _|_. Since that means it diverges, the code for
625         // the call itself is unreachable.
626         let (llresult, new_bcx) = base::invoke(bcx, llfn, llargs);
627         bcx = new_bcx;
628
629         match dest {
630             None => { assert!(ty::type_is_immediate(bcx.tcx(), ret_ty)) }
631             Some(expr::Ignore) => {
632                 // drop the value if it is not being saved.
633                 if ty::type_needs_drop(bcx.tcx(), ret_ty) {
634                     if ty::type_is_immediate(bcx.tcx(), ret_ty) {
635                         let llscratchptr = alloc_ty(bcx, ret_ty, "__ret");
636                         Store(bcx, llresult, llscratchptr);
637                         bcx = glue::drop_ty(bcx, llscratchptr, ret_ty);
638                     } else {
639                         bcx = glue::drop_ty(bcx, llretslot, ret_ty);
640                     }
641                 }
642             }
643             Some(expr::SaveIn(lldest)) => {
644                 // If this is an immediate, store into the result location.
645                 // (If this was not an immediate, the result will already be
646                 // directly written into the output slot.)
647                 if ty::type_is_immediate(bcx.tcx(), ret_ty) {
648                     Store(bcx, llresult, lldest);
649                 }
650             }
651         }
652
653         if ty::type_is_bot(ret_ty) {
654             Unreachable(bcx);
655         }
656         rslt(bcx, llresult)
657     }
658 }
659
660
661 pub enum CallArgs<'self> {
662     ArgExprs(&'self [@ast::expr]),
663     ArgVals(&'self [ValueRef])
664 }
665
666 pub fn trans_ret_slot(bcx: @mut Block, fn_ty: ty::t, dest: Option<expr::Dest>)
667                       -> ValueRef {
668     let retty = ty::ty_fn_ret(fn_ty);
669
670     match dest {
671         Some(expr::SaveIn(dst)) => dst,
672         _ => {
673             if ty::type_is_immediate(bcx.tcx(), retty) {
674                 unsafe {
675                     llvm::LLVMGetUndef(Type::nil().ptr_to().to_ref())
676                 }
677             } else {
678                 alloc_ty(bcx, retty, "__trans_ret_slot")
679             }
680         }
681     }
682 }
683
684 pub fn trans_args(cx: @mut Block,
685                   args: CallArgs,
686                   fn_ty: ty::t,
687                   autoref_arg: AutorefArg,
688                   llargs: &mut ~[ValueRef]) -> @mut Block
689 {
690     let _icx = push_ctxt("trans_args");
691     let mut temp_cleanups = ~[];
692     let arg_tys = ty::ty_fn_args(fn_ty);
693
694     let mut bcx = cx;
695
696     // First we figure out the caller's view of the types of the arguments.
697     // This will be needed if this is a generic call, because the callee has
698     // to cast her view of the arguments to the caller's view.
699     match args {
700       ArgExprs(arg_exprs) => {
701         for (i, arg_expr) in arg_exprs.iter().enumerate() {
702             let arg_val = unpack_result!(bcx, {
703                 trans_arg_expr(bcx,
704                                arg_tys[i],
705                                ty::ByCopy,
706                                *arg_expr,
707                                &mut temp_cleanups,
708                                autoref_arg)
709             });
710             llargs.push(arg_val);
711         }
712       }
713       ArgVals(vs) => {
714         llargs.push_all(vs);
715       }
716     }
717
718     // now that all arguments have been successfully built, we can revoke any
719     // temporary cleanups, as they are only needed if argument construction
720     // should fail (for example, cleanup of copy mode args).
721     for c in temp_cleanups.iter() {
722         revoke_clean(bcx, *c)
723     }
724
725     bcx
726 }
727
728 pub enum AutorefArg {
729     DontAutorefArg,
730     DoAutorefArg
731 }
732
733 // temp_cleanups: cleanups that should run only if failure occurs before the
734 // call takes place:
735 pub fn trans_arg_expr(bcx: @mut Block,
736                       formal_arg_ty: ty::t,
737                       self_mode: ty::SelfMode,
738                       arg_expr: @ast::expr,
739                       temp_cleanups: &mut ~[ValueRef],
740                       autoref_arg: AutorefArg) -> Result {
741     let _icx = push_ctxt("trans_arg_expr");
742     let ccx = bcx.ccx();
743
744     debug!("trans_arg_expr(formal_arg_ty=(%s), self_mode=%?, arg_expr=%s)",
745            formal_arg_ty.repr(bcx.tcx()),
746            self_mode,
747            arg_expr.repr(bcx.tcx()));
748
749     // translate the arg expr to a datum
750     let arg_datumblock = expr::trans_to_datum(bcx, arg_expr);
751     let arg_datum = arg_datumblock.datum;
752     let bcx = arg_datumblock.bcx;
753
754     debug!("   arg datum: %s", arg_datum.to_str(bcx.ccx()));
755
756     let mut val;
757     if ty::type_is_bot(arg_datum.ty) {
758         // For values of type _|_, we generate an
759         // "undef" value, as such a value should never
760         // be inspected. It's important for the value
761         // to have type lldestty (the callee's expected type).
762         let llformal_arg_ty = type_of::type_of(ccx, formal_arg_ty);
763         unsafe {
764             val = llvm::LLVMGetUndef(llformal_arg_ty.to_ref());
765         }
766     } else {
767         // FIXME(#3548) use the adjustments table
768         match autoref_arg {
769             DoAutorefArg => {
770                 val = arg_datum.to_ref_llval(bcx);
771             }
772             DontAutorefArg => {
773                 let need_scratch = ty::type_needs_drop(bcx.tcx(), arg_datum.ty) ||
774                     (bcx.expr_is_lval(arg_expr) &&
775                      arg_datum.appropriate_mode(bcx.tcx()).is_by_ref());
776
777                 let arg_datum = if need_scratch {
778                     let scratch = scratch_datum(bcx, arg_datum.ty, "__self", false);
779                     arg_datum.store_to_datum(bcx, INIT, scratch);
780
781                     // Technically, ownership of val passes to the callee.
782                     // However, we must cleanup should we fail before the
783                     // callee is actually invoked.
784                     scratch.add_clean(bcx);
785                     temp_cleanups.push(scratch.val);
786
787                     scratch
788                 } else {
789                     arg_datum
790                 };
791
792                 val = match self_mode {
793                     ty::ByRef => {
794                         debug!("by ref arg with type %s", bcx.ty_to_str(arg_datum.ty));
795                         arg_datum.to_ref_llval(bcx)
796                     }
797                     ty::ByCopy => {
798                         debug!("by copy arg with type %s", bcx.ty_to_str(arg_datum.ty));
799                         arg_datum.to_appropriate_llval(bcx)
800                     }
801                 }
802             }
803         }
804
805         if formal_arg_ty != arg_datum.ty {
806             // this could happen due to e.g. subtyping
807             let llformal_arg_ty = type_of::type_of_explicit_arg(ccx, &formal_arg_ty);
808             debug!("casting actual type (%s) to match formal (%s)",
809                    bcx.val_to_str(val), bcx.llty_str(llformal_arg_ty));
810             val = PointerCast(bcx, val, llformal_arg_ty);
811         }
812     }
813
814     debug!("--- trans_arg_expr passing %s", bcx.val_to_str(val));
815     return rslt(bcx, val);
816 }