pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch};
pub use self::select::{MethodMatchedData}; // intentionally don't export variants
pub use self::specialize::{OverlapError, specialization_graph, specializes, translate_substs};
-pub use self::specialize::{SpecializesCache};
+pub use self::specialize::{SpecializesCache, find_method};
pub use self::util::elaborate_predicates;
pub use self::util::supertraits;
pub use self::util::Supertraits;
Ok(resolved_value)
}
+/// Normalizes the predicates and checks whether they hold. If this
+/// returns false, then either normalize encountered an error or one
+/// of the predicates did not hold. Used when creating vtables to
+/// check for unsatisfiable methods.
+pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ predicates: Vec<ty::Predicate<'tcx>>)
+ -> bool
+{
+ debug!("normalize_and_test_predicates(predicates={:?})",
+ predicates);
+
+ tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
+ let mut selcx = SelectionContext::new(&infcx);
+ let mut fulfill_cx = FulfillmentContext::new();
+ let cause = ObligationCause::dummy();
+ let Normalized { value: predicates, obligations } =
+ normalize(&mut selcx, cause.clone(), &predicates);
+ for obligation in obligations {
+ fulfill_cx.register_predicate_obligation(&infcx, obligation);
+ }
+ for predicate in predicates {
+ let obligation = Obligation::new(cause.clone(), predicate);
+ fulfill_cx.register_predicate_obligation(&infcx, obligation);
+ }
+
+ fulfill_cx.select_all_or_error(&infcx).is_ok()
+ })
+}
+
+/// Given a trait `trait_ref`, iterates the vtable entries
+/// that come from `trait_ref`, including its supertraits.
+#[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait.
+pub fn get_vtable_methods<'a, 'tcx>(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ trait_ref: ty::PolyTraitRef<'tcx>)
+ -> impl Iterator<Item=Option<(DefId, &'tcx Substs<'tcx>)>> + 'a
+{
+ debug!("get_vtable_methods({:?})", trait_ref);
+
+ supertraits(tcx, trait_ref).flat_map(move |trait_ref| {
+ tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id());
+
+ let trait_item_def_ids = tcx.impl_or_trait_items(trait_ref.def_id());
+ let trait_methods = (0..trait_item_def_ids.len()).filter_map(move |i| {
+ match tcx.impl_or_trait_item(trait_item_def_ids[i]) {
+ ty::MethodTraitItem(m) => Some(m),
+ _ => None
+ }
+ });
+
+ // Now list each method's DefId and Substs (for within its trait).
+ // If the method can never be called from this object, produce None.
+ trait_methods.map(move |trait_method| {
+ debug!("get_vtable_methods: trait_method={:?}", trait_method);
+
+ // Some methods cannot be called on an object; skip those.
+ if !tcx.is_vtable_safe_method(trait_ref.def_id(), &trait_method) {
+ debug!("get_vtable_methods: not vtable safe");
+ return None;
+ }
+
+ // the method may have some early-bound lifetimes, add
+ // regions for those
+ let substs = Substs::for_item(tcx, trait_method.def_id,
+ |_, _| tcx.mk_region(ty::ReErased),
+ |def, _| trait_ref.substs().type_for_def(def));
+
+ // It's possible that the method relies on where clauses that
+ // do not hold for this particular set of type parameters.
+ // Note that this method could then never be called, so we
+ // do not want to try and trans it, in that case (see #23435).
+ let predicates = trait_method.predicates.instantiate_own(tcx, substs);
+ if !normalize_and_test_predicates(tcx, predicates.predicates) {
+ debug!("get_vtable_methods: predicates do not hold");
+ return None;
+ }
+
+ Some((trait_method.def_id, substs))
+ })
+ })
+}
+
impl<'tcx,O> Obligation<'tcx,O> {
pub fn new(cause: ObligationCause<'tcx>,
trait_ref: O)
use middle::region;
use ty::subst::{Subst, Substs};
use traits::{self, Reveal, ObligationCause, Normalized};
-use ty::{self, TyCtxt};
+use ty::{self, TyCtxt, TypeFoldable};
use syntax_pos::DUMMY_SP;
+use syntax::ast;
+
pub mod specialization_graph;
/// Information pertinent to an overlapping impl error.
source_substs.rebase_onto(infcx.tcx, source_impl, target_substs)
}
+/// Given a selected impl described by `impl_data`, returns the
+/// definition and substitions for the method with the name `name`,
+/// and trait method substitutions `substs`, in that impl, a less
+/// specialized impl, or the trait default, whichever applies.
+pub fn find_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ name: ast::Name,
+ substs: &'tcx Substs<'tcx>,
+ impl_data: &super::VtableImplData<'tcx, ()>)
+ -> (DefId, &'tcx Substs<'tcx>)
+{
+ assert!(!substs.needs_infer());
+
+ let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap();
+ let trait_def = tcx.lookup_trait_def(trait_def_id);
+
+ match trait_def.ancestors(impl_data.impl_def_id).fn_defs(tcx, name).next() {
+ Some(node_item) => {
+ let substs = tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
+ let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs);
+ let substs = translate_substs(&infcx, impl_data.impl_def_id,
+ substs, node_item.node);
+ tcx.lift(&substs).unwrap_or_else(|| {
+ bug!("find_method: translate_substs \
+ returned {:?} which contains inference types/regions",
+ substs);
+ })
+ });
+ (node_item.item.def_id, substs)
+ }
+ None => {
+ bug!("method {:?} not found in {:?}", name, impl_data.impl_def_id)
+ }
+ }
+}
+
/// Is impl1 a specialization of impl2?
///
/// Specialization is determined by the sets of types to which the impls apply;
//! virtually impossible. Thus, symbol hash generation exclusively relies on
//! DefPaths which are much more robust in the face of changes to the code base.
-use common::{CrateContext, SharedCrateContext, gensym_name};
+use common::SharedCrateContext;
use monomorphize::Instance;
use util::sha2::{Digest, Sha256};
let mut hash_state = scx.symbol_hasher().borrow_mut();
record_time(&tcx.sess.perf_stats.symbol_hash_time, || {
hash_state.reset();
+ let mut hasher = Sha256Hasher(&mut hash_state);
- let mut hasher = ty::util::TypeIdHasher::new(tcx, Sha256Hasher(&mut hash_state));
// the main symbol name is not necessarily unique; hash in the
// compiler's internal def-path, guaranteeing each symbol has a
// truly unique path
- hasher.hash(def_path.to_string(tcx));
+ def_path.deterministic_hash_to(tcx, &mut hasher);
// Include the main item-type. Note that, in this case, the
// assertions about `needs_subst` may not hold, but this item-type
// ought to be the same for every reference anyway.
+ let mut hasher = ty::util::TypeIdHasher::new(tcx, hasher);
assert!(!item_type.has_erasable_regions());
hasher.visit_ty(item_type);
substs.visit_with(&mut hasher);
}
});
- fn truncated_hash_result(symbol_hasher: &mut Sha256) -> String {
- let output = symbol_hasher.result_bytes();
- // 64 bits should be enough to avoid collisions.
- output[.. 8].to_hex()
- }
- format!("h{}", truncated_hash_result(&mut hash_state))
+ // 64 bits should be enough to avoid collisions.
+ let output = hash_state.result_bytes();
+ format!("h{}", output[..8].to_hex())
}
impl<'a, 'tcx> Instance<'tcx> {
pub fn symbol_name(self, scx: &SharedCrateContext<'a, 'tcx>) -> String {
- let Instance { def: def_id, ref substs } = self;
+ let Instance { def: def_id, substs } = self;
debug!("symbol_name(def_id={:?}, substs={:?})",
def_id, substs);
scx.tcx().push_item_path(&mut buffer, def_id);
});
- mangle(buffer.names.into_iter(), Some(&hash[..]))
+ mangle(buffer.names.into_iter(), &hash)
}
}
};
let hash = get_symbol_hash(scx, &empty_def_path, t, None);
let path = [token::intern_and_get_ident(prefix)];
- mangle(path.iter().cloned(), Some(&hash[..]))
-}
-
-/// Only symbols that are invisible outside their compilation unit should use a
-/// name generated by this function.
-pub fn internal_name_from_type_and_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
- t: Ty<'tcx>,
- suffix: &str)
- -> String {
- let path = [token::intern(&t.to_string()).as_str(),
- gensym_name(suffix).as_str()];
- let def_path = DefPath {
- data: vec![],
- krate: LOCAL_CRATE,
- };
- let hash = get_symbol_hash(ccx.shared(), &def_path, t, None);
- mangle(path.iter().cloned(), Some(&hash[..]))
+ mangle(path.iter().cloned(), &hash)
}
// Name sanitation. LLVM will happily accept identifiers with weird names, but
return result;
}
-pub fn mangle<PI: Iterator<Item=InternedString>>(path: PI, hash: Option<&str>) -> String {
+fn mangle<PI: Iterator<Item=InternedString>>(path: PI, hash: &str) -> String {
// Follow C++ namespace-mangling style, see
// http://en.wikipedia.org/wiki/Name_mangling for more info.
//
push(&mut n, &data);
}
- if let Some(s) = hash {
- push(&mut n, s)
- }
+ push(&mut n, hash);
n.push('E'); // End name-sequence.
n
pub use self::CalleeData::*;
use arena::TypedArena;
-use back::symbol_names;
use llvm::{self, ValueRef, get_params};
use rustc::hir::def_id::DefId;
use rustc::ty::subst::Substs;
let trait_ref = tcx.normalize_associated_type(&ty::Binder(trait_ref));
match common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref) {
traits::VtableImpl(vtable_impl) => {
- let impl_did = vtable_impl.impl_def_id;
- let mname = tcx.item_name(def_id);
- // create a concatenated set of substitutions which includes
- // those from the impl and those from the method:
- let mth = meth::get_impl_method(tcx, substs, impl_did, vtable_impl.substs, mname);
+ let name = tcx.item_name(def_id);
+ let (def_id, substs) = traits::find_method(tcx, name, substs, &vtable_impl);
// Translate the function, bypassing Callee::def.
// That is because default methods have the same ID as the
// trait method used to look up the impl method that ended
// up here, so calling Callee::def would infinitely recurse.
- let (llfn, ty) = get_fn(ccx, mth.method.def_id, mth.substs);
+ let (llfn, ty) = get_fn(ccx, def_id, substs);
Callee::ptr(llfn, ty)
}
traits::VtableClosure(vtable_closure) => {
// The substitutions should have no type parameters remaining
// after passing through fulfill_obligation
let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap();
+ let instance = Instance::new(def_id, substs);
let llfn = closure::trans_closure_method(ccx,
vtable_closure.closure_def_id,
vtable_closure.substs,
+ instance,
trait_closure_kind);
let method_ty = def_ty(ccx.shared(), def_id, substs);
}
traits::VtableFnPointer(vtable_fn_pointer) => {
let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap();
- let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, vtable_fn_pointer.fn_ty);
+ let instance = Instance::new(def_id, substs);
+ let llfn = trans_fn_pointer_shim(ccx, instance,
+ trait_closure_kind,
+ vtable_fn_pointer.fn_ty);
let method_ty = def_ty(ccx.shared(), def_id, substs);
Callee::ptr(llfn, method_ty)
pub fn reify<'a>(self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef {
match self.data {
Fn(llfn) => llfn,
- Virtual(idx) => {
- meth::trans_object_shim(ccx, self.ty, idx)
- }
+ Virtual(_) => meth::trans_object_shim(ccx, self),
NamedTupleConstructor(disr) => match self.ty.sty {
ty::TyFnDef(def_id, substs, _) => {
let instance = Instance::new(def_id, substs);
/// ```
///
/// but for the bare function type given.
-pub fn trans_fn_pointer_shim<'a, 'tcx>(
+fn trans_fn_pointer_shim<'a, 'tcx>(
ccx: &'a CrateContext<'a, 'tcx>,
+ method_instance: Instance<'tcx>,
closure_kind: ty::ClosureKind,
bare_fn_ty: Ty<'tcx>)
-> ValueRef
debug!("tuple_fn_ty: {:?}", tuple_fn_ty);
//
- let function_name =
- symbol_names::internal_name_from_type_and_suffix(ccx,
- bare_fn_ty,
- "fn_pointer_shim");
+ let function_name = method_instance.symbol_name(ccx.shared());
let llfn = declare::define_internal_fn(ccx, &function_name, tuple_fn_ty);
attributes::set_frame_pointer_elimination(ccx, llfn);
//
// except according to those terms.
use arena::TypedArena;
-use back::symbol_names;
use llvm::{self, ValueRef, get_params};
use rustc::hir::def_id::DefId;
use abi::{Abi, FnType};
pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
closure_def_id: DefId,
substs: ty::ClosureSubsts<'tcx>,
+ method_instance: Instance<'tcx>,
trait_closure_kind: ty::ClosureKind)
-> ValueRef
{
// fn call_once(mut self, ...) { call_mut(&mut self, ...) }
//
// These are both the same at trans time.
- trans_fn_once_adapter_shim(ccx, closure_def_id, substs, llfn)
+ trans_fn_once_adapter_shim(ccx, closure_def_id, substs, method_instance, llfn)
}
_ => {
bug!("trans_closure_adapter_shim: cannot convert {:?} to {:?}",
ccx: &'a CrateContext<'a, 'tcx>,
closure_def_id: DefId,
substs: ty::ClosureSubsts<'tcx>,
+ method_instance: Instance<'tcx>,
llreffn: ValueRef)
-> ValueRef
{
}));
// Create the by-value helper.
- let function_name =
- symbol_names::internal_name_from_type_and_suffix(ccx, llonce_fn_ty, "once_shim");
+ let function_name = method_instance.symbol_name(ccx.shared());
let lloncefn = declare::declare_fn(ccx, &function_name, llonce_fn_ty);
attributes::set_frame_pointer_elimination(ccx, lloncefn);
use syntax_pos::DUMMY_SP;
use base::custom_coerce_unsize_info;
use context::SharedCrateContext;
-use common::{fulfill_obligation, normalize_and_test_predicates, type_is_sized};
+use common::{fulfill_obligation, type_is_sized};
use glue::{self, DropGlueKind};
-use meth;
use monomorphize::{self, Instance};
use util::nodemap::{FnvHashSet, FnvHashMap, DefIdMap};
// Now that we know which impl is being used, we can dispatch to
// the actual function:
match vtbl {
- traits::VtableImpl(traits::VtableImplData {
- impl_def_id: impl_did,
- substs: impl_substs,
- nested: _ }) =>
- {
- let impl_method = meth::get_impl_method(tcx,
- rcvr_substs,
- impl_did,
- impl_substs,
- trait_method.name);
- Some((impl_method.method.def_id, &impl_method.substs))
+ traits::VtableImpl(impl_data) => {
+ Some(traits::find_method(tcx, trait_method.name, rcvr_substs, &impl_data))
}
// If we have a closure or a function pointer, we will also encounter
// the concrete closure/function somewhere else (during closure or fn
if let ty::TyTrait(ref trait_ty) = trait_ty.sty {
let poly_trait_ref = trait_ty.principal.with_self_ty(scx.tcx(), impl_ty);
+ let param_substs = Substs::empty(scx.tcx());
// Walk all methods of the trait, including those of its supertraits
- for trait_ref in traits::supertraits(scx.tcx(), poly_trait_ref) {
- let vtable = fulfill_obligation(scx, DUMMY_SP, trait_ref);
- match vtable {
- traits::VtableImpl(
- traits::VtableImplData {
- impl_def_id,
- substs,
- nested: _ }) => {
- let items = meth::get_vtable_methods(scx.tcx(), impl_def_id, substs)
- .into_iter()
- // filter out None values
- .filter_map(|opt_impl_method| opt_impl_method)
- // create translation items
- .filter_map(|impl_method| {
- if can_have_local_instance(scx.tcx(), impl_method.method.def_id) {
- Some(create_fn_trans_item(scx,
- impl_method.method.def_id,
- impl_method.substs,
- Substs::empty(scx.tcx())))
- } else {
- None
- }
- });
-
- output.extend(items);
- }
- _ => { /* */ }
- }
- }
+ let methods = traits::get_vtable_methods(scx.tcx(), poly_trait_ref);
+ let methods = methods.filter_map(|method| method)
+ .filter_map(|(def_id, substs)| do_static_dispatch(scx, def_id, substs, param_substs))
+ .filter(|&(def_id, _)| can_have_local_instance(scx.tcx(), def_id))
+ .map(|(def_id, substs)| create_fn_trans_item(scx, def_id, substs, param_substs));
+ output.extend(methods);
// Also add the destructor
let dg_type = glue::get_drop_glue_type(scx.tcx(), impl_ty);
- if glue::type_needs_drop(scx.tcx(), dg_type) {
- output.push(TransItem::DropGlue(DropGlueKind::Ty(dg_type)));
- }
+ output.push(TransItem::DropGlue(DropGlueKind::Ty(dg_type)));
}
}
let impl_substs = Substs::for_item(tcx, impl_def_id,
|_, _| tcx.mk_region(ty::ReErased),
|_, _| tcx.types.err);
- let mth = meth::get_impl_method(tcx,
- callee_substs,
- impl_def_id,
- impl_substs,
- method.name);
-
- assert!(mth.is_provided);
-
- let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs);
- if !normalize_and_test_predicates(tcx, predicates) {
+ let impl_data = traits::VtableImplData {
+ impl_def_id: impl_def_id,
+ substs: impl_substs,
+ nested: vec![]
+ };
+ let (def_id, substs) = traits::find_method(tcx,
+ method.name,
+ callee_substs,
+ &impl_data);
+
+ let predicates = tcx.lookup_predicates(def_id).predicates
+ .subst(tcx, substs);
+ if !traits::normalize_and_test_predicates(tcx, predicates) {
continue;
}
if can_have_local_instance(tcx, method.def_id) {
- let empty_substs = tcx.erase_regions(&mth.substs);
let item = create_fn_trans_item(scx,
method.def_id,
callee_substs,
- empty_substs);
+ tcx.erase_regions(&substs));
output.push(item);
}
}
llsize_of_alloc(ccx, llty) == 0
}
-/// Generates a unique symbol based off the name given. This is used to create
-/// unique symbols for things like closures.
-pub fn gensym_name(name: &str) -> ast::Name {
- let num = token::gensym(name).0;
- // use one colon which will get translated to a period by the mangler, and
- // we're guaranteed that `num` is globally unique for this crate.
- token::gensym(&format!("{}:{}", name, num))
-}
-
/*
* A note on nomenclature of linking: "extern", "foreign", and "upcall".
*
})
}
-/// Normalizes the predicates and checks whether they hold. If this
-/// returns false, then either normalize encountered an error or one
-/// of the predicates did not hold. Used when creating vtables to
-/// check for unsatisfiable methods.
-pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- predicates: Vec<ty::Predicate<'tcx>>)
- -> bool
-{
- debug!("normalize_and_test_predicates(predicates={:?})",
- predicates);
-
- tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
- let mut selcx = SelectionContext::new(&infcx);
- let mut fulfill_cx = traits::FulfillmentContext::new();
- let cause = traits::ObligationCause::dummy();
- let traits::Normalized { value: predicates, obligations } =
- traits::normalize(&mut selcx, cause.clone(), &predicates);
- for obligation in obligations {
- fulfill_cx.register_predicate_obligation(&infcx, obligation);
- }
- for predicate in predicates {
- let obligation = traits::Obligation::new(cause.clone(), predicate);
- fulfill_cx.register_predicate_obligation(&infcx, obligation);
- }
-
- fulfill_cx.select_all_or_error(&infcx).is_ok()
- })
-}
-
pub fn langcall(tcx: TyCtxt,
span: Option<Span>,
msg: &str,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::rc::Rc;
-
use attributes;
use arena::TypedArena;
-use back::symbol_names;
use llvm::{ValueRef, get_params};
-use rustc::hir::def_id::DefId;
-use rustc::ty::subst::{Subst, Substs};
-use rustc::traits::{self, Reveal};
+use rustc::traits;
use abi::FnType;
use base::*;
use build::*;
-use callee::{Callee, Virtual, trans_fn_pointer_shim};
-use closure;
+use callee::Callee;
use common::*;
use consts;
use debuginfo::DebugLoc;
use declare;
use glue;
use machine;
+use monomorphize::Instance;
use type_::Type;
use type_of::*;
use value::Value;
-use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
-
-use syntax::ast::Name;
-use syntax_pos::DUMMY_SP;
+use rustc::ty;
// drop_glue pointer, size, align.
const VTABLE_OFFSET: usize = 3;
/// In fact, all virtual calls can be thought of as normal trait calls
/// that go through this shim function.
pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
- method_ty: Ty<'tcx>,
- vtable_index: usize)
+ callee: Callee<'tcx>)
-> ValueRef {
let _icx = push_ctxt("trans_object_shim");
let tcx = ccx.tcx();
- debug!("trans_object_shim(vtable_index={}, method_ty={:?})",
- vtable_index,
- method_ty);
+ debug!("trans_object_shim({:?})", callee);
+
+ let (sig, abi, function_name) = match callee.ty.sty {
+ ty::TyFnDef(def_id, substs, f) => {
+ let instance = Instance::new(def_id, substs);
+ (&f.sig, f.abi, instance.symbol_name(ccx.shared()))
+ }
+ _ => bug!()
+ };
- let sig = tcx.erase_late_bound_regions(&method_ty.fn_sig());
+ let sig = tcx.erase_late_bound_regions(sig);
let sig = tcx.normalize_associated_type(&sig);
- let fn_ty = FnType::new(ccx, method_ty.fn_abi(), &sig, &[]);
+ let fn_ty = FnType::new(ccx, abi, &sig, &[]);
- let function_name =
- symbol_names::internal_name_from_type_and_suffix(ccx, method_ty, "object_shim");
- let llfn = declare::define_internal_fn(ccx, &function_name, method_ty);
+ let llfn = declare::define_internal_fn(ccx, &function_name, callee.ty);
attributes::set_frame_pointer_elimination(ccx, llfn);
let (block_arena, fcx): (TypedArena<_>, FunctionContext);
let mut bcx = fcx.init(false);
let dest = fcx.llretslotptr.get();
-
- debug!("trans_object_shim: method_offset_in_vtable={}",
- vtable_index);
-
let llargs = get_params(fcx.llfn);
-
- let callee = Callee {
- data: Virtual(vtable_index),
- ty: method_ty
- };
bcx = callee.call(bcx, DebugLoc::None,
&llargs[fcx.fn_ty.ret.is_indirect() as usize..], dest).bcx;
}
// Not in the cache. Build it.
- let methods = traits::supertraits(tcx, trait_ref.clone()).flat_map(|trait_ref| {
- let vtable = fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref.clone());
- match vtable {
- // Should default trait error here?
- traits::VtableDefaultImpl(_) |
- traits::VtableBuiltin(_) => {
- Vec::new().into_iter()
- }
- traits::VtableImpl(
- traits::VtableImplData {
- impl_def_id: id,
- substs,
- nested: _ }) => {
- let nullptr = C_null(Type::nil(ccx).ptr_to());
- get_vtable_methods(tcx, id, substs)
- .into_iter()
- .map(|opt_mth| opt_mth.map_or(nullptr, |mth| {
- Callee::def(ccx, mth.method.def_id, &mth.substs).reify(ccx)
- }))
- .collect::<Vec<_>>()
- .into_iter()
- }
- traits::VtableClosure(
- traits::VtableClosureData {
- closure_def_id,
- substs,
- nested: _ }) => {
- let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_ref.def_id()).unwrap();
- let llfn = closure::trans_closure_method(ccx,
- closure_def_id,
- substs,
- trait_closure_kind);
- vec![llfn].into_iter()
- }
- traits::VtableFnPointer(
- traits::VtableFnPointerData {
- fn_ty: bare_fn_ty,
- nested: _ }) => {
- let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_ref.def_id()).unwrap();
- vec![trans_fn_pointer_shim(ccx, trait_closure_kind, bare_fn_ty)].into_iter()
- }
- traits::VtableObject(ref data) => {
- // this would imply that the Self type being erased is
- // an object type; this cannot happen because we
- // cannot cast an unsized type into a trait object
- bug!("cannot get vtable for an object type: {:?}",
- data);
- }
- traits::VtableParam(..) => {
- bug!("resolved vtable for {:?} to bad vtable {:?} in trans",
- trait_ref,
- vtable);
- }
- }
+ let nullptr = C_null(Type::nil(ccx).ptr_to());
+ let methods = traits::get_vtable_methods(tcx, trait_ref).map(|opt_mth| {
+ opt_mth.map_or(nullptr, |(def_id, substs)| {
+ Callee::def(ccx, def_id, substs).reify(ccx)
+ })
});
let size_ty = sizing_type_of(ccx, trait_ref.self_ty());
let size = machine::llsize_of_alloc(ccx, size_ty);
let align = align_of(ccx, trait_ref.self_ty());
- let components: Vec<_> = vec![
+ let components: Vec<_> = [
// Generate a destructor for the vtable.
glue::get_drop_glue(ccx, trait_ref.self_ty()),
C_uint(ccx, size),
C_uint(ccx, align)
- ].into_iter().chain(methods).collect();
+ ].iter().cloned().chain(methods).collect();
let vtable_const = C_struct(ccx, &components, false);
let align = machine::llalign_of_pref(ccx, val_ty(vtable_const));
ccx.vtables().borrow_mut().insert(trait_ref, vtable);
vtable
}
-
-pub fn get_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- impl_id: DefId,
- substs: &'tcx Substs<'tcx>)
- -> Vec<Option<ImplMethod<'tcx>>>
-{
- debug!("get_vtable_methods(impl_id={:?}, substs={:?}", impl_id, substs);
-
- let trait_id = match tcx.impl_trait_ref(impl_id) {
- Some(t_id) => t_id.def_id,
- None => bug!("make_impl_vtable: don't know how to \
- make a vtable for a type impl!")
- };
-
- tcx.populate_implementations_for_trait_if_necessary(trait_id);
-
- let trait_item_def_ids = tcx.impl_or_trait_items(trait_id);
- trait_item_def_ids
- .iter()
-
- // Filter out non-method items.
- .filter_map(|&item_def_id| {
- match tcx.impl_or_trait_item(item_def_id) {
- ty::MethodTraitItem(m) => Some(m),
- _ => None
- }
- })
-
- // Now produce pointers for each remaining method. If the
- // method could never be called from this object, just supply
- // null.
- .map(|trait_method_type| {
- debug!("get_vtable_methods: trait_method_def_id={:?}",
- trait_method_type.def_id);
-
- let name = trait_method_type.name;
-
- // Some methods cannot be called on an object; skip those.
- if !tcx.is_vtable_safe_method(trait_id, &trait_method_type) {
- debug!("get_vtable_methods: not vtable safe");
- return None;
- }
-
- debug!("get_vtable_methods: trait_method_type={:?}",
- trait_method_type);
-
- // the method may have some early-bound lifetimes, add
- // regions for those
- let method_substs = Substs::for_item(tcx, trait_method_type.def_id,
- |_, _| tcx.mk_region(ty::ReErased),
- |_, _| tcx.types.err);
-
- // The substitutions we have are on the impl, so we grab
- // the method type from the impl to substitute into.
- let mth = get_impl_method(tcx, method_substs, impl_id, substs, name);
-
- debug!("get_vtable_methods: mth={:?}", mth);
-
- // If this is a default method, it's possible that it
- // relies on where clauses that do not hold for this
- // particular set of type parameters. Note that this
- // method could then never be called, so we do not want to
- // try and trans it, in that case. Issue #23435.
- if mth.is_provided {
- let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs);
- if !normalize_and_test_predicates(tcx, predicates) {
- debug!("get_vtable_methods: predicates do not hold");
- return None;
- }
- }
-
- Some(mth)
- })
- .collect()
-}
-
-#[derive(Debug)]
-pub struct ImplMethod<'tcx> {
- pub method: Rc<ty::Method<'tcx>>,
- pub substs: &'tcx Substs<'tcx>,
- pub is_provided: bool
-}
-
-/// Locates the applicable definition of a method, given its name.
-pub fn get_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- substs: &'tcx Substs<'tcx>,
- impl_def_id: DefId,
- impl_substs: &'tcx Substs<'tcx>,
- name: Name)
- -> ImplMethod<'tcx>
-{
- assert!(!substs.needs_infer());
-
- let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap();
- let trait_def = tcx.lookup_trait_def(trait_def_id);
-
- match trait_def.ancestors(impl_def_id).fn_defs(tcx, name).next() {
- Some(node_item) => {
- let substs = tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
- let substs = substs.rebase_onto(tcx, trait_def_id, impl_substs);
- let substs = traits::translate_substs(&infcx, impl_def_id,
- substs, node_item.node);
- tcx.lift(&substs).unwrap_or_else(|| {
- bug!("trans::meth::get_impl_method: translate_substs \
- returned {:?} which contains inference types/regions",
- substs);
- })
- });
- ImplMethod {
- method: node_item.item,
- substs: substs,
- is_provided: node_item.node.is_from_trait(),
- }
- }
- None => {
- bug!("method {:?} not found in {:?}", name, impl_def_id)
- }
- }
-}