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.
13 use arena::TypedArena;
15 use llvm::{ValueRef, get_params};
16 use middle::def_id::DefId;
18 use middle::subst::{Subst, Substs};
23 use trans::callee::{Callee, Virtual, ArgVals,
24 trans_fn_pointer_shim, trans_fn_ref_with_substs};
29 use trans::debuginfo::DebugLoc;
34 use trans::type_::Type;
35 use trans::type_of::*;
36 use middle::ty::{self, Ty, TyCtxt};
38 use syntax::ast::{self, Name};
40 use syntax::codemap::DUMMY_SP;
44 // drop_glue pointer, size, align.
45 const VTABLE_OFFSET: usize = 3;
47 /// The main "translation" pass for methods. Generates code
48 /// for non-monomorphized methods only. Other methods will
49 /// be generated once they are invoked with specific type parameters,
50 /// see `trans::base::lval_static_fn()` or `trans::base::monomorphic_fn()`.
51 pub fn trans_impl(ccx: &CrateContext,
53 impl_items: &[hir::ImplItem],
54 generics: &hir::Generics,
56 let _icx = push_ctxt("meth::trans_impl");
59 debug!("trans_impl(name={}, id={})", name, 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() {
67 for impl_item in impl_items {
68 match impl_item.node {
69 hir::ImplItemKind::Method(ref sig, ref body) => {
70 if sig.generics.ty_params.is_empty() {
71 let trans_everywhere = attr::requests_inline(&impl_item.attrs);
72 for (ref ccx, is_origin) in ccx.maybe_iter(trans_everywhere) {
73 let llfn = get_item_val(ccx, impl_item.id);
74 let empty_substs = tcx.mk_substs(Substs::trans_empty());
85 if is_origin { OriginalTranslation } else { InlinedCopy });
94 /// Compute the appropriate callee, give na method's ID, trait ID,
95 /// substitutions and a Vtable for that trait.
96 pub fn callee_for_trait_impl<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
98 substs: &'tcx subst::Substs<'tcx>,
101 vtable: traits::Vtable<'tcx, ()>)
103 let _icx = push_ctxt("meth::callee_for_trait_impl");
105 traits::VtableImpl(vtable_impl) => {
106 let impl_did = vtable_impl.impl_def_id;
107 let mname = ccx.tcx().item_name(method_id);
108 // create a concatenated set of substitutions which includes
109 // those from the impl and those from the method:
110 let impl_substs = vtable_impl.substs.with_method_from(&substs);
111 let substs = ccx.tcx().mk_substs(impl_substs);
112 let mth = get_impl_method(ccx.tcx(), impl_did, impl_substs, mname);
114 // Translate the function, bypassing Callee::def.
115 // That is because default methods have the same ID as the
116 // trait method used to look up the impl method that ended
117 // up here, so calling Callee::def would infinitely recurse.
118 Callee::ptr(trans_fn_ref_with_substs(ccx, mth.method.def_id,
119 Some(method_ty), mth.substs))
121 traits::VtableClosure(vtable_closure) => {
122 // The substitutions should have no type parameters remaining
123 // after passing through fulfill_obligation
124 let trait_closure_kind = ccx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
125 let llfn = closure::trans_closure_method(ccx,
126 vtable_closure.closure_def_id,
127 vtable_closure.substs,
129 let fn_ptr_ty = match method_ty.sty {
130 ty::TyFnDef(_, _, fty) => ccx.tcx().mk_ty(ty::TyFnPtr(fty)),
131 _ => unreachable!("expected fn item type, found {}",
134 Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty))
136 traits::VtableFnPointer(fn_ty) => {
137 let trait_closure_kind = ccx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
138 let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, fn_ty);
139 let fn_ptr_ty = match method_ty.sty {
140 ty::TyFnDef(_, _, fty) => ccx.tcx().mk_ty(ty::TyFnPtr(fty)),
141 _ => unreachable!("expected fn item type, found {}",
144 Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty))
146 traits::VtableObject(ref data) => {
148 data: Virtual(traits::get_vtable_index_of_object_method(
149 ccx.tcx(), data, method_id)),
153 traits::VtableBuiltin(..) |
154 traits::VtableDefaultImpl(..) |
155 traits::VtableParam(..) => {
157 &format!("resolved vtable bad vtable {:?} in trans",
163 /// Extracts a method from a trait object's vtable, at the
164 /// specified index, and casts it to the given type.
165 pub fn get_virtual_method<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
169 -> Datum<'tcx, Rvalue> {
170 let _icx = push_ctxt("meth::get_virtual_method");
173 // Load the data pointer from the object.
174 debug!("get_virtual_method(callee_ty={}, vtable_index={}, llvtable={})",
177 bcx.val_to_string(llvtable));
179 let mptr = Load(bcx, GEPi(bcx, llvtable, &[vtable_index + VTABLE_OFFSET]));
181 // Replace the self type (&Self or Box<Self>) with an opaque pointer.
182 if let ty::TyFnDef(_, _, fty) = method_ty.sty {
183 let opaque_ty = opaque_method_ty(ccx.tcx(), fty);
184 immediate_rvalue(PointerCast(bcx, mptr, type_of(ccx, opaque_ty)), opaque_ty)
186 immediate_rvalue(mptr, method_ty)
190 /// Generate a shim function that allows an object type like `SomeTrait` to
191 /// implement the type `SomeTrait`. Imagine a trait definition:
193 /// trait SomeTrait { fn get(&self) -> i32; ... }
195 /// And a generic bit of code:
197 /// fn foo<T:SomeTrait>(t: &T) {
198 /// let x = SomeTrait::get;
202 /// What is the value of `x` when `foo` is invoked with `T=SomeTrait`?
203 /// The answer is that it is a shim function generated by this routine:
205 /// fn shim(t: &SomeTrait) -> i32 {
206 /// // ... call t.get() virtually ...
209 /// In fact, all virtual calls can be thought of as normal trait calls
210 /// that go through this shim function.
211 pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
214 -> Datum<'tcx, Rvalue> {
215 let _icx = push_ctxt("trans_object_shim");
218 debug!("trans_object_shim(vtable_index={}, method_ty={:?})",
222 let ret_ty = tcx.erase_late_bound_regions(&method_ty.fn_ret());
223 let ret_ty = infer::normalize_associated_type(tcx, &ret_ty);
225 let shim_fn_ty = match method_ty.sty {
226 ty::TyFnDef(_, _, fty) => tcx.mk_ty(ty::TyFnPtr(fty)),
227 _ => unreachable!("expected fn item type, found {}", method_ty)
231 let function_name = link::mangle_internal_name_by_type_and_seq(ccx, shim_fn_ty, "object_shim");
232 let llfn = declare::define_internal_rust_fn(ccx, &function_name, shim_fn_ty);
234 let empty_substs = tcx.mk_substs(Substs::trans_empty());
235 let (block_arena, fcx): (TypedArena<_>, FunctionContext);
236 block_arena = TypedArena::new();
237 fcx = new_fn_ctxt(ccx,
245 let mut bcx = init_function(&fcx, false, ret_ty);
247 let llargs = get_params(fcx.llfn);
249 let self_idx = fcx.arg_offset();
250 let llself = llargs[self_idx];
251 let llvtable = llargs[self_idx + 1];
253 debug!("trans_object_shim: llself={}, llvtable={}",
254 bcx.val_to_string(llself), bcx.val_to_string(llvtable));
256 assert!(!fcx.needs_ret_allocas);
259 fcx.llretslotptr.get().map(
260 |_| expr::SaveIn(fcx.get_ret_slot(bcx, ret_ty, "ret_slot")));
262 debug!("trans_object_shim: method_offset_in_vtable={}",
265 let callee = Callee {
266 data: Virtual(vtable_index),
269 bcx = callee.call(bcx, DebugLoc::None, ArgVals(&llargs[self_idx..]), dest).bcx;
271 finish_fn(&fcx, bcx, ret_ty, DebugLoc::None);
273 immediate_rvalue(llfn, shim_fn_ty)
276 /// Creates a returns a dynamic vtable for the given type and vtable origin.
277 /// This is used only for objects.
279 /// The `trait_ref` encodes the erased self type. Hence if we are
280 /// making an object `Foo<Trait>` from a value of type `Foo<T>`, then
281 /// `trait_ref` would map `T:Trait`.
282 pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
283 trait_ref: ty::PolyTraitRef<'tcx>)
287 let _icx = push_ctxt("meth::get_vtable");
289 debug!("get_vtable(trait_ref={:?})", trait_ref);
292 match ccx.vtables().borrow().get(&trait_ref) {
293 Some(&val) => { return val }
297 // Not in the cache. Build it.
298 let methods = traits::supertraits(tcx, trait_ref.clone()).flat_map(|trait_ref| {
299 let vtable = fulfill_obligation(ccx, DUMMY_SP, trait_ref.clone());
301 // Should default trait error here?
302 traits::VtableDefaultImpl(_) |
303 traits::VtableBuiltin(_) => {
304 Vec::new().into_iter()
307 traits::VtableImplData {
311 let nullptr = C_null(Type::nil(ccx).ptr_to());
312 get_vtable_methods(ccx, id, substs)
317 trans_fn_ref_with_substs(ccx,
328 traits::VtableClosure(
329 traits::VtableClosureData {
333 let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_ref.def_id()).unwrap();
334 let llfn = closure::trans_closure_method(ccx,
338 vec![llfn].into_iter()
340 traits::VtableFnPointer(bare_fn_ty) => {
341 let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_ref.def_id()).unwrap();
342 vec![trans_fn_pointer_shim(ccx, trait_closure_kind, bare_fn_ty)].into_iter()
344 traits::VtableObject(ref data) => {
345 // this would imply that the Self type being erased is
346 // an object type; this cannot happen because we
347 // cannot cast an unsized type into a trait object
349 &format!("cannot get vtable for an object type: {:?}",
352 traits::VtableParam(..) => {
354 &format!("resolved vtable for {:?} to bad vtable {:?} in trans",
361 let size_ty = sizing_type_of(ccx, trait_ref.self_ty());
362 let size = machine::llsize_of_alloc(ccx, size_ty);
363 let align = align_of(ccx, trait_ref.self_ty());
365 let components: Vec<_> = vec![
366 // Generate a destructor for the vtable.
367 glue::get_drop_glue(ccx, trait_ref.self_ty()),
370 ].into_iter().chain(methods).collect();
372 let vtable_const = C_struct(ccx, &components, false);
373 let align = machine::llalign_of_pref(ccx, val_ty(vtable_const));
374 let vtable = consts::addr_of(ccx, vtable_const, align, "vtable");
376 ccx.vtables().borrow_mut().insert(trait_ref, vtable);
380 pub fn get_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
382 substs: &'tcx subst::Substs<'tcx>)
383 -> Vec<Option<ty::util::ImplMethod<'tcx>>>
387 debug!("get_vtable_methods(impl_id={:?}, substs={:?}", impl_id, substs);
389 let trt_id = match tcx.impl_trait_ref(impl_id) {
390 Some(t_id) => t_id.def_id,
391 None => ccx.sess().bug("make_impl_vtable: don't know how to \
392 make a vtable for a type impl!")
395 tcx.populate_implementations_for_trait_if_necessary(trt_id);
397 let trait_item_def_ids = tcx.trait_item_def_ids(trt_id);
401 // Filter out non-method items.
402 .filter_map(|item_def_id| {
404 ty::MethodTraitItemId(def_id) => Some(def_id),
409 // Now produce pointers for each remaining method. If the
410 // method could never be called from this object, just supply
412 .map(|trait_method_def_id| {
413 debug!("get_vtable_methods: trait_method_def_id={:?}",
414 trait_method_def_id);
416 let trait_method_type = match tcx.impl_or_trait_item(trait_method_def_id) {
417 ty::MethodTraitItem(m) => m,
418 _ => ccx.sess().bug("should be a method, not other assoc item"),
420 let name = trait_method_type.name;
422 // Some methods cannot be called on an object; skip those.
423 if !traits::is_vtable_safe_method(tcx, trt_id, &trait_method_type) {
424 debug!("get_vtable_methods: not vtable safe");
428 debug!("get_vtable_methods: trait_method_type={:?}",
431 // The substitutions we have are on the impl, so we grab
432 // the method type from the impl to substitute into.
433 let mth = get_impl_method(tcx, impl_id, substs.clone(), name);
435 debug!("get_vtable_methods: mth={:?}", mth);
437 // If this is a default method, it's possible that it
438 // relies on where clauses that do not hold for this
439 // particular set of type parameters. Note that this
440 // method could then never be called, so we do not want to
441 // try and trans it, in that case. Issue #23435.
443 let predicates = mth.method.predicates.predicates.subst(tcx, mth.substs);
444 if !normalize_and_test_predicates(ccx, predicates.into_vec()) {
445 debug!("get_vtable_methods: predicates do not hold");
455 /// Replace the self type (&Self or Box<Self>) with an opaque pointer.
456 fn opaque_method_ty<'tcx>(tcx: &TyCtxt<'tcx>, method_ty: &ty::BareFnTy<'tcx>)
458 let mut inputs = method_ty.sig.0.inputs.clone();
459 inputs[0] = tcx.mk_mut_ptr(tcx.mk_mach_int(ast::IntTy::I8));
461 tcx.mk_fn_ptr(ty::BareFnTy {
462 unsafety: method_ty.unsafety,
464 sig: ty::Binder(ty::FnSig {
466 output: method_ty.sig.0.output,
467 variadic: method_ty.sig.0.variadic,
473 pub struct ImplMethod<'tcx> {
474 pub method: Rc<ty::Method<'tcx>>,
475 pub substs: Substs<'tcx>,
476 pub is_provided: bool
479 /// Locates the applicable definition of a method, given its name.
480 pub fn get_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
482 substs: Substs<'tcx>,
486 assert!(!substs.types.needs_infer());
488 traits::get_impl_item_or_default(tcx, impl_def_id, |cand| {
489 if let &ty::MethodTraitItem(ref meth) = cand {
490 if meth.name == name {
491 return Some(meth.clone())
495 }).map(|(meth, source)| {
498 substs: source.translate_substs(tcx, substs),
499 is_provided: source.is_from_trait(),
501 }).unwrap_or_else(|| {
502 tcx.sess.bug(&format!("method {:?} not found in {:?}",