Skip to content

Commit 0252693

Browse files
committed
Improve handling of trait bounds on a trait in default methods.
This is work on rust-lang#7460. It does not properly handle certain cross crate situations, because we don't properly export vtable resolution information.
1 parent 649b26f commit 0252693

File tree

2 files changed

+92
-38
lines changed

2 files changed

+92
-38
lines changed

src/librustc/middle/trans/callee.rs

Lines changed: 65 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,58 @@ pub fn trans_fn_ref_with_vtables_to_callee(
195195
type_params, vtables))}
196196
}
197197

198+
fn get_impl_resolutions(bcx: block,
199+
impl_id: ast::def_id)
200+
-> typeck::vtable_res {
201+
if impl_id.crate == ast::local_crate {
202+
*bcx.ccx().maps.vtable_map.get(&impl_id.node)
203+
} else {
204+
// XXX: This is a temporary hack to work around not properly
205+
// exporting information about resolutions for impls.
206+
// This doesn't actually work if the trait has param bounds,
207+
// but it does allow us to survive the case when it does not.
208+
let trait_ref = ty::impl_trait_ref(bcx.tcx(), impl_id).get();
209+
@vec::from_elem(trait_ref.substs.tps.len(), @~[])
210+
}
211+
}
212+
213+
fn resolve_default_method_vtables(bcx: block,
214+
impl_id: ast::def_id,
215+
method: &ty::Method,
216+
substs: &ty::substs,
217+
impl_vtables: Option<typeck::vtable_res>)
218+
-> typeck::vtable_res {
219+
220+
// Get the vtables that the impl implements the trait at
221+
let trait_vtables = get_impl_resolutions(bcx, impl_id);
222+
223+
// Build up a param_substs that we are going to resolve the
224+
// trait_vtables under.
225+
let param_substs = Some(@param_substs {
226+
tys: copy substs.tps,
227+
self_ty: substs.self_ty,
228+
vtables: impl_vtables,
229+
self_vtable: None
230+
});
231+
232+
let trait_vtables_fixed = resolve_vtables_under_param_substs(
233+
bcx.tcx(), param_substs, trait_vtables);
234+
235+
// Now we pull any vtables for parameters on the actual method.
236+
let num_method_vtables = method.generics.type_param_defs.len();
237+
let method_vtables = match impl_vtables {
238+
Some(vtables) => {
239+
let num_impl_type_parameters =
240+
vtables.len() - num_method_vtables;
241+
vtables.tailn(num_impl_type_parameters).to_owned()
242+
},
243+
None => vec::from_elem(num_method_vtables, @~[])
244+
};
245+
246+
@(*trait_vtables_fixed + method_vtables)
247+
}
248+
249+
198250
pub fn trans_fn_ref_with_vtables(
199251
bcx: block, //
200252
def_id: ast::def_id, // def id of fn
@@ -246,9 +298,9 @@ pub fn trans_fn_ref_with_vtables(
246298
// We need to do a bunch of special handling for default methods.
247299
// We need to modify the def_id and our substs in order to monomorphize
248300
// the function.
249-
let (def_id, opt_impl_did, substs, self_vtable) =
301+
let (def_id, opt_impl_did, substs, self_vtable, vtables) =
250302
match tcx.provided_method_sources.find(&def_id) {
251-
None => (def_id, None, substs, None),
303+
None => (def_id, None, substs, None, vtables),
252304
Some(source) => {
253305
// There are two relevant substitutions when compiling
254306
// default methods. First, there is the substitution for
@@ -282,49 +334,31 @@ pub fn trans_fn_ref_with_vtables(
282334
let self_vtable =
283335
typeck::vtable_static(source.impl_id, receiver_substs,
284336
receiver_vtables);
285-
286-
// XXX: I think that if the *trait* has vtables on it,
287-
// it is all over
288-
289337
// Compute the first substitution
290338
let first_subst = make_substs_for_receiver_types(
291339
tcx, source.impl_id, trait_ref, method);
292340

293341
// And compose them
294342
let new_substs = first_subst.subst(tcx, &substs);
343+
344+
345+
let vtables =
346+
resolve_default_method_vtables(bcx, source.impl_id,
347+
method, &new_substs, vtables);
348+
295349
debug!("trans_fn_with_vtables - default method: \
296350
substs = %s, trait_subst = %s, \
297-
first_subst = %s, new_subst = %s",
351+
first_subst = %s, new_subst = %s, \
352+
self_vtable = %s, vtables = %s",
298353
substs.repr(tcx), trait_ref.substs.repr(tcx),
299-
first_subst.repr(tcx), new_substs.repr(tcx));
300-
354+
first_subst.repr(tcx), new_substs.repr(tcx),
355+
self_vtable.repr(tcx), vtables.repr(tcx));
301356

302357
(source.method_id, Some(source.impl_id),
303-
new_substs, Some(self_vtable))
358+
new_substs, Some(self_vtable), Some(vtables))
304359
}
305360
};
306361

307-
// XXX: this is *completely* bad and wrong. I feel bad. Handling
308-
// of vtables is currently bogus for default methods, and changing
309-
// to an unflattented representation of vtables causes this to
310-
// show up in cases that it did not previously. We need to make
311-
// the vtables list be the same length as the substs. There is
312-
// nothing right about this. I really need to emphasize just how
313-
// wrong it is: it is completely wrong.
314-
// XXX: bad.
315-
// This will be fixed in the next commit.
316-
let vtables = do vtables.map |vtbls| {
317-
if vtbls.len() < substs.tps.len() {
318-
@(vec::from_elem(substs.tps.len() - vtbls.len(), @~[]) +
319-
**vtbls)
320-
} else if vtbls.len() > substs.tps.len() {
321-
@vtbls.tailn(vtbls.len() - substs.tps.len()).to_owned()
322-
} else {
323-
*vtbls
324-
}
325-
};
326-
327-
328362
// Check whether this fn has an inlined copy and, if so, redirect
329363
// def_id to the local id of the inlined copy.
330364
let def_id = {

src/librustc/middle/trans/common.rs

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,30 +1035,50 @@ pub fn node_vtables(bcx: block, id: ast::node_id)
10351035

10361036
pub fn resolve_vtables_in_fn_ctxt(fcx: fn_ctxt, vts: typeck::vtable_res)
10371037
-> typeck::vtable_res {
1038+
resolve_vtables_under_param_substs(fcx.ccx.tcx,
1039+
fcx.param_substs,
1040+
vts)
1041+
}
1042+
1043+
pub fn resolve_vtables_under_param_substs(tcx: ty::ctxt,
1044+
param_substs: Option<@param_substs>,
1045+
vts: typeck::vtable_res)
1046+
-> typeck::vtable_res {
10381047
@vec::map(*vts, |ds|
1039-
@vec::map(**ds, |d| resolve_vtable_in_fn_ctxt(fcx, copy *d)))
1048+
@vec::map(**ds, |d|
1049+
resolve_vtable_under_param_substs(tcx, param_substs, copy *d)))
10401050
}
10411051

1052+
10421053
// Apply the typaram substitutions in the fn_ctxt to a vtable. This should
10431054
// eliminate any vtable_params.
10441055
pub fn resolve_vtable_in_fn_ctxt(fcx: fn_ctxt, vt: typeck::vtable_origin)
10451056
-> typeck::vtable_origin {
1046-
let tcx = fcx.ccx.tcx;
1057+
resolve_vtable_under_param_substs(fcx.ccx.tcx,
1058+
fcx.param_substs,
1059+
vt)
1060+
}
1061+
1062+
pub fn resolve_vtable_under_param_substs(tcx: ty::ctxt,
1063+
param_substs: Option<@param_substs>,
1064+
vt: typeck::vtable_origin)
1065+
-> typeck::vtable_origin {
10471066
match vt {
10481067
typeck::vtable_static(trait_id, tys, sub) => {
1049-
let tys = match fcx.param_substs {
1068+
let tys = match param_substs {
10501069
Some(substs) => {
10511070
do vec::map(tys) |t| {
10521071
ty::subst_tps(tcx, substs.tys, substs.self_ty, *t)
10531072
}
10541073
}
10551074
_ => tys
10561075
};
1057-
typeck::vtable_static(trait_id, tys,
1058-
resolve_vtables_in_fn_ctxt(fcx, sub))
1076+
typeck::vtable_static(
1077+
trait_id, tys,
1078+
resolve_vtables_under_param_substs(tcx, param_substs, sub))
10591079
}
10601080
typeck::vtable_param(n_param, n_bound) => {
1061-
match fcx.param_substs {
1081+
match param_substs {
10621082
Some(substs) => {
10631083
find_vtable(tcx, substs, n_param, n_bound)
10641084
}
@@ -1070,7 +1090,7 @@ pub fn resolve_vtable_in_fn_ctxt(fcx: fn_ctxt, vt: typeck::vtable_origin)
10701090
}
10711091
}
10721092
typeck::vtable_self(_trait_id) => {
1073-
match fcx.param_substs {
1093+
match param_substs {
10741094
Some(@param_substs
10751095
{self_vtable: Some(ref self_vtable), _}) => {
10761096
copy *self_vtable

0 commit comments

Comments
 (0)