Auto merge of #31072 - arielb1:method-callee-cleanup, r=michaelwoerister

The old code was terribly ugly and was duplicated in several places.

r? @michaelwoerister
This commit is contained in:
bors 2016-01-22 07:55:13 +00:00
commit b4a2579cf0
8 changed files with 76 additions and 187 deletions

View File

@ -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);

View File

@ -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
}
}

View File

@ -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>,

View File

@ -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 =

View File

@ -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

View File

@ -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,10 +97,10 @@ 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,
pub fn trans_trait_method(&mut self,
bcx: Block<'bcx, 'tcx>,
ty: Ty<'tcx>,
method_id: DefId,
@ -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();

View File

@ -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 {