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.
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.
14 use lib::llvm::ValueRef;
16 use metadata::csearch;
17 use middle::trans::base::*;
18 use middle::trans::build::*;
19 use middle::trans::callee::*;
20 use middle::trans::callee;
21 use middle::trans::common::*;
22 use middle::trans::datum::*;
23 use middle::trans::expr::{SaveIn, Ignore};
24 use middle::trans::expr;
25 use middle::trans::glue;
26 use middle::trans::monomorphize;
27 use middle::trans::type_of::*;
30 use util::common::indenter;
31 use util::ppaux::Repr;
33 use middle::trans::type_::Type;
35 use std::c_str::ToCStr;
37 use syntax::ast_map::{path, path_mod, path_name, path_pretty_name};
39 use syntax::{ast, ast_map};
40 use syntax::parse::token;
44 The main "translation" pass for methods. Generates code
45 for non-monomorphized methods only. Other methods will
46 be generated once they are invoked with specific type parameters,
47 see `trans::base::lval_static_fn()` or `trans::base::monomorphic_fn()`.
49 pub fn trans_impl(ccx: @mut CrateContext,
52 methods: &[@ast::method],
53 generics: &ast::Generics,
55 let _icx = push_ctxt("impl::trans_impl");
58 debug2!("trans_impl(path={}, name={}, id={:?})",
59 path.repr(tcx), name.repr(tcx), id);
61 // Both here and below with generic methods, be sure to recurse and look for
62 // items that we need to translate.
63 if !generics.ty_params.is_empty() {
64 let mut v = TransItemVisitor{ ccx: ccx };
65 for method in methods.iter() {
66 visit::walk_method_helper(&mut v, *method, ());
70 let sub_path = vec::append_one(path, path_name(name));
71 for method in methods.iter() {
72 if method.generics.ty_params.len() == 0u {
73 let llfn = get_item_val(ccx, method.id);
74 let path = vec::append_one(sub_path.clone(),
75 path_name(method.ident));
83 let mut v = TransItemVisitor{ ccx: ccx };
84 visit::walk_method_helper(&mut v, *method, ());
89 /// Translates a (possibly monomorphized) method body.
92 /// * `path`: the path to the method
93 /// * `method`: the AST node for the method
94 /// * `param_substs`: if this is a generic method, the current values for
95 /// type parameters and so forth, else none
96 /// * `llfn`: the LLVM ValueRef for the method
97 /// * `impl_id`: the node ID of the impl this method is inside
99 /// XXX(pcwalton) Can we take `path` by reference?
100 pub fn trans_method(ccx: @mut CrateContext,
102 method: &ast::method,
103 param_substs: Option<@param_substs>,
105 // figure out how self is being passed
106 let self_arg = match method.explicit_self.node {
111 // determine the (monomorphized) type that `self` maps to for
113 let self_ty = ty::node_id_to_type(ccx.tcx, method.self_id);
114 let self_ty = match param_substs {
116 Some(@param_substs {tys: ref tys, self_ty: ref self_sub, _}) => {
117 ty::subst_tps(ccx.tcx, *tys, *self_sub, self_ty)
120 debug2!("calling trans_fn with self_ty {}",
121 self_ty.repr(ccx.tcx));
122 match method.explicit_self.node {
123 ast::sty_value => impl_self(self_ty, ty::ByRef),
124 _ => impl_self(self_ty, ty::ByCopy),
129 // generate the actual code
141 pub fn trans_self_arg(bcx: @mut Block,
143 temp_cleanups: &mut ~[ValueRef],
144 mentry: typeck::method_map_entry) -> Result {
145 let _icx = push_ctxt("impl::trans_self_arg");
147 // self is passed as an opaque box in the environment slot
148 let self_ty = ty::mk_opaque_box(bcx.tcx());
157 pub fn trans_method_callee(bcx: @mut Block,
158 callee_id: ast::NodeId,
160 mentry: typeck::method_map_entry)
162 let _icx = push_ctxt("impl::trans_method_callee");
164 debug2!("trans_method_callee(callee_id={:?}, this={}, mentry={})",
166 bcx.expr_to_str(this),
167 mentry.repr(bcx.tcx()));
169 match mentry.origin {
170 typeck::method_static(did) => {
171 let callee_fn = callee::trans_fn_ref(bcx, did, callee_id);
172 let mut temp_cleanups = ~[];
173 let Result {bcx, val} = trans_self_arg(bcx, this, &mut temp_cleanups, mentry);
176 data: Method(MethodData {
177 llfn: callee_fn.llfn,
179 temp_cleanup: temp_cleanups.head_opt().map(|v| *v),
180 self_mode: mentry.self_mode,
184 typeck::method_param(typeck::method_param {
190 match bcx.fcx.param_substs {
192 ty::populate_implementations_for_trait_if_necessary(
196 let vtbl = find_vtable(bcx.tcx(), substs,
198 trans_monomorphized_callee(bcx, callee_id, this, mentry,
201 // how to get rid of this?
202 None => fail2!("trans_method_callee: missing param_substs")
206 typeck::method_object(ref mt) => {
207 trans_trait_callee(bcx,
215 pub fn trans_static_method_callee(bcx: @mut Block,
216 method_id: ast::DefId,
217 trait_id: ast::DefId,
218 callee_id: ast::NodeId)
220 let _icx = push_ctxt("impl::trans_static_method_callee");
223 debug2!("trans_static_method_callee(method_id={:?}, trait_id={}, \
226 ty::item_path_str(bcx.tcx(), trait_id),
228 let _indenter = indenter();
230 ty::populate_implementations_for_trait_if_necessary(bcx.tcx(), trait_id);
232 // When we translate a static fn defined in a trait like:
234 // trait<T1...Tn> Trait {
235 // fn foo<M1...Mn>(...) {...}
238 // this winds up being translated as something like:
240 // fn foo<T1...Tn,self: Trait<T1...Tn>,M1...Mn>(...) {...}
242 // So when we see a call to this function foo, we have to figure
243 // out which impl the `Trait<T1...Tn>` bound on the type `self` was
245 let bound_index = ty::lookup_trait_def(bcx.tcx(), trait_id).
246 generics.type_param_defs.len();
248 let mname = if method_id.crate == ast::LOCAL_CRATE {
249 match bcx.tcx().items.get_copy(&method_id.node) {
250 ast_map::node_trait_method(trait_method, _, _) => {
251 ast_util::trait_method_to_ty_method(trait_method).ident
253 _ => fail2!("callee is not a trait method")
256 let path = csearch::get_item_path(bcx.tcx(), method_id);
257 match path[path.len()-1] {
258 path_pretty_name(s, _) | path_name(s) => { s }
259 path_mod(_) => { fail2!("path doesn't have a name?") }
262 debug2!("trans_static_method_callee: method_id={:?}, callee_id={:?}, \
263 name={}", method_id, callee_id, ccx.sess.str_of(mname));
265 let vtbls = resolve_vtables_in_fn_ctxt(
266 bcx.fcx, ccx.maps.vtable_map.get_copy(&callee_id));
268 match vtbls[bound_index][0] {
269 typeck::vtable_static(impl_did, ref rcvr_substs, rcvr_origins) => {
270 assert!(rcvr_substs.iter().all(|t| !ty::type_needs_infer(*t)));
272 let mth_id = method_with_name(bcx.ccx(), impl_did, mname.name);
273 let (callee_substs, callee_origins) =
274 combine_impl_and_methods_tps(
275 bcx, mth_id, callee_id,
276 *rcvr_substs, rcvr_origins);
278 let FnData {llfn: lval} =
279 trans_fn_ref_with_vtables(bcx,
283 Some(callee_origins));
285 let callee_ty = node_id_type(bcx, callee_id);
286 let llty = type_of_fn_from_ty(ccx, callee_ty).ptr_to();
287 FnData {llfn: PointerCast(bcx, lval, llty)}
290 fail2!("vtable_param left in monomorphized \
291 function's vtable substs");
296 pub fn method_with_name(ccx: &mut CrateContext,
298 name: ast::Name) -> ast::DefId {
299 let meth_id_opt = ccx.impl_method_cache.find_copy(&(impl_id, name));
305 let imp = ccx.tcx.impls.find(&impl_id)
306 .expect("could not find impl while translating");
307 let meth = imp.methods.iter().find(|m| m.ident.name == name)
308 .expect("could not find method while translating");
310 ccx.impl_method_cache.insert((impl_id, name), meth.def_id);
314 pub fn trans_monomorphized_callee(bcx: @mut Block,
315 callee_id: ast::NodeId,
317 mentry: typeck::method_map_entry,
318 trait_id: ast::DefId,
320 vtbl: typeck::vtable_origin)
322 let _icx = push_ctxt("impl::trans_monomorphized_callee");
324 typeck::vtable_static(impl_did, ref rcvr_substs, rcvr_origins) => {
326 let mname = ty::trait_method(ccx.tcx, trait_id, n_method).ident;
327 let mth_id = method_with_name(bcx.ccx(), impl_did, mname.name);
329 // obtain the `self` value:
330 let mut temp_cleanups = ~[];
331 let Result {bcx, val: llself_val} =
332 trans_self_arg(bcx, base, &mut temp_cleanups, mentry);
334 // create a concatenated set of substitutions which includes
335 // those from the impl and those from the method:
336 let (callee_substs, callee_origins) =
337 combine_impl_and_methods_tps(
338 bcx, mth_id, callee_id,
339 *rcvr_substs, rcvr_origins);
341 // translate the function
342 let callee = trans_fn_ref_with_vtables(bcx,
346 Some(callee_origins));
348 // create a llvalue that represents the fn ptr
349 let fn_ty = node_id_type(bcx, callee_id);
350 let llfn_ty = type_of_fn_from_ty(ccx, fn_ty).ptr_to();
351 let llfn_val = PointerCast(bcx, callee.llfn, llfn_ty);
353 // combine the self environment with the rest
356 data: Method(MethodData {
359 temp_cleanup: temp_cleanups.head_opt().map(|v| *v),
360 self_mode: mentry.self_mode,
364 typeck::vtable_param(*) => {
365 fail2!("vtable_param left in monomorphized function's vtable substs");
371 pub fn combine_impl_and_methods_tps(bcx: @mut Block,
373 callee_id: ast::NodeId,
374 rcvr_substs: &[ty::t],
375 rcvr_origins: typeck::vtable_res)
376 -> (~[ty::t], typeck::vtable_res) {
379 * Creates a concatenated set of substitutions which includes
380 * those from the impl and those from the method. This are
381 * some subtle complications here. Statically, we have a list
382 * of type parameters like `[T0, T1, T2, M1, M2, M3]` where
383 * `Tn` are type parameters that appear on the receiver. For
384 * example, if the receiver is a method parameter `A` with a
385 * bound like `trait<B,C,D>` then `Tn` would be `[B,C,D]`.
387 * The weird part is that the type `A` might now be bound to
388 * any other type, such as `foo<X>`. In that case, the vector
389 * we want is: `[X, M1, M2, M3]`. Therefore, what we do now is
390 * to slice off the method type parameters and append them to
391 * the type parameters from the type that the receiver is
395 let method = ty::method(ccx.tcx, mth_did);
396 let n_m_tps = method.generics.type_param_defs.len();
397 let node_substs = node_id_type_params(bcx, callee_id);
398 debug2!("rcvr_substs={:?}", rcvr_substs.repr(ccx.tcx));
400 = vec::append(rcvr_substs.to_owned(),
401 node_substs.tailn(node_substs.len() - n_m_tps));
402 debug2!("n_m_tps={:?}", n_m_tps);
403 debug2!("node_substs={:?}", node_substs.repr(ccx.tcx));
404 debug2!("ty_substs={:?}", ty_substs.repr(ccx.tcx));
407 // Now, do the same work for the vtables. The vtables might not
408 // exist, in which case we need to make them.
409 let r_m_origins = match node_vtables(bcx, callee_id) {
411 None => @vec::from_elem(node_substs.len(), @~[])
414 = @vec::append(rcvr_origins.to_owned(),
415 r_m_origins.tailn(r_m_origins.len() - n_m_tps));
417 return (ty_substs, vtables);
420 pub fn trans_trait_callee(bcx: @mut Block,
421 callee_id: ast::NodeId,
423 self_expr: &ast::Expr)
426 * Create a method callee where the method is coming from a trait
427 * object (e.g., @Trait type). In this case, we must pull the fn
428 * pointer out of the vtable that is packaged up with the object.
429 * Objects are represented as a pair, so we first evaluate the self
430 * expression and then extract the self data and vtable out of the
434 let _icx = push_ctxt("impl::trans_trait_callee");
437 // make a local copy for trait if needed
438 let self_ty = expr_ty_adjusted(bcx, self_expr);
439 let self_scratch = match ty::get(self_ty).sty {
440 ty::ty_trait(_, _, ty::RegionTraitStore(*), _, _) => {
441 unpack_datum!(bcx, expr::trans_to_datum(bcx, self_expr))
444 let d = scratch_datum(bcx, self_ty, "__trait_callee", false);
445 bcx = expr::trans_into(bcx, self_expr, expr::SaveIn(d.val));
446 // Arrange a temporary cleanup for the object in case something
447 // should go wrong before the method is actually *invoked*.
454 let callee_ty = node_id_type(bcx, callee_id);
455 trans_trait_callee_from_llval(bcx,
459 Some(self_scratch.val))
462 pub fn trans_trait_callee_from_llval(bcx: @mut Block,
466 temp_cleanup: Option<ValueRef>)
469 * Same as `trans_trait_callee()` above, except that it is given
470 * a by-ref pointer to the object pair.
473 let _icx = push_ctxt("impl::trans_trait_callee");
476 // Load the data pointer from the object.
477 debug2!("(translating trait callee) loading second index from pair");
478 let llboxptr = GEPi(bcx, llpair, [0u, abi::trt_field_box]);
479 let llbox = Load(bcx, llboxptr);
480 let llself = PointerCast(bcx, llbox, Type::opaque_box(ccx).ptr_to());
482 // Load the function from the vtable and cast it to the expected type.
483 debug2!("(translating trait callee) loading method");
484 let llcallee_ty = type_of_fn_from_ty(ccx, callee_ty);
485 let llvtable = Load(bcx,
488 [0u, abi::trt_field_vtable]),
489 Type::vtable().ptr_to().ptr_to()));
490 let mptr = Load(bcx, GEPi(bcx, llvtable, [0u, n_method + 1]));
491 let mptr = PointerCast(bcx, mptr, llcallee_ty.ptr_to());
495 data: Method(MethodData {
498 temp_cleanup: temp_cleanup,
500 // We know that the func declaration is &self, ~self,
501 // or @self, and such functions are always by-copy
502 // (right now, at least).
503 self_mode: ty::ByCopy,
508 pub fn vtable_id(ccx: @mut CrateContext,
509 origin: &typeck::vtable_origin)
512 &typeck::vtable_static(impl_id, ref substs, sub_vtables) => {
513 let psubsts = param_substs {
514 tys: (*substs).clone(),
515 vtables: Some(sub_vtables),
520 monomorphize::make_mono_id(
526 // can't this be checked at the callee?
527 _ => fail2!("vtable_id")
531 /// Creates a returns a dynamic vtable for the given type and vtable origin.
532 /// This is used only for objects.
533 pub fn get_vtable(bcx: @mut Block,
535 origins: typeck::vtable_param_res)
538 let _icx = push_ctxt("impl::get_vtable");
541 let hash_id = (self_ty, vtable_id(ccx, &origins[0]));
542 match ccx.vtables.find(&hash_id) {
543 Some(&val) => { return val }
547 // Not in the cache. Actually build it.
548 let methods = do origins.flat_map |origin| {
550 typeck::vtable_static(id, ref substs, sub_vtables) => {
551 emit_vtable_methods(bcx, id, *substs, sub_vtables)
553 _ => ccx.sess.bug("get_vtable: expected a static origin"),
557 // Generate a type descriptor for the vtable.
558 let tydesc = get_tydesc(ccx, self_ty);
559 glue::lazily_emit_all_tydesc_glue(ccx, tydesc);
561 let vtable = make_vtable(ccx, tydesc, methods);
562 ccx.vtables.insert(hash_id, vtable);
566 /// Helper function to declare and initialize the vtable.
567 pub fn make_vtable(ccx: &mut CrateContext,
568 tydesc: &tydesc_info,
572 let _icx = push_ctxt("impl::make_vtable");
574 let mut components = ~[ tydesc.tydesc ];
575 for &ptr in ptrs.iter() {
579 let tbl = C_struct(components);
580 let sym = token::gensym("vtable");
581 let vt_gvar = do format!("vtable{}", sym).with_c_str |buf| {
582 llvm::LLVMAddGlobal(ccx.llmod, val_ty(tbl).to_ref(), buf)
584 llvm::LLVMSetInitializer(vt_gvar, tbl);
585 llvm::LLVMSetGlobalConstant(vt_gvar, lib::llvm::True);
586 lib::llvm::SetLinkage(vt_gvar, lib::llvm::InternalLinkage);
591 fn emit_vtable_methods(bcx: @mut Block,
594 vtables: typeck::vtable_res)
599 let trt_id = match ty::impl_trait_ref(tcx, impl_id) {
600 Some(t_id) => t_id.def_id,
601 None => ccx.sess.bug("make_impl_vtable: don't know how to \
602 make a vtable for a type impl!")
605 ty::populate_implementations_for_trait_if_necessary(bcx.tcx(), trt_id);
607 let trait_method_def_ids = ty::trait_method_def_ids(tcx, trt_id);
608 do trait_method_def_ids.map |method_def_id| {
609 let ident = ty::method(tcx, *method_def_id).ident;
610 // The substitutions we have are on the impl, so we grab
611 // the method type from the impl to substitute into.
612 let m_id = method_with_name(ccx, impl_id, ident.name);
613 let m = ty::method(tcx, m_id);
614 debug2!("(making impl vtable) emitting method {} at subst {}",
617 let fty = ty::subst_tps(tcx,
620 ty::mk_bare_fn(tcx, m.fty.clone()));
621 if m.generics.has_type_params() || ty::type_has_self(fty) {
622 debug2!("(making impl vtable) method has self or type params: {}",
623 tcx.sess.str_of(ident));
624 C_null(Type::nil().ptr_to())
626 trans_fn_ref_with_vtables(bcx, m_id, 0,
627 substs, Some(vtables)).llfn
632 pub fn trans_trait_cast(bcx: @mut Block,
636 _store: ty::TraitStore)
639 let _icx = push_ctxt("impl::trans_cast");
641 let lldest = match dest {
643 return expr::trans_into(bcx, val, Ignore);
649 let v_ty = expr_ty(bcx, val);
651 let mut llboxdest = GEPi(bcx, lldest, [0u, abi::trt_field_box]);
652 // Just store the pointer into the pair. (Region/borrowed
653 // and boxed trait objects are represented as pairs, and
654 // have no type descriptor field.)
655 llboxdest = PointerCast(bcx,
657 type_of(bcx.ccx(), v_ty).ptr_to());
658 bcx = expr::trans_into(bcx, val, SaveIn(llboxdest));
660 // Store the vtable into the pair or triple.
661 // This is structured a bit funny because of dynamic borrow failures.
663 let res = ccx.maps.vtable_map.get(&id);
664 let res = resolve_vtables_in_fn_ctxt(bcx.fcx, *res);
667 let vtable = get_vtable(bcx, v_ty, origins);
668 Store(bcx, vtable, PointerCast(bcx,
669 GEPi(bcx, lldest, [0u, abi::trt_field_vtable]),
670 val_ty(vtable).ptr_to()));