about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-01-22 07:55:13 +0000
committerbors <bors@rust-lang.org>2016-01-22 07:55:13 +0000
commitb4a2579cf0b9876e8cdf99e4f58b4154a671f48e (patch)
tree49aa1025657e9ba6ac05654efe9e6845274c41bb
parent00ee90f0f091916c3a4d42c48ccd71186186ffae (diff)
parent0a01d0b7323a690f3b084ea5ce3c5ec4d5e0b3a3 (diff)
downloadrust-b4a2579cf0b9876e8cdf99e4f58b4154a671f48e.tar.gz
rust-b4a2579cf0b9876e8cdf99e4f58b4154a671f48e.zip
Auto merge of #31072 - arielb1:method-callee-cleanup, r=michaelwoerister
The old code was terribly ugly and was duplicated in several places.

r? @michaelwoerister
-rw-r--r--src/librustc/middle/const_eval.rs19
-rw-r--r--src/librustc/middle/subst.rs41
-rw-r--r--src/librustc/middle/ty/util.rs1
-rw-r--r--src/librustc_lint/builtin.rs4
-rw-r--r--src/librustc_trans/trans/common.rs18
-rw-r--r--src/librustc_trans/trans/meth.rs129
-rw-r--r--src/librustc_trans/trans/mir/did.rs49
-rw-r--r--src/librustc_typeck/check/method/confirm.rs2
8 files changed, 76 insertions, 187 deletions
diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs
index 942f2d6efb1..ef011067cd0 100644
--- a/src/librustc/middle/const_eval.rs
+++ b/src/librustc/middle/const_eval.rs
@@ -1233,20 +1233,11 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
                                                 rcvr_substs: subst::Substs<'tcx>)
                                                 -> Option<&'tcx Expr>
 {
-    let subst::SeparateVecsPerParamSpace {
-        types: rcvr_type,
-        selfs: rcvr_self,
-        fns: _,
-    } = rcvr_substs.types.split();
-    let trait_substs =
-        subst::Substs::erased(subst::VecPerParamSpace::new(rcvr_type,
-                                                           rcvr_self,
-                                                           Vec::new()));
-    let trait_substs = tcx.mk_substs(trait_substs);
-    debug!("resolve_trait_associated_const: trait_substs={:?}",
-           trait_substs);
-    let trait_ref = ty::Binder(ty::TraitRef { def_id: trait_id,
-                                              substs: trait_substs });
+    let trait_ref = ty::Binder(
+        rcvr_substs.erase_regions().to_trait_ref(tcx, trait_id)
+    );
+    debug!("resolve_trait_associated_const: trait_ref={:?}",
+           trait_ref);
 
     tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id());
     let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None);
diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs
index 61f7b2db4c4..ddc817ffc02 100644
--- a/src/librustc/middle/subst.rs
+++ b/src/librustc/middle/subst.rs
@@ -14,6 +14,7 @@ pub use self::ParamSpace::*;
 pub use self::RegionSubsts::*;
 
 use middle::cstore;
+use middle::def_id::DefId;
 use middle::ty::{self, Ty};
 use middle::ty::fold::{TypeFoldable, TypeFolder};
 
@@ -142,16 +143,34 @@ impl<'tcx> Substs<'tcx> {
                        -> Substs<'tcx>
     {
         let Substs { types, regions } = self;
-        let types = types.with_vec(FnSpace, m_types);
-        let regions = regions.map(|r| r.with_vec(FnSpace, m_regions));
+        let types = types.with_slice(FnSpace, &m_types);
+        let regions = regions.map(|r| r.with_slice(FnSpace, &m_regions));
         Substs { types: types, regions: regions }
     }
 
-    pub fn method_to_trait(self) -> Substs<'tcx> {
-        let Substs { mut types, regions } = self;
+    pub fn with_method_from(self,
+                            meth_substs: &Substs<'tcx>)
+                            -> Substs<'tcx>
+    {
+        let Substs { types, regions } = self;
+        let types = types.with_slice(FnSpace, meth_substs.types.get_slice(FnSpace));
+        let regions = regions.map(|r| {
+            r.with_slice(FnSpace, meth_substs.regions().get_slice(FnSpace))
+        });
+        Substs { types: types, regions: regions }
+    }
+
+    /// Creates a trait-ref out of this substs, ignoring the FnSpace substs
+    pub fn to_trait_ref(&self, tcx: &ty::ctxt<'tcx>, trait_id: DefId)
+                        -> ty::TraitRef<'tcx> {
+        let Substs { mut types, regions } = self.clone();
         types.truncate(FnSpace, 0);
         let regions = regions.map(|mut r| { r.truncate(FnSpace, 0); r });
-        Substs { types: types, regions: regions }
+
+        ty::TraitRef {
+            def_id: trait_id,
+            substs: tcx.mk_substs(Substs { types: types, regions: regions })
+        }
     }
 }
 
@@ -290,10 +309,6 @@ impl<T> VecPerParamSpace<T> {
         }
     }
 
