mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-03 04:04:06 +00:00
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:
commit
b4a2579cf0
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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>,
|
||||
|
@ -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 =
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user