Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

clean up trans_static_method_callee and friends #31072

Merged
merged 2 commits into from
Jan 22, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we take care to erase regions here?

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(#20847): handle at least VtableFnPointer
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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above: Before combine_impl_and_methods_tps would make sure we'd get something with erased regions, now we can't rely on it unless we know that the Substs in the vtable are already region-erased.

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