-    pub fn params_from_type(types: Vec<T>) -> VecPerParamSpace<T> {
-        VecPerParamSpace::empty().with_vec(TypeSpace, types)
-    }
-
     /// `t` is the type space.
     /// `s` is the self space.
     /// `f` is the fn space.
@@ -483,11 +498,15 @@ impl<T> VecPerParamSpace<T> {
         }
     }
 
-    pub fn with_vec(mut self, space: ParamSpace, vec: Vec<T>)
+    pub fn with_slice(mut self, space: ParamSpace, slice: &[T])
                     -> VecPerParamSpace<T>
+        where T: Clone
     {
         assert!(self.is_empty_in(space));
-        self.replace(space, vec);
+        for t in slice {
+            self.push(space, t.clone());
+        }
+
         self
     }
 }
diff --git a/src/librustc/middle/ty/util.rs b/src/librustc/middle/ty/util.rs
index 03145951367..8cfd27843ae 100644
--- a/src/librustc/middle/ty/util.rs
+++ b/src/librustc/middle/ty/util.rs
@@ -604,7 +604,6 @@ pub struct ImplMethod<'tcx> {
 }
 
 impl<'tcx> ty::ctxt<'tcx> {
-    #[inline(never)] // is this perfy enough?
     pub fn get_impl_method(&self,
                            impl_def_id: DefId,
                            substs: Substs<'tcx>,
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 8621743668b..9e3ca70e5e4 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -855,9 +855,7 @@ impl LateLintPass for UnconditionalRecursion {
                 // A trait method, from any number of possible sources.
                 // Attempt to select a concrete impl before checking.
                 ty::TraitContainer(trait_def_id) => {
-                    let trait_substs = callee_substs.clone().method_to_trait();
-                    let trait_substs = tcx.mk_substs(trait_substs);
-                    let trait_ref = ty::TraitRef::new(trait_def_id, trait_substs);
+                    let trait_ref = callee_substs.to_trait_ref(tcx, trait_def_id);
                     let trait_ref = ty::Binder(trait_ref);
                     let span = tcx.map.span(expr_id);
                     let obligation =
diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs
index 6c03916af6c..ed47e529d49 100644
--- a/src/librustc_trans/trans/common.rs
+++ b/src/librustc_trans/trans/common.rs
@@ -1049,9 +1049,9 @@ pub enum ExprOrMethodCall {
 }
 
 pub fn node_id_substs<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                            node: ExprOrMethodCall,
-                            param_substs: &subst::Substs<'tcx>)
-                            -> subst::Substs<'tcx> {
+                                node: ExprOrMethodCall,
+                                param_substs: &subst::Substs<'tcx>)
+                                -> subst::Substs<'tcx> {
     let tcx = ccx.tcx();
 
     let substs = match node {
@@ -1064,13 +1064,13 @@ pub fn node_id_substs<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     };
 
     if substs.types.needs_infer() {
-            tcx.sess.bug(&format!("type parameters for node {:?} include inference types: {:?}",
-                                 node, substs));
-        }
+        tcx.sess.bug(&format!("type parameters for node {:?} include inference types: {:?}",
+                              node, substs));
+    }
 
-        monomorphize::apply_param_substs(tcx,
-                                         param_substs,
-                                         &substs.erase_regions())
+    monomorphize::apply_param_substs(tcx,
+                                     param_substs,
+                                     &substs.erase_regions())
 }
 
 pub fn langcall(bcx: Block,
diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs
index bd12dd8c3ef..4695595d16f 100644
--- a/src/librustc_trans/trans/meth.rs
+++ b/src/librustc_trans/trans/meth.rs
@@ -14,7 +14,6 @@ use llvm::{ValueRef, get_params};
 use middle::def_id::DefId;
 use middle::infer;
 use middle::subst::{Subst, Substs};
-use middle::subst::VecPerParamSpace;
 use middle::subst;
 use middle::traits;
 use trans::base::*;
@@ -34,7 +33,7 @@ use trans::machine;
 use trans::monomorphize;
 use trans::type_::Type;
 use trans::type_of::*;
-use middle::ty::{self, Ty, TypeFoldable};
+use middle::ty::{self, Ty};
 use middle::ty::MethodCall;
 
 use syntax::ast;
@@ -117,10 +116,7 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         }
 
         ty::TraitContainer(trait_def_id) => {
-            let trait_substs = method.substs.clone().method_to_trait();
-            let trait_substs = bcx.tcx().mk_substs(trait_substs);
-            let trait_ref = ty::TraitRef::new(trait_def_id, trait_substs);
-
+            let trait_ref = method.substs.to_trait_ref(bcx.tcx(), trait_def_id);
             let trait_ref = ty::Binder(bcx.monomorphize(&trait_ref));
             let span = bcx.tcx().map.span(method_call.expr_id);
             debug!("method_call={:?} trait_ref={:?} trait_ref id={:?} substs={:?}",
@@ -128,9 +124,7 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                    trait_ref,
                    trait_ref.0.def_id,
                    trait_ref.0.substs);
-            let origin = fulfill_obligation(bcx.ccx(),
-                                            span,
-                                            trait_ref.clone());
+            let origin = fulfill_obligation(bcx.ccx(), span, trait_ref);
             debug!("origin = {:?}", origin);
             trans_monomorphized_callee(bcx,
                                        method_call,
@@ -169,44 +163,9 @@ pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     // type parameters that belong to the trait but also some that
     // belong to the method:
     let rcvr_substs = node_id_substs(ccx, ExprId(expr_id), param_substs);
-    let subst::SeparateVecsPerParamSpace {
-        types: rcvr_type,
-        selfs: rcvr_self,
-        fns: rcvr_method
-    } = rcvr_substs.types.split();
-
-    // Lookup the precise impl being called. To do that, we need to
-    // create a trait reference identifying the self type and other
-    // input type parameters. To create that trait reference, we have
-    // to pick apart the type parameters to identify just those that
-    // pertain to the trait. This is easiest to explain by example:
-    //
-    //     trait Convert {
-    //         fn from<U:Foo>(n: U) -> Option<Self>;
-    //     }
-    //     ...
-    //     let f = <Vec<i32> as Convert>::from::<String>(...)
-    //
-    // Here, in this call, which I've written with explicit UFCS
-    // notation, the set of type parameters will be:
-    //
-    //     rcvr_type: [] <-- nothing declared on the trait itself
-    //     rcvr_self: [Vec<i32>] <-- the self type
-    //     rcvr_method: [String] <-- method type parameter
-    //
-    // So we create a trait reference using the first two,
-    // basically corresponding to `<Vec<i32> as Convert>`.
-    // The remaining type parameters (`rcvr_method`) will be used below.
-    let trait_substs =
-        Substs::erased(VecPerParamSpace::new(rcvr_type,
-                                             rcvr_self,
-                                             Vec::new()));
-    let trait_substs = tcx.mk_substs(trait_substs);
-    debug!("trait_substs={:?}", trait_substs);
-    let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, trait_substs));
-    let vtbl = fulfill_obligation(ccx,
-                                  DUMMY_SP,
-                                  trait_ref);
+    debug!("rcvr_substs={:?}", rcvr_substs);
+    let trait_ref = ty::Binder(rcvr_substs.to_trait_ref(tcx, trait_id));
+    let vtbl = fulfill_obligation(ccx, DUMMY_SP, trait_ref);
 
     // Now that we know which impl is being used, we can dispatch to
     // the actual function:
@@ -216,33 +175,7 @@ pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             substs: impl_substs,
             nested: _ }) =>
         {
-            assert!(!impl_substs.types.needs_infer());
-
-            // Create the substitutions that are in scope. This combines
-            // the type parameters from the impl with those declared earlier.
-            // To see what I mean, consider a possible impl:
-            //
-            //    impl<T> Convert for Vec<T> {
-            //        fn from<U:Foo>(n: U) { ... }
-            //    }
-            //
-            // Recall that we matched `<Vec<i32> as Convert>`. Trait
-            // resolution will have given us a substitution
-            // containing `impl_substs=[[T=i32],[],[]]` (the type
-            // parameters defined on the impl). We combine
-            // that with the `rcvr_method` from before, which tells us
-            // the type parameters from the *method*, to yield
-            // `callee_substs=[[T=i32],[],[U=String]]`.
-            let subst::SeparateVecsPerParamSpace {
-                types: impl_type,
-                selfs: impl_self,
-                fns: _
-            } = impl_substs.types.split();
-            let callee_substs =
-                Substs::erased(VecPerParamSpace::new(impl_type,
-                                                     impl_self,
-                                                     rcvr_method));
-
+            let callee_substs = impl_substs.with_method_from(&rcvr_substs);
             let mth = tcx.get_impl_method(impl_did, callee_substs, mname);
             trans_fn_ref_with_substs(ccx, mth.method.def_id, ExprId(expr_id),
                                      param_substs,
@@ -256,6 +189,7 @@ pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                               idx)
         }
         _ => {
+            // FIXME(#20847): handle at least VtableFnPointer
             tcx.sess.bug(&format!("static call to invalid vtable: {:?}",
                                  vtbl));
         }
