Skip to content

Commit 78ee821

Browse files
committed
Implement trait inheritance for bounded type parameters
1 parent daa89e0 commit 78ee821

38 files changed

+1001
-173
lines changed

src/librustc/middle/trans/common.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1330,16 +1330,12 @@ fn find_vtable(tcx: ty::ctxt, ps: &param_substs,
13301330
debug!("find_vtable_in_fn_ctxt(n_param=%u, n_bound=%u, ps=%?)",
13311331
n_param, n_bound, param_substs_to_str(tcx, ps));
13321332

1333-
let mut vtable_off = n_bound, i = 0u;
13341333
// Vtables are stored in a flat array, finding the right one is
13351334
// somewhat awkward
1336-
for vec::each(*ps.bounds) |bounds| {
1337-
if i >= n_param { break; }
1338-
for vec::each(**bounds) |bound| {
1339-
match *bound { ty::bound_trait(_) => vtable_off += 1u, _ => () }
1340-
}
1341-
i += 1u;
1342-
}
1335+
let first_n_bounds = ps.bounds.view(0, n_param);
1336+
let vtables_to_skip =
1337+
ty::count_traits_and_supertraits(tcx, first_n_bounds);
1338+
let vtable_off = vtables_to_skip + n_bound;
13431339
ps.vtables.get()[vtable_off]
13441340
}
13451341

