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))}
|
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(
|
pub fn trans_fn_ref_with_vtables(
|
||||||
bcx: block, //
|
bcx: block, //
|
||||||
def_id: ast::def_id, // def id of fn
|
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 do a bunch of special handling for default methods.
|
||||||
// We need to modify the def_id and our substs in order to monomorphize
|
// We need to modify the def_id and our substs in order to monomorphize
|
||||||
// the function.
|
// 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) {
|
match tcx.provided_method_sources.find(&def_id) {
|
||||||
None => (def_id, None, substs, None),
|
None => (def_id, None, substs, None, vtables),
|
||||||
Some(source) => {
|
Some(source) => {
|
||||||
// There are two relevant substitutions when compiling
|
// There are two relevant substitutions when compiling
|
||||||
// default methods. First, there is the substitution for
|
// default methods. First, there is the substitution for
|
||||||
@ -282,49 +334,31 @@ pub fn trans_fn_ref_with_vtables(
|
|||||||
let self_vtable =
|
let self_vtable =
|
||||||
typeck::vtable_static(source.impl_id, receiver_substs,
|
typeck::vtable_static(source.impl_id, receiver_substs,
|
||||||
receiver_vtables);
|
receiver_vtables);
|
||||||
|
|
||||||
// XXX: I think that if the *trait* has vtables on it,
|
|
||||||
// it is all over
|
|
||||||
|
|
||||||
// Compute the first substitution
|
// Compute the first substitution
|
||||||
let first_subst = make_substs_for_receiver_types(
|
let first_subst = make_substs_for_receiver_types(
|
||||||
tcx, source.impl_id, trait_ref, method);
|
tcx, source.impl_id, trait_ref, method);
|
||||||
|
|
||||||
// And compose them
|
// And compose them
|
||||||
let new_substs = first_subst.subst(tcx, &substs);
|
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: \
|
debug!("trans_fn_with_vtables - default method: \
|
||||||
substs = %s, trait_subst = %s, \
|
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),
|
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),
|
(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
|
// Check whether this fn has an inlined copy and, if so, redirect
|
||||||
// def_id to the local id of the inlined copy.
|
// def_id to the local id of the inlined copy.
|
||||||
let def_id = {
|
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)
|
pub fn resolve_vtables_in_fn_ctxt(fcx: fn_ctxt, vts: typeck::vtable_res)
|
||||||
-> typeck::vtable_res {
|
-> typeck::vtable_res {
|
||||||
@vec::map(*vts, |ds|
|
resolve_vtables_under_param_substs(fcx.ccx.tcx,
|
||||||
@vec::map(**ds, |d| resolve_vtable_in_fn_ctxt(fcx, copy *d)))
|
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
|
// Apply the typaram substitutions in the fn_ctxt to a vtable. This should
|
||||||
// eliminate any vtable_params.
|
// eliminate any vtable_params.
|
||||||
pub fn resolve_vtable_in_fn_ctxt(fcx: fn_ctxt, vt: typeck::vtable_origin)
|
pub fn resolve_vtable_in_fn_ctxt(fcx: fn_ctxt, vt: typeck::vtable_origin)
|
||||||
-> 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 {
|
match vt {
|
||||||
typeck::vtable_static(trait_id, tys, sub) => {
|
typeck::vtable_static(trait_id, tys, sub) => {
|
||||||
let tys = match fcx.param_substs {
|
let tys = match param_substs {
|
||||||
Some(substs) => {
|
Some(substs) => {
|
||||||
do vec::map(tys) |t| {
|
do vec::map(tys) |t| {
|
||||||
ty::subst_tps(tcx, substs.tys, substs.self_ty, *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
|
_ => tys
|
||||||
};
|
};
|
||||||
typeck::vtable_static(trait_id, tys,
|
typeck::vtable_static(
|
||||||
resolve_vtables_in_fn_ctxt(fcx, sub))
|
trait_id, tys,
|
||||||
|
resolve_vtables_under_param_substs(tcx, param_substs, sub))
|
||||||
}
|
}
|
||||||
typeck::vtable_param(n_param, n_bound) => {
|
typeck::vtable_param(n_param, n_bound) => {
|
||||||
match fcx.param_substs {
|
match param_substs {
|
||||||
Some(substs) => {
|
Some(substs) => {
|
||||||
find_vtable(tcx, substs, n_param, n_bound)
|
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) => {
|
typeck::vtable_self(_trait_id) => {
|
||||||
match fcx.param_substs {
|
match param_substs {
|
||||||
Some(@param_substs
|
Some(@param_substs
|
||||||
{self_vtable: Some(ref self_vtable), _}) => {
|
{self_vtable: Some(ref self_vtable), _}) => {
|
||||||
copy *self_vtable
|
copy *self_vtable
|
||||||
|
Loading…
Reference in New Issue
Block a user