Skip to content

Commit

Permalink
clean up trans_static_method_callee and friends
Browse files Browse the repository at this point in the history
  • Loading branch information
Ariel Ben-Yehuda committed Jan 21, 2016
1 parent 34b4e66 commit 29c296f
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 187 deletions.
19 changes: 5 additions & 14 deletions src/librustc/middle/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
41 changes: 30 additions & 11 deletions src/librustc/middle/subst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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 })
}
}
}

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
}
}
Expand Down
1 change: 0 additions & 1 deletion src/librustc/middle/ty/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand Down
4 changes: 1 addition & 3 deletions src/librustc_lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
18 changes: 9 additions & 9 deletions src/librustc_trans/trans/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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,
Expand Down
129 changes: 13 additions & 116 deletions src/librustc_trans/trans/meth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
Expand All @@ -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;
Expand Down Expand Up @@ -117,20 +116,15 @@ 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={:?}",
method_call,
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,
Expand Down Expand Up @@ -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:
Expand All @@ -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,
Expand All @@ -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));
}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit 29c296f

Please sign in to comment.