@@ -285,11 +219,11 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             };
             // create a concatenated set of substitutions which includes
             // those from the impl and those from the method:
-            let callee_substs =
-                combine_impl_and_methods_tps(
-                    bcx, MethodCallKey(method_call), vtable_impl.substs);
-
-            let mth = bcx.tcx().get_impl_method(impl_did, callee_substs, mname);
+            let meth_substs = node_id_substs(ccx,
+                                             MethodCallKey(method_call),
+                                             bcx.fcx.param_substs);
+            let impl_substs = vtable_impl.substs.with_method_from(&meth_substs);
+            let mth = bcx.tcx().get_impl_method(impl_did, impl_substs, mname);
             // translate the function
             let datum = trans_fn_ref_with_substs(bcx.ccx(),
                                                  mth.method.def_id,
@@ -346,43 +280,6 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     }
 }
 
- /// Creates a concatenated set of substitutions which includes those from the impl and those from
- /// the method.  This are some subtle complications here.  Statically, we have a list of type
- /// parameters like `[T0, T1, T2, M1, M2, M3]` where `Tn` are type parameters that appear on the
- /// receiver.  For example, if the receiver is a method parameter `A` with a bound like
- /// `trait<B,C,D>` then `Tn` would be `[B,C,D]`.
- ///
- /// The weird part is that the type `A` might now be bound to any other type, such as `foo<X>`.
- /// In that case, the vector we want is: `[X, M1, M2, M3]`.  Therefore, what we do now is to slice
- /// off the method type parameters and append them to the type parameters from the type that the
- /// receiver is mapped to.
-fn combine_impl_and_methods_tps<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                                            node: ExprOrMethodCall,
-                                            rcvr_substs: subst::Substs<'tcx>)
-                                            -> subst::Substs<'tcx>
-{
-    let ccx = bcx.ccx();
-
-    let node_substs = node_id_substs(ccx, node, bcx.fcx.param_substs);
-
-    debug!("rcvr_substs={:?}", rcvr_substs);
-    debug!("node_substs={:?}", node_substs);
-
-    // Break apart the type parameters from the node and type
-    // parameters from the receiver.
-    let node_method = node_substs.types.split().fns;
-    let subst::SeparateVecsPerParamSpace {
-        types: rcvr_type,
-        selfs: rcvr_self,
-        fns: rcvr_method
-    } = rcvr_substs.types.clone().split();
-    assert!(rcvr_method.is_empty());
-    subst::Substs {
-        regions: subst::ErasedRegions,
-        types: subst::VecPerParamSpace::new(rcvr_type, rcvr_self, node_method)
-    }
-}
-
 /// Create a method callee where the method is coming from a trait object (e.g., Box<Trait> type).
 /// In this case, we must pull the fn pointer out of the vtable that is packaged up with the
 /// object. Objects are represented as a pair, so we first evaluate the self expression and then
