]> git.lizzy.rs Git - rust.git/commitdiff
rustc_trans: simplify vtable and symbol handling.
authorEduard Burtescu <edy.burt@gmail.com>
Mon, 19 Sep 2016 09:47:47 +0000 (12:47 +0300)
committerEduard Burtescu <edy.burt@gmail.com>
Tue, 20 Sep 2016 17:30:52 +0000 (20:30 +0300)
src/librustc/traits/mod.rs
src/librustc/traits/specialize/mod.rs
src/librustc_trans/back/symbol_names.rs
src/librustc_trans/callee.rs
src/librustc_trans/closure.rs
src/librustc_trans/collector.rs
src/librustc_trans/common.rs
src/librustc_trans/meth.rs

index a96cf1111e1d3fbe8ab0ea4fb82a81d20632e2f4..7ba10d9c0a58e1140d35de18d2148993014a5191 100644 (file)
@@ -40,7 +40,7 @@
 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;
@@ -527,6 +527,88 @@ pub fn fully_normalize<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
     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)
index 2f63526bf6c270d493b32329d3c3827e1c9a644d..e37425901c8c8f2dd74ae0d89cc9ce127692f9e3 100644 (file)
 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.
@@ -103,6 +105,41 @@ pub fn translate_substs<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
     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;
index 500e9edebf3fe7fa976d4a9cd2e70cae2cb92056..0a668db06908090b8a7689380bdf37ffc5da243b 100644 (file)
@@ -97,7 +97,7 @@
 //! 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};
 
@@ -152,16 +152,17 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
     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);
 
@@ -172,18 +173,15 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
             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);
@@ -278,7 +276,7 @@ pub fn symbol_name(self, scx: &SharedCrateContext<'a, 'tcx>) -> String {
             scx.tcx().push_item_path(&mut buffer, def_id);
         });
 
-        mangle(buffer.names.into_iter(), Some(&hash[..]))
+        mangle(buffer.names.into_iter(), &hash)
     }
 }
 
@@ -307,23 +305,7 @@ pub fn exported_name_from_type_and_prefix<'a, 'tcx>(scx: &SharedCrateContext<'a,
     };
     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
@@ -376,7 +358,7 @@ pub fn sanitize(s: &str) -> String {
     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.
     //
@@ -403,9 +385,7 @@ fn push(n: &mut String, s: &str) {
         push(&mut n, &data);
     }
 
-    if let Some(s) = hash {
-        push(&mut n, s)
-    }
+    push(&mut n, hash);
 
     n.push('E'); // End name-sequence.
     n
index 9785ee24557938877b4dfc03c23e865ab7aa1eb7..8822287a0e754a6e66a8e53edb33aa1ee37dd61c 100644 (file)
@@ -17,7 +17,6 @@
 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;
@@ -133,26 +132,25 @@ pub fn trait_method<'a>(ccx: &CrateContext<'a, 'tcx>,
         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);
@@ -160,7 +158,10 @@ pub fn trait_method<'a>(ccx: &CrateContext<'a, 'tcx>,
             }
             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)
@@ -217,9 +218,7 @@ pub fn call<'a, 'blk>(self, bcx: Block<'blk, 'tcx>,
     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);
@@ -264,8 +263,9 @@ fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>,
 /// ```
 ///
 /// 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
@@ -345,10 +345,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
     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);
     //
index 83882c27e8e7b6191ea2b77117a825fbfa9a771c..c0692e8085fc25ddb0b44b6a870f4b0e6ec9d430 100644 (file)
@@ -9,7 +9,6 @@
 // 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};
@@ -152,6 +151,7 @@ pub fn trans_closure_body_via_mir<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 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
 {
@@ -199,7 +199,7 @@ pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
             //     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 {:?}",
@@ -213,6 +213,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
     ccx: &'a CrateContext<'a, 'tcx>,
     closure_def_id: DefId,
     substs: ty::ClosureSubsts<'tcx>,
+    method_instance: Instance<'tcx>,
     llreffn: ValueRef)
     -> ValueRef
 {
@@ -255,8 +256,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
     }));
 
     // 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);
 
index b9449eeecf427f260c649187d796eb98f8d5cd0e..2849b384e1bd211fccd4b52344083f9bb8ea5c85 100644 (file)
 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};
 
@@ -899,17 +898,8 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
     // 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
@@ -1043,43 +1033,19 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a,
 
     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)));
     }
 }
 
@@ -1239,25 +1205,27 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, '
                     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);
                     }
                 }
index e0de04d150ca7446adba00b9ab1b5fafe4851a3d..db1a541919036087616d1329873093d873d1f2f4 100644 (file)
@@ -150,15 +150,6 @@ pub fn type_is_zero_size<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -
     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".
 *
@@ -1002,35 +993,6 @@ pub fn fulfill_obligation<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
     })
 }
 
-/// 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,
index 8540c7a99db15a466c9102091fb3a15d6ac0a94a..e8dcaf71f2dd2fc9d053ca6934aa9b6fc9dcee5b 100644 (file)
@@ -8,33 +8,25 @@
 // 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;
@@ -73,23 +65,26 @@ pub fn get_virtual_method<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 /// 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);
@@ -98,16 +93,7 @@ pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
     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;
 
@@ -140,72 +126,23 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     }
 
     // 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));
@@ -214,122 +151,3 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     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)
-        }
-    }
-}