src/librustc/middle/trans/meth.rs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -243,17 +243,7 @@ fn trans_static_method_callee(bcx: block,
243243
// one we are interested in.
244244
let bound_index = {
245245
let trait_polyty = ty::lookup_item_type(bcx.tcx(), trait_id);
246-
let mut index = 0;
247-
for trait_polyty.bounds.each |param_bounds| {
248-
for param_bounds.each |param_bound| {
249-
match *param_bound {
250-
ty::bound_trait(_) => { index += 1; }
251-
ty::bound_copy | ty::bound_owned |
252-
ty::bound_send | ty::bound_const => {}
253-
}
254-
}
255-
}
256-
index
246+
ty::count_traits_and_supertraits(bcx.tcx(), *trait_polyty.bounds)
257247
};
258248
259249
let mname = if method_id.crate == ast::local_crate {

src/librustc/middle/ty.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,8 @@ export DerivedFieldInfo;
204204
export AutoAdjustment;
205205
export AutoRef;
206206
export AutoRefKind, AutoPtr, AutoBorrowVec, AutoBorrowFn;
207+
export iter_bound_traits_and_supertraits;
208+
export count_traits_and_supertraits;
207209

208210
// Data types
209211

@@ -4530,6 +4532,64 @@ pure fn determine_inherited_purity(parent_purity: ast::purity,
45304532
}
45314533
}
45324534

4535+
// Iterate over a type parameter's bounded traits and any supertraits
4536+
// of those traits, ignoring kinds.
4537+
fn iter_bound_traits_and_supertraits(tcx: ctxt,
4538+
bounds: param_bounds,
4539+
f: &fn(t) -> bool) {
4540+
for bounds.each |bound| {
4541+
4542+
let bound_trait_ty = match *bound {
4543+
ty::bound_trait(bound_t) => bound_t,
4544+
4545+
ty::bound_copy | ty::bound_send |
4546+
ty::bound_const | ty::bound_owned => {
4547+
loop; // skip non-trait bounds
4548+
}
4549+
};
4550+
4551+
let mut worklist = ~[];
4552+
4553+
let init_trait_ty = bound_trait_ty;
4554+
4555+
worklist.push(init_trait_ty);
4556+
4557+
let mut i = 0;
4558+
while i < worklist.len() {
4559+
let init_trait_ty = worklist[i];
4560+
i += 1;
4561+
4562+
let init_trait_id = match ty_to_def_id(init_trait_ty) {
4563+
Some(id) => id,
4564+
None => tcx.sess.bug(
4565+
~"trait type should have def_id")
4566+
};
4567+
4568+
// Add supertraits to worklist
4569+
let supertraits = trait_supertraits(tcx,
4570+
init_trait_id);
4571+
for supertraits.each |supertrait| {
4572+
worklist.push(supertrait.tpt.ty);
4573+
}
4574+
4575+
if !f(init_trait_ty) {
4576+
return;
4577+
}
4578+
}
4579+
}
4580+
}
4581+
4582+
fn count_traits_and_supertraits(tcx: ctxt,
4583+
boundses: &[param_bounds]) -> uint {
4584+
let mut total = 0;
4585+
for boundses.each |bounds| {
4586+
for iter_bound_traits_and_supertraits(tcx, *bounds) |_trait_ty| {
4587+
total += 1;
4588+
}
4589+
}
4590+
return total;
4591+
}
4592+
45334593
impl mt : cmp::Eq {
45344594
pure fn eq(&self, other: &mt) -> bool {
45354595
(*self).ty == (*other).ty && (*self).mutbl == (*other).mutbl

src/librustc/middle/typeck/check/method.rs

Lines changed: 99 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ impl LookupContext {
241241
loop {
242242
match get(self_ty).sty {
243243
ty_param(p) => {
244-
self.push_inherent_candidates_from_param(p);
244+
self.push_inherent_candidates_from_param(self_ty, p);
245245
}
246246
ty_trait(did, ref substs, vstore) => {
247247
self.push_inherent_candidates_from_trait(
@@ -305,16 +305,18 @@ impl LookupContext {
305305
}
306306
}
307307

308-
fn push_inherent_candidates_from_param(&self, param_ty: param_ty) {
308+
fn push_inherent_candidates_from_param(&self, rcvr_ty: ty::t,
309+
param_ty: param_ty) {
309310
debug!("push_inherent_candidates_from_param(param_ty=%?)",
310311
param_ty);
311312
let _indenter = indenter();
312313

313314
let tcx = self.tcx();
314315
let mut next_bound_idx = 0; // count only trait bounds
315316
let bounds = tcx.ty_param_bounds.get(param_ty.def_id.node);
317+
316318
for vec::each(*bounds) |bound| {
317-
let bound_t = match *bound {
319+
let bound_trait_ty = match *bound {
318320
ty::bound_trait(bound_t) => bound_t,
319321

320322
ty::bound_copy | ty::bound_send |
@@ -323,56 +325,64 @@ impl LookupContext {
323325
}
324326
};
325327

326-
let this_bound_idx = next_bound_idx;
327-
next_bound_idx += 1;
328328

329-
let (trait_id, bound_substs) = match ty::get(bound_t).sty {
330-
ty::ty_trait(i, substs, _) => (i, substs),
329+
let bound_substs = match ty::get(bound_trait_ty).sty {
330+
ty::ty_trait(_, substs, _) => substs,
331331
_ => {
332332
self.bug(fmt!("add_candidates_from_param: \
333333
non-trait bound %s",
334-
self.ty_to_str(bound_t)));
334+
self.ty_to_str(bound_trait_ty)));
335335
}
336336
};
337337

338+
338339
// Loop over the trait and all of its supertraits.
339-
let worklist = dvec::DVec();
340-
worklist.push((trait_id, move bound_substs));
340+
let mut worklist = ~[];
341+
342+
let init_trait_ty = bound_trait_ty;
343+
let init_substs = bound_substs;
344+
345+
// Replace any appearance of `self` with the type of the
346+
// generic parameter itself. Note that this is the only
347+
// case where this replacement is necessary: in all other
348+
// cases, we are either invoking a method directly from an
349+
// impl or class (where the self type is not permitted),
350+
// or from a trait type (in which case methods that refer
351+
// to self are not permitted).
352+
let init_substs = {self_ty: Some(rcvr_ty), ..init_substs};
353+
354+
worklist.push((init_trait_ty, init_substs));
341355

342356
let mut i = 0;
343357
while i < worklist.len() {
344-
let (trait_id, bound_substs) = worklist[i];
358+
let (init_trait_ty, init_substs) = worklist[i];
345359
i += 1;
346360

347-
// Replace any appearance of `self` with the type of the
348-
// generic parameter itself. Note that this is the only
349-
// case where this replacement is necessary: in all other
350-
// cases, we are either invoking a method directly from an
351-
// impl or class (where the self type is not permitted),
352-
// or from a trait type (in which case methods that refer
353-
// to self are not permitted).
354-
let rcvr_ty = ty::mk_param(tcx, param_ty.idx,
355-
param_ty.def_id);
356-
let rcvr_substs = {self_ty: Some(rcvr_ty), ..bound_substs};
361+
let init_trait_id = ty::ty_to_def_id(init_trait_ty).get();
357362

358363
// Add all the supertraits of this trait to the worklist.
359-
debug!("finding supertraits for %d:%d", trait_id.crate,
360-
trait_id.node);
361-
let instantiated_trait_refs = ty::trait_supertraits(
362-
tcx, trait_id);
363-
for instantiated_trait_refs.each |instantiated_trait_ref| {
364-
debug!("adding supertrait");
364+
let supertraits = ty::trait_supertraits(tcx,
365+
init_trait_id);
366+
for supertraits.each |supertrait| {
367+
debug!("adding supertrait: %?",
368+
supertrait.def_id);
365369

366370
let new_substs = ty::subst_substs(
367371
tcx,
368-
&instantiated_trait_ref.tpt.substs,
369-
&rcvr_substs);
372+
&supertrait.tpt.substs,
373+
&init_substs);
374+
375+
// Again replacing the self type
376+
let new_substs = {self_ty: Some(rcvr_ty), ..new_substs};
370377

371-
worklist.push(
372-
(instantiated_trait_ref.def_id, new_substs));
378+
worklist.push((supertrait.tpt.ty, new_substs));
373379
}
374380

375-
let trait_methods = ty::trait_methods(tcx, trait_id);
381+
382+
let this_bound_idx = next_bound_idx;
383+
next_bound_idx += 1;
384+
385+
let trait_methods = ty::trait_methods(tcx, init_trait_id);
376386
let pos = {
377387
// FIXME #3453 can't use trait_methods.position
378388
match vec::position(*trait_methods,
@@ -381,6 +391,8 @@ impl LookupContext {
381391
{
382392
Some(pos) => pos,
383393
None => {
394+
debug!("trait doesn't contain method: %?",
395+
init_trait_id);
384396
loop; // check next trait or bound
385397
}
386398
}
@@ -389,18 +401,21 @@ impl LookupContext {
389401

390402
let (rcvr_ty, rcvr_substs) =
391403
self.create_rcvr_ty_and_substs_for_method(
392-
method.self_ty, rcvr_ty, move rcvr_substs);
404+
method.self_ty, rcvr_ty, move init_substs);
393405

394-
self.inherent_candidates.push(Candidate {
406+
let cand = Candidate {
395407
rcvr_ty: rcvr_ty,
396408
rcvr_substs: rcvr_substs,
397409
num_method_tps: method.tps.len(),
398410
self_mode: get_mode_from_self_type(method.self_ty),
399-
origin: method_param({trait_id:trait_id,
411+
origin: method_param({trait_id:init_trait_id,
400412
method_num:pos,
401413
param_num:param_ty.idx,
402414
bound_num:this_bound_idx})
403-
});
415+
};
416+
417+
debug!("pushing inherent candidate for param: %?", cand);
418+
self.inherent_candidates.push(cand);
404419
}
405420
}
406421
}
@@ -775,6 +790,8 @@ impl LookupContext {
775790
let relevant_candidates =
776791
candidates.filter_to_vec(|c| self.is_relevant(self_ty, &c));
777792

793+
let relevant_candidates = self.merge_candidates(relevant_candidates);
794+
778795
if relevant_candidates.len() == 0 {
779796
return None;
780797
}
@@ -791,6 +808,52 @@ impl LookupContext {
791808
Some(self.confirm_candidate(self_ty, &relevant_candidates[0]))
792809
}
793810

811+
fn merge_candidates(&self, candidates: &[Candidate]) -> ~[Candidate] {
812+
let mut merged = ~[];
813+
let mut i = 0;
814+
while i < candidates.len() {
815+
let candidate_a = candidates[i];
816+
817+
let mut skip = false;
818+
819+
let mut j = i + 1;
820+
while j < candidates.len() {
821+
let candidate_b = candidates[j];
822+
debug!("attempting to merge %? and %?",
823+
candidate_a, candidate_b);
824+
let candidates_same = match (&candidate_a.origin,
825+
&candidate_b.origin) {
826+
(&method_param(p1), &method_param(p2)) => {
827+
let same_trait = p1.trait_id == p2.trait_id;
828+
let same_method = p1.method_num == p2.method_num;
829+
let same_param = p1.param_num == p2.param_num;
830+
// The bound number may be different because
831+
// multiple bounds may lead to the same trait
832+
// impl
833+
same_trait && same_method && same_param
834+
}
835+
_ => false
836+
};
837+
if candidates_same {
838+
skip = true;
839+
break;
840+
}
841+
j += 1;
842+
}
843+
844+
i += 1;
845+
846+
if skip {
847+
// There are more than one of these and we need only one
848+
loop;
849+
} else {
850+
merged.push(candidate_a);
851+
}
852+
}
853+
854+
return merged;
855+
}
856+
794857
fn confirm_candidate(&self,
795858
self_ty: ty::t,
796859
candidate: &Candidate)

0 commit comments

Comments
 (0)