Improve handling of trait bounds on a trait in default methods.
This is work on #7460. It does not properly handle certain cross crate situations, because we don't properly export vtable resolution information.
This commit is contained in:
parent
649b26f7c6
commit
0252693db2
@ -195,6 +195,58 @@ pub fn trans_fn_ref_with_vtables_to_callee(
|
||||
type_params, vtables))}
|
||||
}
|
||||
|
||||
fn get_impl_resolutions(bcx: block,
|
||||
impl_id: ast::def_id)
|
||||
-> typeck::vtable_res {
|
||||
if impl_id.crate == ast::local_crate {
|
||||
*bcx.ccx().maps.vtable_map.get(&impl_id.node)
|
||||
} else {
|
||||
// XXX: This is a temporary hack to work around not properly
|
||||
// exporting information about resolutions for impls.
|
||||
// This doesn't actually work if the trait has param bounds,
|
||||
// but it does allow us to survive the case when it does not.
|
||||
let trait_ref = ty::impl_trait_ref(bcx.tcx(), impl_id).get();
|
||||
@vec::from_elem(trait_ref.substs.tps.len(), @~[])
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_default_method_vtables(bcx: block,
|
||||
impl_id: ast::def_id,
|
||||
method: &ty::Method,
|
||||
substs: &ty::substs,
|
||||
impl_vtables: Option<typeck::vtable_res>)
|
||||
-> typeck::vtable_res {
|
||||
|
||||
// Get the vtables that the impl implements the trait at
|
||||
let trait_vtables = get_impl_resolutions(bcx, impl_id);
|
||||
|
||||
// Build up a param_substs that we are going to resolve the
|
||||
// trait_vtables under.
|
||||
let param_substs = Some(@param_substs {
|
||||
tys: copy substs.tps,
|
||||
self_ty: substs.self_ty,
|
||||
vtables: impl_vtables,
|
||||
self_vtable: None
|
||||
});
|
||||
|
||||
let trait_vtables_fixed = resolve_vtables_under_param_substs(
|
||||
bcx.tcx(), param_substs, trait_vtables);
|
||||
|
||||
// Now we pull any vtables for parameters on the actual method.
|
||||
let num_method_vtables = method.generics.type_param_defs.len();
|
||||
let method_vtables = match impl_vtables {
|
||||
Some(vtables) => {
|
||||
let num_impl_type_parameters =
|
||||
vtables.len() - num_method_vtables;
|
||||
vtables.tailn(num_impl_type_parameters).to_owned()
|
||||
},
|
||||
None => vec::from_elem(num_method_vtables, @~[])
|
||||
};
|
||||
|
||||
@(*trait_vtables_fixed + method_vtables)
|
||||
}
|
||||
|
||||
|
||||
pub fn trans_fn_ref_with_vtables(
|
||||
bcx: block, //
|
||||
def_id: ast::def_id, // def id of fn
|
||||
@ -246,9 +298,9 @@ pub fn trans_fn_ref_with_vtables(
|
||||
// We need to do a bunch of special handling for default methods.
|
||||
// We need to modify the def_id and our substs in order to monomorphize
|
||||
// the function.
|
||||
let (def_id, opt_impl_did, substs, self_vtable) =
|
||||
let (def_id, opt_impl_did, substs, self_vtable, vtables) =
|
||||
match tcx.provided_method_sources.find(&def_id) {
|
||||
None => (def_id, None, substs, None),
|
||||
None => (def_id, None, substs, None, vtables),
|
||||
Some(source) => {
|
||||
// There are two relevant substitutions when compiling
|
||||
// default methods. First, there is the substitution for
|
||||
@ -282,49 +334,31 @@ pub fn trans_fn_ref_with_vtables(
|
||||
let self_vtable =
|
||||
typeck::vtable_static(source.impl_id, receiver_substs,
|
||||
receiver_vtables);
|
||||
|
||||
// XXX: I think that if the *trait* has vtables on it,
|
||||
// it is all over
|
||||
|
||||
// Compute the first substitution
|
||||
let first_subst = make_substs_for_receiver_types(
|
||||
tcx, source.impl_id, trait_ref, method);
|
||||
|
||||
// And compose them
|
||||
let new_substs = first_subst.subst(tcx, &substs);
|
||||
|
||||
|
||||
let vtables =
|
||||
resolve_default_method_vtables(bcx, source.impl_id,
|
||||
method, &new_substs, vtables);
|
||||
|
||||
debug!("trans_fn_with_vtables - default method: \
|
||||
substs = %s, trait_subst = %s, \
|
||||
first_subst = %s, new_subst = %s",
|
||||
first_subst = %s, new_subst = %s, \
|
||||
self_vtable = %s, vtables = %s",
|
||||
substs.repr(tcx), trait_ref.substs.repr(tcx),
|
||||
first_subst.repr(tcx), new_substs.repr(tcx));
|
||||
|
||||
first_subst.repr(tcx), new_substs.repr(tcx),
|
||||
self_vtable.repr(tcx), vtables.repr(tcx));
|
||||
|
||||
(source.method_id, Some(source.impl_id),
|
||||
new_substs, Some(self_vtable))
|
||||
new_substs, Some(self_vtable), Some(vtables))
|
||||
}
|
||||
};
|
||||
|
||||
// XXX: this is *completely* bad and wrong. I feel bad. Handling
|
||||
// of vtables is currently bogus for default methods, and changing
|
||||
// to an unflattented representation of vtables causes this to
|
||||
// show up in cases that it did not previously. We need to make
|
||||
// the vtables list be the same length as the substs. There is
|
||||
// nothing right about this. I really need to emphasize just how
|
||||
// wrong it is: it is completely wrong.
|
||||
// XXX: bad.
|
||||
// This will be fixed in the next commit.
|
||||
let vtables = do vtables.map |vtbls| {
|
||||
if vtbls.len() < substs.tps.len() {
|
||||
@(vec::from_elem(substs.tps.len() - vtbls.len(), @~[]) +
|
||||
**vtbls)
|
||||
} else if vtbls.len() > substs.tps.len() {
|
||||
@vtbls.tailn(vtbls.len() - substs.tps.len()).to_owned()
|
||||
} else {
|
||||
*vtbls
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Check whether this fn has an inlined copy and, if so, redirect
|
||||
// def_id to the local id of the inlined copy.
|
||||
let def_id = {
|
||||
|
@ -1035,18 +1035,37 @@ pub fn node_vtables(bcx: block, id: ast::node_id)
|
||||
|
||||
pub fn resolve_vtables_in_fn_ctxt(fcx: fn_ctxt, vts: typeck::vtable_res)
|
||||
-> typeck::vtable_res {
|
||||
@vec::map(*vts, |ds|
|
||||
@vec::map(**ds, |d| resolve_vtable_in_fn_ctxt(fcx, copy *d)))
|
||||
resolve_vtables_under_param_substs(fcx.ccx.tcx,
|
||||
fcx.param_substs,
|
||||
vts)
|
||||
}
|
||||
|
||||
pub fn resolve_vtables_under_param_substs(tcx: ty::ctxt,
|
||||
param_substs: Option<@param_substs>,
|
||||
vts: typeck::vtable_res)
|
||||
-> typeck::vtable_res {
|
||||
@vec::map(*vts, |ds|
|
||||
@vec::map(**ds, |d|
|
||||
resolve_vtable_under_param_substs(tcx, param_substs, copy *d)))
|
||||
}
|
||||
|
||||
|
||||
// Apply the typaram substitutions in the fn_ctxt to a vtable. This should
|
||||
// eliminate any vtable_params.
|
||||
pub fn resolve_vtable_in_fn_ctxt(fcx: fn_ctxt, vt: typeck::vtable_origin)
|
||||
-> typeck::vtable_origin {
|
||||
let tcx = fcx.ccx.tcx;
|
||||
resolve_vtable_under_param_substs(fcx.ccx.tcx,
|
||||
fcx.param_substs,
|
||||
vt)
|
||||
}
|
||||
|
||||
pub fn resolve_vtable_under_param_substs(tcx: ty::ctxt,
|
||||
param_substs: Option<@param_substs>,
|
||||
vt: typeck::vtable_origin)
|
||||
-> typeck::vtable_origin {
|
||||
match vt {
|
||||
typeck::vtable_static(trait_id, tys, sub) => {
|
||||
let tys = match fcx.param_substs {
|
||||
let tys = match param_substs {
|
||||
Some(substs) => {
|
||||
do vec::map(tys) |t| {
|
||||
ty::subst_tps(tcx, substs.tys, substs.self_ty, *t)
|
||||
@ -1054,11 +1073,12 @@ pub fn resolve_vtable_in_fn_ctxt(fcx: fn_ctxt, vt: typeck::vtable_origin)
|
||||
}
|
||||
_ => tys
|
||||
};
|
||||
typeck::vtable_static(trait_id, tys,
|
||||
resolve_vtables_in_fn_ctxt(fcx, sub))
|
||||
typeck::vtable_static(
|
||||
trait_id, tys,
|
||||
resolve_vtables_under_param_substs(tcx, param_substs, sub))
|
||||
}
|
||||
typeck::vtable_param(n_param, n_bound) => {
|
||||
match fcx.param_substs {
|
||||
match param_substs {
|
||||
Some(substs) => {
|
||||
find_vtable(tcx, substs, n_param, n_bound)
|
||||
}
|
||||
@ -1070,7 +1090,7 @@ pub fn resolve_vtable_in_fn_ctxt(fcx: fn_ctxt, vt: typeck::vtable_origin)
|
||||
}
|
||||
}
|
||||
typeck::vtable_self(_trait_id) => {
|
||||
match fcx.param_substs {
|
||||
match param_substs {
|
||||
Some(@param_substs
|
||||
{self_vtable: Some(ref self_vtable), _}) => {
|
||||
copy *self_vtable
|
||||
|
Loading…
Reference in New Issue
Block a user