diff --git a/src/librustc_trans/trans/mir/did.rs b/src/librustc_trans/trans/mir/did.rs
index 3238869cac5..e433776bef2 100644
--- a/src/librustc_trans/trans/mir/did.rs
+++ b/src/librustc_trans/trans/mir/did.rs
@@ -16,7 +16,6 @@ use rustc::middle::ty::{self, Ty, TypeFoldable};
 use rustc::middle::subst::Substs;
 use rustc::middle::const_eval;
 use rustc::middle::def_id::DefId;
-use rustc::middle::subst;
 use rustc::middle::traits;
 use rustc::mir::repr::ItemKind;
 use trans::common::{Block, fulfill_obligation};
@@ -46,7 +45,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
             ItemKind::Function => self.trans_fn_ref(bcx, ty, substs, did),
             ItemKind::Method => match bcx.tcx().impl_or_trait_item(did).container() {
                 ty::ImplContainer(_) => self.trans_fn_ref(bcx, ty, substs, did),
-                ty::TraitContainer(tdid) => self.trans_static_method(bcx, ty, did, tdid, substs)
+                ty::TraitContainer(tdid) => self.trans_trait_method(bcx, ty, did, tdid, substs)
             },
             ItemKind::Constant => {
                 let did = inline::maybe_instantiate_inline(bcx.ccx(), did);
@@ -98,16 +97,16 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
         }
     }
 
