Skip to content

Commit 04f1763

Browse files
committed
Combine the vtable_origins from impl + method.
Not as clean as it could be, but fixes #3314.
1 parent 22b8757 commit 04f1763

File tree

8 files changed

+298
-84
lines changed

8 files changed

+298
-84
lines changed

src/rustc/middle/trans/callee.rs

+14-10
Original file line numberDiff line numberDiff line change
@@ -120,21 +120,18 @@ fn trans_fn_ref_to_callee(bcx: block,
120120
fn trans_fn_ref(bcx: block,
121121
def_id: ast::def_id,
122122
ref_id: ast::node_id) -> FnData {
123-
//!
124-
//
125-
// Translates a reference (with id `ref_id`) to the fn/method
126-
// with id `def_id` into a function pointer. This may require
127-
// monomorphization or inlining.
123+
/*!
124+
*
125+
* Translates a reference (with id `ref_id`) to the fn/method
126+
* with id `def_id` into a function pointer. This may require
127+
* monomorphization or inlining. */
128128

129129
let _icx = bcx.insn_ctxt("trans_fn");
130130

131131
let type_params = node_id_type_params(bcx, ref_id);
132132

133-
let raw_vtables = bcx.ccx().maps.vtable_map.find(ref_id);
134-
let resolved_vtables = raw_vtables.map(
135-
|vts| impl::resolve_vtables_in_fn_ctxt(bcx.fcx, vts));
136-
trans_fn_ref_with_vtables(bcx, def_id, ref_id, type_params,
137-
resolved_vtables)
133+
let vtables = node_vtables(bcx, ref_id);
134+
trans_fn_ref_with_vtables(bcx, def_id, ref_id, type_params, vtables)
138135
}
139136

140137
fn trans_fn_ref_with_vtables_to_callee(bcx: block,
@@ -174,6 +171,13 @@ fn trans_fn_ref_with_vtables(
174171
let ccx = bcx.ccx();
175172
let tcx = ccx.tcx;
176173

174+
debug!("trans_fn_ref_with_vtables(bcx=%s, def_id=%?, ref_id=%?, \
175+
type_params=%?, vtables=%?)",
176+
bcx.to_str(), def_id, ref_id,
177+
type_params.map(|t| bcx.ty_to_str(t)),
178+
vtables);
179+
let _indenter = indenter();
180+
177181
// Polytype of the function item (may have type params)
178182
let fn_tpt = ty::lookup_item_type(tcx, def_id);
179183

src/rustc/middle/trans/common.rs

+74
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,13 @@ type param_substs = {tys: ~[ty::t],
187187
vtables: Option<typeck::vtable_res>,
188188
bounds: @~[ty::param_bounds]};
189189

190+
fn param_substs_to_str(tcx: ty::ctxt, substs: &param_substs) -> ~str {
191+
fmt!("param_substs {tys:%?, vtables:%?, bounds:%?}",
192+
substs.tys.map(|t| ty_to_str(tcx, t)),
193+
substs.vtables.map(|vs| vs.map(|v| v.to_str(tcx))),
194+
substs.bounds.map(|b| ty::param_bounds_to_str(tcx, b)))
195+
}
196+
190197
// Function context. Every LLVM function we create will have one of
191198
// these.
192199
type fn_ctxt = @{
@@ -1181,9 +1188,11 @@ fn node_id_type(bcx: block, id: ast::node_id) -> ty::t {
11811188
_ => { assert !ty::type_has_params(t); t }
11821189
}
11831190
}
1191+
11841192
fn expr_ty(bcx: block, ex: @ast::expr) -> ty::t {
11851193
node_id_type(bcx, ex.id)
11861194
}
1195+
11871196
fn node_id_type_params(bcx: block, id: ast::node_id) -> ~[ty::t] {
11881197
let tcx = bcx.tcx();
11891198
let params = ty::node_id_to_type_params(tcx, id);
@@ -1195,6 +1204,71 @@ fn node_id_type_params(bcx: block, id: ast::node_id) -> ~[ty::t] {
11951204
}
11961205
}
11971206
1207+
fn node_vtables(bcx: block, id: ast::node_id) -> Option<typeck::vtable_res> {
1208+
let raw_vtables = bcx.ccx().maps.vtable_map.find(id);
1209+
raw_vtables.map(
1210+
|vts| impl::resolve_vtables_in_fn_ctxt(bcx.fcx, vts))
1211+
}
1212+
1213+
fn resolve_vtables_in_fn_ctxt(fcx: fn_ctxt, vts: typeck::vtable_res)
1214+
-> typeck::vtable_res
1215+
{
1216+
@vec::map(*vts, |d| resolve_vtable_in_fn_ctxt(fcx, d))
1217+
}
1218+
1219+
// Apply the typaram substitutions in the fn_ctxt to a vtable. This should
1220+
// eliminate any vtable_params.
1221+
fn resolve_vtable_in_fn_ctxt(fcx: fn_ctxt, vt: typeck::vtable_origin)
1222+
-> typeck::vtable_origin
1223+
{
1224+
let tcx = fcx.ccx.tcx;
1225+
match vt {
1226+
typeck::vtable_static(trait_id, tys, sub) => {
1227+
let tys = match fcx.param_substs {
1228+
Some(substs) => {
1229+
vec::map(tys, |t| ty::subst_tps(tcx, substs.tys, t))
1230+
}
1231+
_ => tys
1232+
};
1233+
typeck::vtable_static(trait_id, tys,
1234+
resolve_vtables_in_fn_ctxt(fcx, sub))
1235+
}
1236+
typeck::vtable_param(n_param, n_bound) => {
1237+
match fcx.param_substs {
1238+
Some(ref substs) => {
1239+
find_vtable(tcx, substs, n_param, n_bound)
1240+
}
1241+
_ => {
1242+
tcx.sess.bug(fmt!(
1243+
"resolve_vtable_in_fn_ctxt: asked to lookup %? but \
1244+
no vtables in the fn_ctxt!", vt))
1245+
}
1246+
}
1247+
}
1248+
_ => vt
1249+
}
1250+
}
1251+
1252+
fn find_vtable(tcx: ty::ctxt, ps: &param_substs,
1253+
n_param: uint, n_bound: uint)
1254+
-> typeck::vtable_origin
1255+
{
1256+
debug!("find_vtable_in_fn_ctxt(n_param=%u, n_bound=%u, ps=%?)",
1257+
n_param, n_bound, param_substs_to_str(tcx, ps));
1258+
1259+
let mut vtable_off = n_bound, i = 0u;
1260+
// Vtables are stored in a flat array, finding the right one is
1261+
// somewhat awkward
1262+
for vec::each(*ps.bounds) |bounds| {
1263+
if i >= n_param { break; }
1264+
for vec::each(*bounds) |bound| {
1265+
match bound { ty::bound_trait(_) => vtable_off += 1u, _ => () }
1266+
}
1267+
i += 1u;
1268+
}
1269+
option::get(ps.vtables)[vtable_off]
1270+
}
1271+
11981272
fn dummy_substs(tps: ~[ty::t]) -> ty::substs {
11991273
{self_r: Some(ty::re_bound(ty::br_self)),
12001274
self_ty: None,

src/rustc/middle/trans/impl.rs

+106-72
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,8 @@ fn trans_method_callee(bcx: block, callee_id: ast::node_id,
134134
typeck::method_param({trait_id:trait_id, method_num:off,
135135
param_num:p, bound_num:b}) => {
136136
match bcx.fcx.param_substs {
137-
Some(substs) => {
138-
let vtbl = find_vtable_in_fn_ctxt(substs, p, b);
137+
Some(ref substs) => {
138+
let vtbl = base::find_vtable(bcx.tcx(), substs, p, b);
139139
trans_monomorphized_callee(bcx, callee_id, self, mentry,
140140
trait_id, off, vtbl)
141141
}
@@ -177,19 +177,17 @@ fn trans_static_method_callee(bcx: block,
177177
bcx.fcx, ccx.maps.vtable_map.get(callee_id));
178178

179179
match vtbls[0] { // is index 0 always the one we want?
180-
typeck::vtable_static(impl_did, impl_substs, sub_origins) => {
180+
typeck::vtable_static(impl_did, rcvr_substs, rcvr_origins) => {
181181

182182
let mth_id = method_with_name(bcx.ccx(), impl_did, mname);
183-
let n_m_tps = method_ty_param_count(ccx, mth_id, impl_did);
184-
let node_substs = node_id_type_params(bcx, callee_id);
185-
let ty_substs
186-
= vec::append(impl_substs,
187-
vec::tailn(node_substs,
188-
node_substs.len() - n_m_tps));
183+
let callee_substs = combine_impl_and_methods_tps(
184+
bcx, mth_id, impl_did, callee_id, rcvr_substs);
185+
let callee_origins = combine_impl_and_methods_origins(
186+
bcx, mth_id, impl_did, callee_id, rcvr_origins);
189187

190188
let FnData {llfn: lval} =
191189
trans_fn_ref_with_vtables(bcx, mth_id, callee_id,
192-
ty_substs, Some(sub_origins));
190+
callee_substs, Some(callee_origins));
193191

194192
let callee_ty = node_id_type(bcx, callee_id);
195193
let llty = T_ptr(type_of_fn_from_ty(ccx, callee_ty));
@@ -248,8 +246,8 @@ fn trans_monomorphized_callee(bcx: block,
248246
-> Callee
249247
{
250248
let _icx = bcx.insn_ctxt("impl::trans_monomorphized_callee");
251-
match vtbl {
252-
typeck::vtable_static(impl_did, impl_substs, sub_origins) => {
249+
return match vtbl {
250+
typeck::vtable_static(impl_did, rcvr_substs, rcvr_origins) => {
253251
let ccx = bcx.ccx();
254252
let mname = ty::trait_methods(ccx.tcx, trait_id)[n_method].ident;
255253
let mth_id = method_with_name(bcx.ccx(), impl_did, mname);
@@ -260,20 +258,14 @@ fn trans_monomorphized_callee(bcx: block,
260258

261259
// create a concatenated set of substitutions which includes
262260
// those from the impl and those from the method:
263-
let n_m_tps = method_ty_param_count(ccx, mth_id, impl_did);
264-
let node_substs = node_id_type_params(bcx, callee_id);
265-
let ty_substs
266-
= vec::append(impl_substs,
267-
vec::tailn(node_substs,
268-
node_substs.len() - n_m_tps));
269-
debug!("n_m_tps=%?", n_m_tps);
270-
debug!("impl_substs=%?", impl_substs.map(|t| bcx.ty_to_str(t)));
271-
debug!("node_substs=%?", node_substs.map(|t| bcx.ty_to_str(t)));
272-
debug!("ty_substs=%?", ty_substs.map(|t| bcx.ty_to_str(t)));
261+
let callee_substs = combine_impl_and_methods_tps(
262+
bcx, mth_id, impl_did, callee_id, rcvr_substs);
263+
let callee_origins = combine_impl_and_methods_origins(
264+
bcx, mth_id, impl_did, callee_id, rcvr_origins);
273265

274266
// translate the function
275267
let callee = trans_fn_ref_with_vtables(
276-
bcx, mth_id, callee_id, ty_substs, Some(sub_origins));
268+
bcx, mth_id, callee_id, callee_substs, Some(callee_origins));
277269

278270
// create a llvalue that represents the fn ptr
279271
let fn_ty = node_id_type(bcx, callee_id);
@@ -297,9 +289,99 @@ fn trans_monomorphized_callee(bcx: block,
297289
typeck::vtable_param(*) => {
298290
fail ~"vtable_param left in monomorphized function's vtable substs";
299291
}
300-
}
292+
};
293+
294+
}
295+
296+
fn combine_impl_and_methods_tps(bcx: block,
297+
mth_did: ast::def_id,
298+
impl_did: ast::def_id,
299+
callee_id: ast::node_id,
300+
rcvr_substs: ~[ty::t])
301+
-> ~[ty::t]
302+
{
303+
/*!
304+
*
305+
* Creates a concatenated set of substitutions which includes
306+
* those from the impl and those from the method. This are
307+
* some subtle complications here. Statically, we have a list
308+
* of type parameters like `[T0, T1, T2, M1, M2, M3]` where
309+
* `Tn` are type parameters that appear on the receiver. For
310+
* example, if the receiver is a method parameter `A` with a
311+
* bound like `trait<B,C,D>` then `Tn` would be `[B,C,D]`.
312+
*
313+
* The weird part is that the type `A` might now be bound to
314+
* any other type, such as `foo<X>`. In that case, the vector
315+
* we want is: `[X, M1, M2, M3]`. Therefore, what we do now is
316+
* to slice off the method type parameters and append them to
317+
* the type parameters from the type that the receiver is
318+
* mapped to. */
319+
320+
let ccx = bcx.ccx();
321+
let n_m_tps = method_ty_param_count(ccx, mth_did, impl_did);
322+
let node_substs = node_id_type_params(bcx, callee_id);
323+
let ty_substs
324+
= vec::append(rcvr_substs,
325+
vec::tailn(node_substs,
326+
node_substs.len() - n_m_tps));
327+
debug!("n_m_tps=%?", n_m_tps);
328+
debug!("rcvr_substs=%?", rcvr_substs.map(|t| bcx.ty_to_str(t)));
329+
debug!("node_substs=%?", node_substs.map(|t| bcx.ty_to_str(t)));
330+
debug!("ty_substs=%?", ty_substs.map(|t| bcx.ty_to_str(t)));
331+
332+
return ty_substs;
333+
}
334+
335+
fn combine_impl_and_methods_origins(bcx: block,
336+
mth_did: ast::def_id,
337+
impl_did: ast::def_id,
338+
callee_id: ast::node_id,
339+
rcvr_origins: typeck::vtable_res)
340+
-> typeck::vtable_res
341+
{
342+
/*!
343+
*
344+
* Similar to `combine_impl_and_methods_tps`, but for vtables.
345+
* This is much messier because of the flattened layout we are
346+
* currently using (for some reason that I fail to understand).
347+
* The proper fix is described in #3446.
348+
*/
349+
350+
351+
// Find the bounds for the method, which are the tail of the
352+
// bounds found in the item type, as the item type combines the
353+
// rcvr + method bounds.
354+
let ccx = bcx.ccx(), tcx = bcx.tcx();
355+
let n_m_tps = method_ty_param_count(ccx, mth_did, impl_did);
356+
let {bounds: r_m_bounds, _} = ty::lookup_item_type(tcx, mth_did);
357+
let n_r_m_tps = r_m_bounds.len(); // rcvr + method tps
358+
let m_boundss = vec::view(*r_m_bounds, n_r_m_tps - n_m_tps, n_r_m_tps);
359+
360+
// Flatten out to find the number of vtables the method expects.
361+
let m_vtables = m_boundss.foldl(0, |sum, m_bounds| {
362+
m_bounds.foldl(sum, |sum, m_bound| {
363+
sum + match m_bound {
364+
ty::bound_copy | ty::bound_owned |
365+
ty::bound_send | ty::bound_const => 0,
366+
ty::bound_trait(_) => 1
367+
}
368+
})
369+
});
370+
371+
// Find the vtables we computed at type check time and monomorphize them
372+
let r_m_origins = match node_vtables(bcx, callee_id) {
373+
Some(vt) => vt,
374+
None => @~[]
375+
};
376+
377+
// Extract those that belong to method:
378+
let m_origins = vec::tailn(*r_m_origins, r_m_origins.len() - m_vtables);
379+
380+
// Combine rcvr + method to find the final result:
381+
@vec::append(*rcvr_origins, m_origins)
301382
}
302383

384+
303385
fn trans_trait_callee(bcx: block,
304386
callee_id: ast::node_id,
305387
n_method: uint,
@@ -367,54 +449,6 @@ fn trans_trait_callee_from_llval(bcx: block,
367449
};
368450
}
369451

370-
fn find_vtable_in_fn_ctxt(ps: param_substs, n_param: uint, n_bound: uint)
371-
-> typeck::vtable_origin
372-
{
373-
let mut vtable_off = n_bound, i = 0u;
374-
// Vtables are stored in a flat array, finding the right one is
375-
// somewhat awkward
376-
for vec::each(*ps.bounds) |bounds| {
377-
if i >= n_param { break; }
378-
for vec::each(*bounds) |bound| {
379-
match bound { ty::bound_trait(_) => vtable_off += 1u, _ => () }
380-
}
381-
i += 1u;
382-
}
383-
option::get(ps.vtables)[vtable_off]
384-
}
385-
386-
fn resolve_vtables_in_fn_ctxt(fcx: fn_ctxt, vts: typeck::vtable_res)
387-
-> typeck::vtable_res {
388-
@vec::map(*vts, |d| resolve_vtable_in_fn_ctxt(fcx, d))
389-
}
390-
391-
// Apply the typaram substitutions in the fn_ctxt to a vtable. This should
392-
// eliminate any vtable_params.
393-
fn resolve_vtable_in_fn_ctxt(fcx: fn_ctxt, vt: typeck::vtable_origin)
394-
-> typeck::vtable_origin {
395-
match vt {
396-
typeck::vtable_static(trait_id, tys, sub) => {
397-
let tys = match fcx.param_substs {
398-
Some(substs) => {
399-
vec::map(tys, |t| ty::subst_tps(fcx.ccx.tcx, substs.tys, t))
400-
}
401-
_ => tys
402-
};
403-
typeck::vtable_static(trait_id, tys,
404-
resolve_vtables_in_fn_ctxt(fcx, sub))
405-
}
406-
typeck::vtable_param(n_param, n_bound) => {
407-
match fcx.param_substs {
408-
Some(substs) => {
409-
find_vtable_in_fn_ctxt(substs, n_param, n_bound)
410-
}
411-
_ => fail ~"resolve_vtable_in_fn_ctxt: no substs"
412-
}
413-
}
414-
_ => vt
415-
}
416-
}
417-
418452
fn vtable_id(ccx: @crate_ctxt, origin: typeck::vtable_origin) -> mono_id {
419453
match origin {
420454
typeck::vtable_static(impl_id, substs, sub_vtables) => {

src/rustc/middle/ty.rs

+15
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ export ck_block;
156156
export ck_box;
157157
export ck_uniq;
158158
export param_bound, param_bounds, bound_copy, bound_owned;
159+
export param_bounds_to_str, param_bound_to_str;
159160
export bound_send, bound_trait;
160161
export param_bounds_to_kind;
161162
export default_arg_mode_for_ty;
@@ -1338,6 +1339,20 @@ fn substs_to_str(cx: ctxt, substs: &substs) -> ~str {
13381339
substs.tps.map(|t| ty_to_str(cx, t)))
13391340
}
13401341
1342+
fn param_bound_to_str(cx: ctxt, pb: &param_bound) -> ~str {
1343+
match *pb {
1344+
bound_copy => ~"copy",
1345+
bound_owned => ~"owned",
1346+
bound_send => ~"send",
1347+
bound_const => ~"const",
1348+
bound_trait(t) => ty_to_str(cx, t)
1349+
}
1350+
}
1351+
1352+
fn param_bounds_to_str(cx: ctxt, pbs: param_bounds) -> ~str {
1353+
fmt!("%?", pbs.map(|pb| param_bound_to_str(cx, &pb)))
1354+
}
1355+
13411356
fn subst(cx: ctxt,
13421357
substs: &substs,
13431358
typ: t) -> t {

0 commit comments

Comments
 (0)