diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 7e7d06e4b814..c71fc28b4d6b 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -40,7 +40,7 @@ pub use self::select::{EvaluationCache, SelectionContext, SelectionCache}; 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, find_method}; +pub use self::specialize::{SpecializesCache, find_associated_item}; pub use self::util::elaborate_predicates; pub use self::util::supertraits; pub use self::util::Supertraits; diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 2c99ee21b0f7..50a4d982832a 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -29,8 +29,6 @@ use traits::{self, Reveal, ObligationCause}; use ty::{self, TyCtxt, TypeFoldable}; use syntax_pos::DUMMY_SP; -use syntax::ast; - pub mod specialization_graph; /// Information pertinent to an overlapping impl error. @@ -106,22 +104,23 @@ pub fn translate_substs<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, } /// 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>) -{ +/// definition and substitions for the method with the name `name` +/// the kind `kind`, and trait method substitutions `substs`, in +/// that impl, a less specialized impl, or the trait default, +/// whichever applies. +pub fn find_associated_item<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + item: &ty::AssociatedItem, + 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); let ancestors = trait_def.ancestors(impl_data.impl_def_id); - match ancestors.defs(tcx, name, ty::AssociatedKind::Method).next() { + match ancestors.defs(tcx, item.name, item.kind).next() { Some(node_item) => { let substs = tcx.infer_ctxt((), Reveal::All).enter(|infcx| { let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs); @@ -137,7 +136,7 @@ pub fn find_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (node_item.item.def_id, substs) } None => { - bug!("method {:?} not found in {:?}", name, impl_data.impl_def_id) + bug!("{:?} not found in {:?}", item, impl_data.impl_def_id) } } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index a0aeb4107c15..5543223105b4 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1469,6 +1469,15 @@ impl InternIteratorElement for T { } } +impl<'a, T, R> InternIteratorElement for &'a T + where T: Clone + 'a +{ + type Output = R; + fn intern_with, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output { + f(&iter.cloned().collect::>()) + } +} + impl InternIteratorElement for Result { type Output = Result; fn intern_with, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output { diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index fdcfb3ebd3ce..d93482acbcb5 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -27,8 +27,17 @@ pub struct Instance<'tcx> { #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum InstanceDef<'tcx> { Item(DefId), + Intrinsic(DefId), // ::call_* + // def-id is FnTrait::call_* FnPtrShim(DefId, Ty<'tcx>), + // ::fn + Virtual(DefId, usize), + // <[mut closure] as FnOnce>::call_once + ClosureOnceShim { + call_once: DefId, + closure_did: DefId + }, } impl<'tcx> InstanceDef<'tcx> { @@ -36,8 +45,12 @@ impl<'tcx> InstanceDef<'tcx> { pub fn def_id(&self) -> DefId { match *self { InstanceDef::Item(def_id) | - InstanceDef::FnPtrShim(def_id, _) - => def_id + InstanceDef::FnPtrShim(def_id, _) | + InstanceDef::Virtual(def_id, _) | + InstanceDef::Intrinsic(def_id, ) | + InstanceDef::ClosureOnceShim { + call_once: def_id, closure_did: _ + } => def_id } } @@ -73,14 +86,23 @@ impl<'tcx> InstanceDef<'tcx> { impl<'tcx> fmt::Display for Instance<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ppaux::parameterized(f, self.substs, self.def_id(), &[])?; match self.def { - InstanceDef::Item(def) => { - ppaux::parameterized(f, self.substs, def, &[]) + InstanceDef::Item(_) => Ok(()), + InstanceDef::Intrinsic(_) => { + write!(f, " - intrinsic") } - InstanceDef::FnPtrShim(def, ty) => { - ppaux::parameterized(f, self.substs, def, &[])?; + InstanceDef::Virtual(_, num) => { + write!(f, " - shim(#{})", num) + } + InstanceDef::FnPtrShim(_, ty) => { write!(f, " - shim({:?})", ty) } + InstanceDef::ClosureOnceShim { + call_once: _, closure_did + } => { + write!(f, " - shim({:?})", closure_did) + } } } } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 2344305fa9a7..1d816d342c4f 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -408,8 +408,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id) }) } - - } pub struct TypeIdHasher<'a, 'gcx: 'a+'tcx, 'tcx: 'a, W> { diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index bf0b1796dffa..2a053535e7e1 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -41,6 +41,7 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, ty::InstanceDef::FnPtrShim(_, ty) => { build_fn_ptr_shim(tcx, ty, instance.def_ty(tcx)) } + _ => bug!("unknown shim kind") }; debug!("make_shim({:?}) = {:?}", instance, result); diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index ce767468c012..10ab199671f6 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -36,9 +36,7 @@ use llvm::{Linkage, ValueRef, Vector, get_param}; use llvm; use rustc::hir::def_id::LOCAL_CRATE; use middle::lang_items::StartFnLangItem; -use rustc::traits; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::adjustment::CustomCoerceUnsized; use rustc::dep_graph::{AssertDepGraphSafe, DepNode, WorkProduct}; use rustc::hir::map as hir_map; use rustc::util::common::time; @@ -54,7 +52,6 @@ use common::{C_bool, C_bytes_in_context, C_i32, C_uint}; use collector::{self, TransItemCollectionMode}; use common::{C_struct_in_context, C_u64, C_undef}; use common::CrateContext; -use common::{fulfill_obligation}; use common::{type_is_zero_size, val_ty}; use common; use consts; @@ -80,7 +77,7 @@ use std::ffi::{CStr, CString}; use std::rc::Rc; use std::str; use std::i32; -use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::Span; use syntax::attr; use rustc::hir; use rustc::ty::layout::{self, Layout}; @@ -313,25 +310,6 @@ pub fn coerce_unsized_into<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, } } -pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx>, - source_ty: Ty<'tcx>, - target_ty: Ty<'tcx>) - -> CustomCoerceUnsized { - let trait_ref = ty::Binder(ty::TraitRef { - def_id: scx.tcx().lang_items.coerce_unsized_trait().unwrap(), - substs: scx.tcx().mk_substs_trait(source_ty, &[target_ty]) - }); - - match fulfill_obligation(scx, DUMMY_SP, trait_ref) { - traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => { - scx.tcx().custom_coerce_unsized_kind(impl_def_id) - } - vtable => { - bug!("invalid CoerceUnsized vtable: {:?}", vtable); - } - } -} - pub fn cast_shift_expr_rhs( cx: &Builder, op: hir::BinOp_, lhs: ValueRef, rhs: ValueRef ) -> ValueRef { diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 2294e8a0002e..70da2a69ef42 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -19,13 +19,13 @@ pub use self::CalleeData::*; use llvm::{self, ValueRef, get_params}; use rustc::hir::def_id::DefId; use rustc::ty::subst::{Substs, Subst}; -use rustc::traits; use abi::{Abi, FnType}; use attributes; use builder::Builder; use common::{self, CrateContext}; use cleanup::CleanupScope; use mir::lvalue::LvalueRef; +use monomorphize; use consts; use common::instance_ty; use declare; @@ -38,8 +38,6 @@ use type_of; use rustc::ty::{self, Ty, TypeFoldable}; use std::iter; -use syntax_pos::DUMMY_SP; - use mir::lvalue::Alignment; #[derive(Debug)] @@ -60,94 +58,39 @@ pub struct Callee<'tcx> { } impl<'tcx> Callee<'tcx> { - /// Function pointer. - pub fn ptr(llfn: ValueRef, ty: Ty<'tcx>) -> Callee<'tcx> { - Callee { - data: Fn(llfn), - ty: ty - } - } - /// Function or method definition. pub fn def<'a>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx>) -> Callee<'tcx> { - let tcx = ccx.tcx(); - - if let Some(trait_id) = tcx.trait_of_item(def_id) { - return Callee::trait_method(ccx, trait_id, def_id, substs); - } - - let instance = ty::Instance::new(def_id, substs); - let fn_ty = instance_ty(ccx.shared(), &instance); - if let ty::TyFnDef(.., f) = fn_ty.sty { - if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic { - return Callee { - data: Intrinsic, - ty: fn_ty + let instance = monomorphize::resolve(ccx.shared(), def_id, substs); + let ty = instance_ty(ccx.shared(), &instance); + let data = match instance.def { + ty::InstanceDef::Intrinsic(_) => Intrinsic, + ty::InstanceDef::ClosureOnceShim { .. } => { + let closure_ty = instance.substs.type_at(0); + let (closure_def_id, closure_substs) = match closure_ty.sty { + ty::TyClosure(def_id, substs) => (def_id, substs), + _ => bug!("bad closure instance {:?}", instance) }; - } - } - let (llfn, ty) = get_fn(ccx, instance); - Callee::ptr(llfn, ty) - } - - /// Trait method, which has to be resolved to an impl method. - pub fn trait_method<'a>(ccx: &CrateContext<'a, 'tcx>, - trait_id: DefId, - def_id: DefId, - substs: &'tcx Substs<'tcx>) - -> Callee<'tcx> { - let tcx = ccx.tcx(); - - let trait_ref = ty::TraitRef::from_method(tcx, trait_id, 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 name = tcx.item_name(def_id); - let instance = common::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, instance); - 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 = trans_closure_method( + Fn(trans_fn_once_adapter_shim( ccx, - vtable_closure.closure_def_id, - vtable_closure.substs, + closure_def_id, + closure_substs, instance, - trait_closure_kind); + get_fn( + ccx, + Instance::new(closure_def_id, closure_substs.substs) + ) + )) + } + ty::InstanceDef::Virtual(_, n) => Virtual(n), + ty::InstanceDef::FnPtrShim(..) | + ty::InstanceDef::Item(..) => { + Fn(get_fn(ccx, instance)) + } + }; - let method_ty = instance_ty(ccx.shared(), &instance); - Callee::ptr(llfn, method_ty) - } - traits::VtableFnPointer(data) => { - let instance = ty::Instance { - def: ty::InstanceDef::FnPtrShim(def_id, data.fn_ty), - substs: substs, - }; - - let (llfn, ty) = get_fn(ccx, instance); - Callee::ptr(llfn, ty) - } - traits::VtableObject(ref data) => { - Callee { - data: Virtual(tcx.get_vtable_index_of_object_method(data, def_id)), - ty: instance_ty(ccx.shared(), &Instance::new(def_id, substs)) - } - } - vtable => { - bug!("resolved vtable bad vtable {:?} in trans", vtable); - } - } + Callee { data, ty } } /// Get the abi::FnType for a direct call. Mainly deals with the fact @@ -155,7 +98,8 @@ impl<'tcx> Callee<'tcx> { /// The extra argument types are for variadic (extern "C") functions. pub fn direct_fn_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>, extra_args: &[Ty<'tcx>]) -> FnType { - let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&self.ty.fn_sig()); + let sig = common::ty_fn_sig(ccx, self.ty); + let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&sig); let mut fn_ty = FnType::unadjusted(ccx, sig, extra_args); if let Virtual(_) = self.data { // Don't pass the vtable, it's not an argument of the virtual fn. @@ -175,72 +119,6 @@ impl<'tcx> Callee<'tcx> { } } -fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, - def_id: DefId, - substs: ty::ClosureSubsts<'tcx>, - method_instance: Instance<'tcx>, - trait_closure_kind: ty::ClosureKind) - -> ValueRef -{ - // If this is a closure, redirect to it. - let (llfn, _) = get_fn(ccx, Instance::new(def_id, substs.substs)); - - // If the closure is a Fn closure, but a FnOnce is needed (etc), - // then adapt the self type - let llfn_closure_kind = ccx.tcx().closure_kind(def_id); - - debug!("trans_closure_adapter_shim(llfn_closure_kind={:?}, \ - trait_closure_kind={:?}, llfn={:?})", - llfn_closure_kind, trait_closure_kind, Value(llfn)); - - match needs_fn_once_adapter_shim(llfn_closure_kind, trait_closure_kind) { - Ok(true) => trans_fn_once_adapter_shim(ccx, - def_id, - substs, - method_instance, - llfn), - Ok(false) => llfn, - Err(()) => { - bug!("trans_closure_adapter_shim: cannot convert {:?} to {:?}", - llfn_closure_kind, - trait_closure_kind); - } - } -} - -pub fn needs_fn_once_adapter_shim(actual_closure_kind: ty::ClosureKind, - trait_closure_kind: ty::ClosureKind) - -> Result -{ - match (actual_closure_kind, trait_closure_kind) { - (ty::ClosureKind::Fn, ty::ClosureKind::Fn) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) | - (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => { - // No adapter needed. - Ok(false) - } - (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => { - // The closure fn `llfn` is a `fn(&self, ...)`. We want a - // `fn(&mut self, ...)`. In fact, at trans time, these are - // basically the same thing, so we can just return llfn. - Ok(false) - } - (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { - // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut - // self, ...)`. We want a `fn(self, ...)`. We can produce - // this by doing something like: - // - // fn call_once(self, ...) { call_mut(&self, ...) } - // fn call_once(mut self, ...) { call_mut(&mut self, ...) } - // - // These are both the same at trans time. - Ok(true) - } - _ => Err(()), - } -} - fn trans_fn_once_adapter_shim<'a, 'tcx>( ccx: &'a CrateContext<'a, 'tcx>, def_id: DefId, @@ -307,7 +185,6 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( // the first argument (`self`) will be the (by value) closure env. let mut llargs = get_params(lloncefn); - let fn_ret = callee.ty.fn_ret(); let fn_ty = callee.direct_fn_type(bcx.ccx, &[]); let self_idx = fn_ty.ret.is_indirect() as usize; let env_arg = &orig_fn_ty.args[0]; @@ -344,7 +221,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( } fn_ty.apply_attrs_callsite(llret); - if fn_ret.0.is_never() { + if sig.output().is_never() { bcx.unreachable(); } else { self_scope.trans(&bcx); @@ -372,7 +249,8 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( /// - `substs`: values for each of the fn/method's parameters fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance<'tcx>) - -> (ValueRef, Ty<'tcx>) { + -> ValueRef +{ let tcx = ccx.tcx(); debug!("get_fn(instance={:?})", instance); @@ -383,7 +261,7 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let fn_ty = common::instance_ty(ccx.shared(), &instance); if let Some(&llfn) = ccx.instances().borrow().get(&instance) { - return (llfn, fn_ty); + return llfn; } let sym = ccx.symbol_map().get_or_compute(ccx.shared(), @@ -455,5 +333,5 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ccx.instances().borrow_mut().insert(instance, llfn); - (llfn, fn_ty) + llfn } diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index c4239fa2ae65..9476ffc94448 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -203,11 +203,8 @@ use rustc::mir::visit as mir_visit; use rustc::mir::visit::Visitor as MirVisitor; use syntax::abi::Abi; -use syntax_pos::DUMMY_SP; -use base::custom_coerce_unsize_info; -use callee::needs_fn_once_adapter_shim; use context::SharedCrateContext; -use common::{def_ty, find_method, instance_ty, fulfill_obligation}; +use common::{def_ty, instance_ty}; use glue::{self, DropGlueKind}; use monomorphize::{self, Instance}; use util::nodemap::{FxHashSet, FxHashMap, DefIdMap}; @@ -555,7 +552,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { let substs = monomorphize::apply_param_substs(self.scx, self.param_substs, &substs); - let instance = monomorphize::resolve_const(self.scx, def_id, substs); + let instance = monomorphize::resolve(self.scx, def_id, substs); collect_neighbours(self.scx, instance, self.output); } @@ -580,32 +577,23 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { let callee_substs = monomorphize::apply_param_substs(self.scx, self.param_substs, &callee_substs); - let dispatched = do_static_dispatch(self.scx, - callee_def_id, - callee_substs); + let instance = + monomorphize::resolve(self.scx, callee_def_id, callee_substs); + if should_trans_locally(self.scx.tcx(), &instance) { + if let ty::InstanceDef::ClosureOnceShim { .. } = instance.def { + // This call will instantiate an FnOnce adapter, which + // drops the closure environment. Therefore we need to + // make sure that we collect the drop-glue for the + // environment type. - if let StaticDispatchResult::Dispatched { - instance, fn_once_adjustment - } = dispatched { - // if we have a concrete impl (which we might not have - // in the case of something compiler generated like an - // object shim or a closure that is handled differently), - // we check if the callee is something that will actually - // result in a translation item ... - if should_trans_locally(self.scx.tcx(), &instance) { - self.output.push(create_fn_trans_item(instance)); - - // This call will instantiate an FnOnce adapter, which drops - // the closure environment. Therefore we need to make sure - // that we collect the drop-glue for the environment type. - if let Some(env_ty) = fn_once_adjustment { - let env_ty = glue::get_drop_glue_type(self.scx, env_ty); - if self.scx.type_needs_drop(env_ty) { - let dg = DropGlueKind::Ty(env_ty); - self.output.push(TransItem::DropGlue(dg)); - } + let env_ty = instance.substs.type_at(0); + let env_ty = glue::get_drop_glue_type(self.scx, env_ty); + if self.scx.type_needs_drop(env_ty) { + let dg = DropGlueKind::Ty(env_ty); + self.output.push(TransItem::DropGlue(dg)); } } + self.output.push(create_fn_trans_item(instance)); } } @@ -664,8 +652,13 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { fn should_trans_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: &Instance<'tcx>) -> bool { let def_id = match instance.def { - ty::InstanceDef::Item(def_id) => def_id, - ty::InstanceDef::FnPtrShim(..) => return true + ty::InstanceDef::Item(def_id) | + ty::InstanceDef::ClosureOnceShim { + call_once: _, closure_did: def_id + } => def_id, + ty::InstanceDef::FnPtrShim(..) => return true, + ty::InstanceDef::Virtual(..) | + ty::InstanceDef::Intrinsic(_) => return false }; match tcx.hir.get_if_local(def_id) { Some(hir_map::NodeForeignItem(..)) => { @@ -718,31 +711,21 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, // If the type implements Drop, also add a translation item for the // monomorphized Drop::drop() implementation. - let destructor = match ty.sty { - ty::TyAdt(def, _) => def.destructor(scx.tcx()), - _ => None + let has_dtor = match ty.sty { + ty::TyAdt(def, _) => def.has_dtor(scx.tcx()), + _ => false }; - if let (Some(destructor), false) = (destructor, ty.is_box()) { - use rustc::ty::ToPolyTraitRef; - + if has_dtor && !ty.is_box() { let drop_trait_def_id = scx.tcx() .lang_items .drop_trait() .unwrap(); - - let self_type_substs = scx.tcx().mk_substs_trait(ty, &[]); - - let trait_ref = ty::TraitRef { - def_id: drop_trait_def_id, - substs: self_type_substs, - }.to_poly_trait_ref(); - - let substs = match fulfill_obligation(scx, DUMMY_SP, trait_ref) { - traits::VtableImpl(data) => data.substs, - _ => bug!() - }; - let instance = Instance::new(destructor.did, substs); + let drop_method = scx.tcx().associated_items(drop_trait_def_id) + .find(|it| it.kind == ty::AssociatedKind::Method) + .unwrap().def_id; + let substs = scx.tcx().mk_substs_trait(ty, &[]); + let instance = monomorphize::resolve(scx, drop_method, substs); if should_trans_locally(scx.tcx(), &instance) { output.push(create_fn_trans_item(instance)); } @@ -817,115 +800,6 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, } } -enum StaticDispatchResult<'tcx> { - // The call could be resolved statically as going to the method with - // `instance`. - Dispatched { - instance: Instance<'tcx>, - // If this is a call to a closure that needs an FnOnce adjustment, - // this contains the new self type of the call (= type of the closure - // environment) - fn_once_adjustment: Option>, - }, - // This goes to somewhere that we don't know at compile-time - Unknown -} - -fn do_static_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, - fn_def_id: DefId, - fn_substs: &'tcx Substs<'tcx>) - -> StaticDispatchResult<'tcx> { - debug!("do_static_dispatch(fn_def_id={}, fn_substs={:?})", - def_id_to_string(scx.tcx(), fn_def_id), - fn_substs); - if let Some(trait_def_id) = scx.tcx().trait_of_item(fn_def_id) { - debug!(" => trait method, attempting to find impl"); - do_static_trait_method_dispatch(scx, - &scx.tcx().associated_item(fn_def_id), - trait_def_id, - fn_substs) - } else { - debug!(" => regular function"); - // The function is not part of an impl or trait, no dispatching - // to be done - StaticDispatchResult::Dispatched { - instance: Instance::new(fn_def_id, fn_substs), - fn_once_adjustment: None, - } - } -} - -// Given a trait-method and substitution information, find out the actual -// implementation of the trait method. -fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, - trait_method: &ty::AssociatedItem, - trait_id: DefId, - rcvr_substs: &'tcx Substs<'tcx>) - -> StaticDispatchResult<'tcx> { - let tcx = scx.tcx(); - debug!("do_static_trait_method_dispatch(trait_method={}, \ - trait_id={}, \ - rcvr_substs={:?})", - def_id_to_string(scx.tcx(), trait_method.def_id), - def_id_to_string(scx.tcx(), trait_id), - rcvr_substs); - - let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); - let vtbl = fulfill_obligation(scx, DUMMY_SP, ty::Binder(trait_ref)); - - // Now that we know which impl is being used, we can dispatch to - // the actual function: - match vtbl { - traits::VtableImpl(impl_data) => { - StaticDispatchResult::Dispatched { - instance: find_method(tcx, trait_method.name, rcvr_substs, &impl_data), - fn_once_adjustment: None, - } - } - traits::VtableClosure(closure_data) => { - let closure_def_id = closure_data.closure_def_id; - let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap(); - let actual_closure_kind = tcx.closure_kind(closure_def_id); - - let needs_fn_once_adapter_shim = - match needs_fn_once_adapter_shim(actual_closure_kind, - trait_closure_kind) { - Ok(true) => true, - _ => false, - }; - - let fn_once_adjustment = if needs_fn_once_adapter_shim { - Some(tcx.mk_closure_from_closure_substs(closure_def_id, - closure_data.substs)) - } else { - None - }; - - StaticDispatchResult::Dispatched { - instance: Instance::new(closure_def_id, closure_data.substs.substs), - fn_once_adjustment: fn_once_adjustment, - } - } - traits::VtableFnPointer(ref data) => { - StaticDispatchResult::Dispatched { - instance: Instance { - def: ty::InstanceDef::FnPtrShim(trait_method.def_id, data.fn_ty), - substs: trait_ref.substs - }, - fn_once_adjustment: None, - } - } - // Trait object shims are always instantiated in-place, and as they are - // just an ABI-adjusting indirect call they do not have any dependencies. - traits::VtableObject(..) => { - StaticDispatchResult::Unknown - } - _ => { - bug!("static call to invalid vtable: {:?}", vtbl) - } - } -} - /// For given pair of source and target type that occur in an unsizing coercion, /// this function finds the pair of types that determines the vtable linking /// them. @@ -991,7 +865,8 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, &ty::TyAdt(target_adt_def, target_substs)) => { assert_eq!(source_adt_def, target_adt_def); - let kind = custom_coerce_unsize_info(scx, source_ty, target_ty); + let kind = + monomorphize::custom_coerce_unsize_info(scx, source_ty, target_ty); let coerce_index = match kind { CustomCoerceUnsized::Struct(i) => i @@ -1017,6 +892,20 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, fn create_fn_trans_item<'a, 'tcx>(instance: Instance<'tcx>) -> TransItem<'tcx> { debug!("create_fn_trans_item(instance={})", instance); + let instance = match instance.def { + ty::InstanceDef::ClosureOnceShim { .. } => { + // HACK: don't create ClosureOnce trans items for now + // have someone else generate the drop glue + let closure_ty = instance.substs.type_at(0); + match closure_ty.sty { + ty::TyClosure(def_id, substs) => { + Instance::new(def_id, substs.substs) + } + _ => bug!("bad closure instance {:?}", instance) + } + } + _ => instance + }; TransItem::Fn(instance) } @@ -1037,18 +926,7 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a, // Walk all methods of the trait, including those of its supertraits let methods = traits::get_vtable_methods(scx.tcx(), poly_trait_ref); let methods = methods.filter_map(|method| method) - .filter_map(|(def_id, substs)| { - if let StaticDispatchResult::Dispatched { - instance, - // We already add the drop-glue for the closure env - // unconditionally below. - fn_once_adjustment: _ , - } = do_static_dispatch(scx, def_id, substs) { - Some(instance) - } else { - None - } - }) + .map(|(def_id, substs)| monomorphize::resolve(scx, def_id, substs)) .filter(|&instance| should_trans_locally(scx.tcx(), &instance)) .map(|instance| create_fn_trans_item(instance)); output.extend(methods); @@ -1203,18 +1081,11 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, ' continue; } - // The substitutions we have are on the impl, so we grab - // the method type from the impl to substitute into. - let impl_substs = tcx.empty_substs_for_def_id(impl_def_id); - let impl_data = traits::VtableImplData { - impl_def_id: impl_def_id, - substs: impl_substs, - nested: vec![] - }; - let instance = find_method(tcx, method.name, callee_substs, &impl_data); + let instance = + monomorphize::resolve(scx, method.def_id, callee_substs); let predicates = tcx.item_predicates(instance.def_id()).predicates - .subst(tcx, impl_substs); + .subst(tcx, instance.substs); if !traits::normalize_and_test_predicates(tcx, predicates) { continue; } diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 4389207cdf29..431325c5ec74 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -17,7 +17,6 @@ use llvm::{ValueRef, ContextRef, TypeKind}; use llvm::{True, False, Bool, OperandBundleDef}; use rustc::hir::def_id::DefId; use rustc::hir::map::DefPathData; -use rustc::util::common::MemoizationMap; use middle::lang_items::LangItem; use base; use builder::Builder; @@ -30,13 +29,11 @@ use value::Value; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::layout::Layout; use rustc::ty::subst::{Subst, Substs}; -use rustc::traits::{self, SelectionContext, Reveal}; use rustc::hir; use libc::{c_uint, c_char}; use std::iter; -use syntax::ast; use syntax::attr; use syntax::symbol::InternedString; use syntax_pos::Span; @@ -427,73 +424,6 @@ pub fn is_null(val: ValueRef) -> bool { } } -/// Attempts to resolve an obligation. The result is a shallow vtable resolution -- meaning that we -/// do not (necessarily) resolve all nested obligations on the impl. Note that type check should -/// guarantee to us that all nested obligations *could be* resolved if we wanted to. -pub fn fulfill_obligation<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, - span: Span, - trait_ref: ty::PolyTraitRef<'tcx>) - -> traits::Vtable<'tcx, ()> -{ - let tcx = scx.tcx(); - - // Remove any references to regions; this helps improve caching. - let trait_ref = tcx.erase_regions(&trait_ref); - - scx.trait_cache().memoize(trait_ref, || { - debug!("trans::fulfill_obligation(trait_ref={:?}, def_id={:?})", - trait_ref, trait_ref.def_id()); - - // Do the initial selection for the obligation. This yields the - // shallow result we are looking for -- that is, what specific impl. - tcx.infer_ctxt((), Reveal::All).enter(|infcx| { - let mut selcx = SelectionContext::new(&infcx); - - let obligation_cause = traits::ObligationCause::misc(span, - ast::DUMMY_NODE_ID); - let obligation = traits::Obligation::new(obligation_cause, - trait_ref.to_poly_trait_predicate()); - - let selection = match selcx.select(&obligation) { - Ok(Some(selection)) => selection, - Ok(None) => { - // Ambiguity can happen when monomorphizing during trans - // expands to some humongo type that never occurred - // statically -- this humongo type can then overflow, - // leading to an ambiguous result. So report this as an - // overflow bug, since I believe this is the only case - // where ambiguity can result. - debug!("Encountered ambiguity selecting `{:?}` during trans, \ - presuming due to overflow", - trait_ref); - tcx.sess.span_fatal(span, - "reached the recursion limit during monomorphization \ - (selection ambiguity)"); - } - Err(e) => { - span_bug!(span, "Encountered error `{:?}` selecting `{:?}` during trans", - e, trait_ref) - } - }; - - debug!("fulfill_obligation: selection={:?}", selection); - - // Currently, we use a fulfillment context to completely resolve - // all nested obligations. This is because they can inform the - // inference of the impl's type parameters. - let mut fulfill_cx = traits::FulfillmentContext::new(); - let vtable = selection.map(|predicate| { - debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate); - fulfill_cx.register_predicate_obligation(&infcx, predicate); - }); - let vtable = infcx.drain_fulfillment_cx_or_panic(span, &mut fulfill_cx, &vtable); - - info!("Cache miss: {:?} => {:?}", trait_ref, vtable); - vtable - }) - }) -} - pub fn langcall(tcx: TyCtxt, span: Option, msg: &str, @@ -617,6 +547,7 @@ pub fn requests_inline<'a, 'tcx>( _ => attr::requests_inline(&tcx.get_attrs(def_id)[..]), } } + /// Given a DefId and some Substs, produces the monomorphic item type. pub fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>, def_id: DefId, @@ -635,14 +566,3 @@ pub fn instance_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>, let ty = instance.def.def_ty(shared.tcx()); monomorphize::apply_param_substs(shared, instance.substs, &ty) } - -pub fn find_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - name: ast::Name, - substs: &'tcx Substs<'tcx>, - impl_data: &traits::VtableImplData<'tcx, ()>) - -> ty::Instance<'tcx> -{ - let (def_id, substs) = traits::find_method(tcx, name, substs, impl_data); - let substs = tcx.erase_regions(&substs); - ty::Instance::new(def_id, substs) -} diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 35ebd67b5f8c..2eb94aa56ab5 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -39,7 +39,6 @@ use value::Value; use Disr; use builder::Builder; -use syntax_pos::DUMMY_SP; use mir::lvalue::Alignment; pub fn trans_exchange_free_ty<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, ptr: LvalueRef<'tcx>) { @@ -241,8 +240,6 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi let shallow_drop = def.is_union(); let tcx = bcx.tcx(); - let def = t.ty_adt_def().unwrap(); - // Be sure to put the contents into a scope so we can use an invoke // instruction to call the user destructor but still call the field // destructors if the user destructor panics. @@ -256,17 +253,12 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi } else { CleanupScope::noop() }; - - let trait_ref = ty::Binder(ty::TraitRef { - def_id: tcx.lang_items.drop_trait().unwrap(), - substs: tcx.mk_substs_trait(t, &[]) - }); - let vtbl = match fulfill_obligation(bcx.ccx.shared(), DUMMY_SP, trait_ref) { - traits::VtableImpl(data) => data, - _ => bug!("dtor for {:?} is not an impl???", t) - }; - let dtor_did = def.destructor(tcx).unwrap().did; - let callee = Callee::def(bcx.ccx, dtor_did, vtbl.substs); + let drop_trait_def_id = tcx.lang_items.drop_trait().unwrap(); + let drop_method = tcx.associated_items(drop_trait_def_id) + .find(|it| it.kind == ty::AssociatedKind::Method) + .unwrap().def_id; + let self_type_substs = tcx.mk_substs_trait(t, &[]); + let callee = Callee::def(bcx.ccx, drop_method, self_type_substs); let fn_ty = callee.direct_fn_type(bcx.ccx, &[]); let llret; let args = &[ptr.llval, ptr.llextra][..1 + ptr.has_extra() as usize]; diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 1530fcda3d3e..49cc0b5fad40 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -28,6 +28,7 @@ #![feature(box_syntax)] #![feature(const_fn)] #![feature(custom_attribute)] +#![cfg_attr(stage0, feature(field_init_shorthand))] #![allow(unused_attributes)] #![feature(i128_type)] #![feature(libc)] diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index deb1073cf9ae..69009ab35604 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -249,7 +249,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { substs: &'tcx Substs<'tcx>, args: IndexVec>) -> Result, ConstEvalErr<'tcx>> { - let instance = monomorphize::resolve_const(ccx.shared(), def_id, substs); + let instance = monomorphize::resolve(ccx.shared(), def_id, substs); let mir = ccx.tcx().instance_mir(instance.def); MirConstContext::new(ccx, &mir, instance.substs, args).trans() } diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index 3b746af275a2..bf073d8b9784 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -8,38 +8,260 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use abi::Abi; use common::*; + use rustc::hir::def_id::DefId; use rustc::infer::TransNormalize; -use rustc::traits; +use rustc::traits::{self, SelectionContext, Reveal}; +use rustc::ty::adjustment::CustomCoerceUnsized; use rustc::ty::fold::{TypeFolder, TypeFoldable}; -use rustc::ty::subst::{Subst, Substs}; +use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::util::common::MemoizationMap; -use syntax::codemap::DUMMY_SP; +use syntax::ast; +use syntax::codemap::{Span, DUMMY_SP}; pub use rustc::ty::Instance; -/// For associated constants from traits, return the impl definition. -pub fn resolve_const<'a, 'tcx>( - scx: &SharedCrateContext<'a, 'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx> +fn fn_once_adapter_instance<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + closure_did: DefId, + substs: ty::ClosureSubsts<'tcx>, + ) -> Instance<'tcx> { + debug!("fn_once_adapter_shim({:?}, {:?})", + closure_did, + substs); + let fn_once = tcx.lang_items.fn_once_trait().unwrap(); + let call_once = tcx.associated_items(fn_once) + .find(|it| it.kind == ty::AssociatedKind::Method) + .unwrap().def_id; + let def = ty::InstanceDef::ClosureOnceShim { call_once, closure_did }; + + let self_ty = tcx.mk_closure_from_closure_substs( + closure_did, substs); + + let sig = tcx.closure_type(closure_did).subst(tcx, substs.substs); + let sig = tcx.erase_late_bound_regions_and_normalize(&sig); + assert_eq!(sig.inputs().len(), 1); + let substs = tcx.mk_substs([ + Kind::from(self_ty), + Kind::from(sig.inputs()[0]), + ].iter().cloned()); + + debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig); + Instance { def, substs } +} + +/// Attempts to resolve an obligation. The result is a shallow vtable resolution -- meaning that we +/// do not (necessarily) resolve all nested obligations on the impl. Note that type check should +/// guarantee to us that all nested obligations *could be* resolved if we wanted to. +fn fulfill_obligation<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, + span: Span, + trait_ref: ty::PolyTraitRef<'tcx>) + -> traits::Vtable<'tcx, ()> +{ + let tcx = scx.tcx(); + + // Remove any references to regions; this helps improve caching. + let trait_ref = tcx.erase_regions(&trait_ref); + + scx.trait_cache().memoize(trait_ref, || { + debug!("trans::fulfill_obligation(trait_ref={:?}, def_id={:?})", + trait_ref, trait_ref.def_id()); + + // Do the initial selection for the obligation. This yields the + // shallow result we are looking for -- that is, what specific impl. + tcx.infer_ctxt((), Reveal::All).enter(|infcx| { + let mut selcx = SelectionContext::new(&infcx); + + let obligation_cause = traits::ObligationCause::misc(span, + ast::DUMMY_NODE_ID); + let obligation = traits::Obligation::new(obligation_cause, + trait_ref.to_poly_trait_predicate()); + + let selection = match selcx.select(&obligation) { + Ok(Some(selection)) => selection, + Ok(None) => { + // Ambiguity can happen when monomorphizing during trans + // expands to some humongo type that never occurred + // statically -- this humongo type can then overflow, + // leading to an ambiguous result. So report this as an + // overflow bug, since I believe this is the only case + // where ambiguity can result. + debug!("Encountered ambiguity selecting `{:?}` during trans, \ + presuming due to overflow", + trait_ref); + tcx.sess.span_fatal(span, + "reached the recursion limit during monomorphization \ + (selection ambiguity)"); + } + Err(e) => { + span_bug!(span, "Encountered error `{:?}` selecting `{:?}` during trans", + e, trait_ref) + } + }; + + debug!("fulfill_obligation: selection={:?}", selection); + + // Currently, we use a fulfillment context to completely resolve + // all nested obligations. This is because they can inform the + // inference of the impl's type parameters. + let mut fulfill_cx = traits::FulfillmentContext::new(); + let vtable = selection.map(|predicate| { + debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate); + fulfill_cx.register_predicate_obligation(&infcx, predicate); + }); + let vtable = infcx.drain_fulfillment_cx_or_panic(span, &mut fulfill_cx, &vtable); + + info!("Cache miss: {:?} => {:?}", trait_ref, vtable); + vtable + }) + }) +} + +fn needs_fn_once_adapter_shim(actual_closure_kind: ty::ClosureKind, + trait_closure_kind: ty::ClosureKind) + -> Result +{ + match (actual_closure_kind, trait_closure_kind) { + (ty::ClosureKind::Fn, ty::ClosureKind::Fn) | + (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) | + (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => { + // No adapter needed. + Ok(false) + } + (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => { + // The closure fn `llfn` is a `fn(&self, ...)`. We want a + // `fn(&mut self, ...)`. In fact, at trans time, these are + // basically the same thing, so we can just return llfn. + Ok(false) + } + (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | + (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { + // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut + // self, ...)`. We want a `fn(self, ...)`. We can produce + // this by doing something like: + // + // fn call_once(self, ...) { call_mut(&self, ...) } + // fn call_once(mut self, ...) { call_mut(&mut self, ...) } + // + // These are both the same at trans time. + Ok(true) + } + _ => Err(()), + } +} + +fn resolve_associated_item<'a, 'tcx>( + scx: &SharedCrateContext<'a, 'tcx>, + trait_item: &ty::AssociatedItem, + trait_id: DefId, + rcvr_substs: &'tcx Substs<'tcx> ) -> Instance<'tcx> { - if let Some(trait_id) = scx.tcx().trait_of_item(def_id) { - let trait_ref = ty::TraitRef::new(trait_id, substs); - let trait_ref = ty::Binder(trait_ref); - let vtable = fulfill_obligation(scx, DUMMY_SP, trait_ref); - if let traits::VtableImpl(vtable_impl) = vtable { - let name = scx.tcx().item_name(def_id); - let ac = scx.tcx().associated_items(vtable_impl.impl_def_id) - .find(|item| item.kind == ty::AssociatedKind::Const && item.name == name); - if let Some(ac) = ac { - return Instance::new(ac.def_id, vtable_impl.substs); + let tcx = scx.tcx(); + let def_id = trait_item.def_id; + debug!("resolve_associated_item(trait_item={:?}, \ + trait_id={:?}, \ + rcvr_substs={:?})", + def_id, trait_id, rcvr_substs); + + let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); + let vtbl = fulfill_obligation(scx, DUMMY_SP, ty::Binder(trait_ref)); + + // Now that we know which impl is being used, we can dispatch to + // the actual function: + match vtbl { + traits::VtableImpl(impl_data) => { + let (def_id, substs) = traits::find_associated_item( + tcx, trait_item, rcvr_substs, &impl_data); + let substs = tcx.erase_regions(&substs); + ty::Instance::new(def_id, substs) + } + traits::VtableClosure(closure_data) => { + let closure_def_id = closure_data.closure_def_id; + let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap(); + let actual_closure_kind = tcx.closure_kind(closure_def_id); + + match needs_fn_once_adapter_shim(actual_closure_kind, + trait_closure_kind) { + Ok(true) => fn_once_adapter_instance( + tcx, closure_def_id, closure_data.substs), + _ => Instance::new(closure_def_id, closure_data.substs.substs), } } + traits::VtableFnPointer(ref data) => { + Instance { + def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty), + substs: rcvr_substs + } + } + traits::VtableObject(ref data) => { + let index = tcx.get_vtable_index_of_object_method(data, def_id); + Instance { + def: ty::InstanceDef::Virtual(def_id, index), + substs: rcvr_substs + } + } + _ => { + bug!("static call to invalid vtable: {:?}", vtbl) + } } +} - Instance::new(def_id, substs) +/// The point where linking happens. Resolve a (def_id, substs) +/// pair to an instance. +pub fn resolve<'a, 'tcx>( + scx: &SharedCrateContext<'a, 'tcx>, + def_id: DefId, + substs: &'tcx Substs<'tcx> +) -> Instance<'tcx> { + debug!("resolve(def_id={:?}, substs={:?})", + def_id, substs); + let result = if let Some(trait_def_id) = scx.tcx().trait_of_item(def_id) { + debug!(" => associated item, attempting to find impl"); + let item = scx.tcx().associated_item(def_id); + resolve_associated_item(scx, &item, trait_def_id, substs) + } else { + let item_type = def_ty(scx, def_id, substs); + let def = match item_type.sty { + ty::TyFnDef(_, _, f) if + f.abi() == Abi::RustIntrinsic || + f.abi() == Abi::PlatformIntrinsic => + { + debug!(" => intrinsic"); + ty::InstanceDef::Intrinsic(def_id) + } + _ => { + debug!(" => free item"); + ty::InstanceDef::Item(def_id) + } + }; + Instance { def, substs } + }; + debug!("resolve(def_id={:?}, substs={:?}) = {}", + def_id, substs, result); + result +} + +pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx>, + source_ty: Ty<'tcx>, + target_ty: Ty<'tcx>) + -> CustomCoerceUnsized { + let trait_ref = ty::Binder(ty::TraitRef { + def_id: scx.tcx().lang_items.coerce_unsized_trait().unwrap(), + substs: scx.tcx().mk_substs_trait(source_ty, &[target_ty]) + }); + + match fulfill_obligation(scx, DUMMY_SP, trait_ref) { + traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => { + scx.tcx().custom_coerce_unsized_kind(impl_def_id) + } + vtable => { + bug!("invalid CoerceUnsized vtable: {:?}", vtable); + } + } } /// Monomorphizes a type from the AST by first applying the in-scope diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 1232c6cd28e5..d0cf32508d44 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -458,7 +458,10 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 't TransItem::Fn(instance) => { let def_id = match instance.def { ty::InstanceDef::Item(def_id) => def_id, - ty::InstanceDef::FnPtrShim(..) => return None + ty::InstanceDef::FnPtrShim(..) | + ty::InstanceDef::ClosureOnceShim { .. } | + ty::InstanceDef::Intrinsic(..) | + ty::InstanceDef::Virtual(..) => return None }; // If this is a method, we want to put it into the same module as