-    /// Translates references to static methods.
+    /// Translates references to trait methods.
     ///
     /// This is an adaptation of meth::trans_static_method_callee
-    pub fn trans_static_method(&mut self,
-                               bcx: Block<'bcx, 'tcx>,
-                               ty: Ty<'tcx>,
-                               method_id: DefId,
-                               trait_id: DefId,
-                               substs: &'tcx Substs<'tcx>)
-                               -> OperandRef<'tcx> {
+    pub fn trans_trait_method(&mut self,
+                              bcx: Block<'bcx, 'tcx>,
+                              ty: Ty<'tcx>,
+                              method_id: DefId,
+                              trait_id: DefId,
+                              substs: &'tcx Substs<'tcx>)
+                              -> OperandRef<'tcx> {
         debug!("trans_static_method(ty={:?}, method={}, trait={}, substs={:?})",
                 ty,
                 bcx.tcx().item_path_str(method_id),
@@ -116,34 +115,20 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
 
         let ccx = bcx.ccx();
         let tcx = bcx.tcx();
-        let subst::SeparateVecsPerParamSpace {
-            types: rcvr_type,
-            selfs: rcvr_self,
-            fns: rcvr_method
-        } = substs.clone().types.split();
-        let trait_substs = Substs::erased(
-            subst::VecPerParamSpace::new(rcvr_type, rcvr_self, Vec::new())
-        );
-        let trait_substs = tcx.mk_substs(trait_substs);
-        let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, trait_substs));
+        let trait_ref = ty::Binder(substs.to_trait_ref(tcx, trait_id));
         let vtbl = fulfill_obligation(ccx, DUMMY_SP, trait_ref);
         match vtbl {
-            traits::VtableImpl(traits::VtableImplData { impl_def_id, substs: imp_substs, .. }) => {
-                assert!(!imp_substs.types.needs_infer());
+            traits::VtableImpl(traits::VtableImplData {
+                impl_def_id, substs: impl_substs, ..
+            }) => {
+                assert!(!impl_substs.types.needs_infer());
 
                 let mname = tcx.item_name(method_id);
 
-                let subst::SeparateVecsPerParamSpace {
-                    types: impl_type,
-                    selfs: impl_self,
-                    fns: _
-                } = imp_substs.types.split();
-                let callee_substs = Substs::erased(
-                    subst::VecPerParamSpace::new(impl_type, impl_self, rcvr_method)
-                );
+                let callee_substs = impl_substs.with_method_from(substs);
                 let mth = tcx.get_impl_method(impl_def_id, callee_substs, mname);
-                let mthsubsts = tcx.mk_substs(mth.substs);
-                self.trans_fn_ref(bcx, ty, mthsubsts, mth.method.def_id)
+                let mth_substs = tcx.mk_substs(mth.substs);
+                self.trans_fn_ref(bcx, ty, mth_substs, mth.method.def_id)
             },
             traits::VtableClosure(data) => {
                 let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index b2462a3612c..1d8f6f005cd 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -332,7 +332,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                     .generics.regions.get_slice(subst::FnSpace));
 
         let subst::Substs { types, regions } = substs;
-        let regions = regions.map(|r| r.with_vec(subst::FnSpace, method_regions));
+        let regions = regions.map(|r| r.with_slice(subst::FnSpace, &method_regions));
         let mut final_substs = subst::Substs { types: types, regions: regions };
 
         if num_supplied_types == 0 {