From 29c296f90bca9e042b0e8c6aabaa76d0586ca13a Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 21 Jan 2016 14:26:35 +0200 Subject: [PATCH 1/2] clean up trans_static_method_callee and friends --- src/librustc/middle/const_eval.rs | 19 +-- src/librustc/middle/subst.rs | 41 +++++-- src/librustc/middle/ty/util.rs | 1 - src/librustc_lint/builtin.rs | 4 +- src/librustc_trans/trans/common.rs | 18 +-- src/librustc_trans/trans/meth.rs | 129 ++------------------ src/librustc_trans/trans/mir/did.rs | 49 +++----- src/librustc_typeck/check/method/confirm.rs | 2 +- 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 VecPerParamSpace { } } - pub fn params_from_type(types: Vec) -> VecPerParamSpace { - 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 VecPerParamSpace { } } - pub fn with_vec(mut self, space: ParamSpace, vec: Vec) + pub fn with_slice(mut self, space: ParamSpace, slice: &[T]) -> VecPerParamSpace + 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..45ac3f5c512 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(n: U) -> Option; - // } - // ... - // let f = as Convert>::from::(...) - // - // 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] <-- the self type - // rcvr_method: [String] <-- method type parameter - // - // So we create a trait reference using the first two, - // basically corresponding to ` 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 Convert for Vec { - // fn from(n: U) { ... } - // } - // - // Recall that we matched ` 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 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` 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`. - /// 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 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 { From 0a01d0b7323a690f3b084ea5ce3c5ec4d5e0b3a3 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 21 Jan 2016 22:07:15 +0200 Subject: [PATCH 2/2] add fixme --- src/librustc_trans/trans/meth.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index 45ac3f5c512..4695595d16f 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -189,7 +189,7 @@ pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, idx) } _ => { - // FIXME + // FIXME(#20847): handle at least VtableFnPointer tcx.sess.bug(&format!("static call to invalid vtable: {:?}", vtbl)); }