// Copyright 2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Code for translating references to other items (DefIds). use syntax::codemap::DUMMY_SP; use rustc::front::map; use rustc::middle::ty::{self, Ty, TypeFoldable}; use rustc::middle::subst::Substs; use rustc::middle::const_eval; use rustc::middle::def_id::DefId; use rustc::middle::traits; use rustc::mir::repr::ItemKind; use trans::common::{Block, fulfill_obligation}; use trans::base; use trans::closure; use trans::expr; use trans::monomorphize; use trans::meth; use trans::inline; use super::MirContext; use super::operand::{OperandRef, OperandValue}; impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { /// Translate reference to item. pub fn trans_item_ref(&mut self, bcx: Block<'bcx, 'tcx>, ty: Ty<'tcx>, kind: ItemKind, substs: &'tcx Substs<'tcx>, did: DefId) -> OperandRef<'tcx> { debug!("trans_item_ref(ty={:?}, kind={:?}, substs={:?}, did={})", ty, kind, substs, bcx.tcx().item_path_str(did)); match kind { ItemKind::Function => self.trans_fn_ref(bcx, ty, substs, did), ItemKind::Method => match bcx.tcx().impl_or_trait_item(did).container() { ty::ImplContainer(_) => self.trans_fn_ref(bcx, ty, substs, did), ty::TraitContainer(tdid) => self.trans_trait_method(bcx, ty, did, tdid, substs) }, ItemKind::Constant => { let did = inline::maybe_instantiate_inline(bcx.ccx(), did); let expr = const_eval::lookup_const_by_id(bcx.tcx(), did, None, Some(substs)) .expect("def was const, but lookup_const_by_id failed"); // FIXME: this is falling back to translating from HIR. This is not easy to fix, // because we would have somehow adapt const_eval to work on MIR rather than HIR. let d = expr::trans(bcx, expr); OperandRef::from_rvalue_datum(d.datum.to_rvalue_datum(d.bcx, "").datum) } } } /// Translates references to a function-like items. /// /// That includes regular functions, non-static methods, struct and enum variant constructors, /// closures and possibly more. /// /// This is an adaptation of callee::trans_fn_ref_with_substs. pub fn trans_fn_ref(&mut self, bcx: Block<'bcx, 'tcx>, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>, did: DefId) -> OperandRef<'tcx> { debug!("trans_fn_ref(ty={:?}, substs={:?}, did={})", ty, substs, bcx.tcx().item_path_str(did)); let did = inline::maybe_instantiate_inline(bcx.ccx(), did); if !substs.types.is_empty() || is_named_tuple_constructor(bcx.tcx(), did) { let (val, fn_ty, _) = monomorphize::monomorphic_fn(bcx.ccx(), did, substs, None); // FIXME: cast fnptr to proper type if necessary OperandRef { ty: fn_ty, val: OperandValue::Immediate(val) } } else { let val = if let Some(node_id) = bcx.tcx().map.as_local_node_id(did) { base::get_item_val(bcx.ccx(), node_id) } else { base::trans_external_path(bcx.ccx(), did, ty) }; // FIXME: cast fnptr to proper type if necessary OperandRef { ty: ty, val: OperandValue::Immediate(val) } } } /// Translates references to trait methods. /// /// This is an adaptation of meth::trans_static_method_callee pub fn trans_trait_method(&mut self, bcx: Block<'bcx, 'tcx>, ty: Ty<'tcx>, method_id: DefId, trait_id: DefId, substs: &'tcx Substs<'tcx>) -> OperandRef<'tcx> { debug!("trans_static_method(ty={:?}, method={}, trait={}, substs={:?})", ty, bcx.tcx().item_path_str(method_id), bcx.tcx().item_path_str(trait_id), substs); let ccx = bcx.ccx(); let tcx = bcx.tcx(); let trait_ref = ty::Binder(substs.to_trait_ref(tcx, trait_id)); let vtbl = fulfill_obligation(ccx, DUMMY_SP, trait_ref); match vtbl { traits::VtableImpl(traits::VtableImplData { impl_def_id, substs: impl_substs, .. }) => { assert!(!impl_substs.types.needs_infer()); let mname = tcx.item_name(method_id); let callee_substs = impl_substs.with_method_from(substs); let mth = tcx.get_impl_method(impl_def_id, callee_substs, mname); let mth_substs = tcx.mk_substs(mth.substs); self.trans_fn_ref(bcx, ty, mth_substs, mth.method.def_id) }, traits::VtableClosure(data) => { let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap(); let llfn = closure::trans_closure_method(bcx.ccx(), data.closure_def_id, data.substs, trait_closure_kind); OperandRef { ty: ty, val: OperandValue::Immediate(llfn) } }, traits::VtableObject(ref data) => { let idx = traits::get_vtable_index_of_object_method(tcx, data, method_id); OperandRef::from_rvalue_datum( meth::trans_object_shim(ccx, data.upcast_trait_ref.clone(), method_id, idx) ) } _ => { tcx.sess.bug(&format!("static call to invalid vtable: {:?}", vtbl)); } } } } fn is_named_tuple_constructor(tcx: &ty::ctxt, def_id: DefId) -> bool { let node_id = match tcx.map.as_local_node_id(def_id) { Some(n) => n, None => { return false; } }; match tcx.map.find(node_id).expect("local item should be in ast map") { map::NodeVariant(v) => { v.node.data.is_tuple() } map::NodeStructCtor(_) => true, _ => false } }