Skip to content

Commit a30ea01

Browse files
committed
Handle supertrait calls in default methods
Add a new method_super origin for supertrait methods. Also make coherence create a table that maps pairs of trait IDs and self types to impl IDs, so that it's possible to check a supertrait method knowing only its index in its trait's methods (without knowing all supertraits for a given trait). r=nmatsakis and graydon -- with hope, we'll revamp all of this code as per #4678, but for now this fixes the bug. Closes #3979
1 parent b927e48 commit a30ea01

14 files changed

+354
-74
lines changed

src/librustc/middle/astencode.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,7 @@ impl method_origin: tr {
564564
fn tr(xcx: extended_decode_ctxt) -> method_origin {
565565
match self {
566566
typeck::method_static(did) => {
567-
typeck::method_static(did.tr(xcx))
567+
typeck::method_static(did.tr(xcx))
568568
}
569569
typeck::method_param(ref mp) => {
570570
typeck::method_param(
@@ -575,10 +575,13 @@ impl method_origin: tr {
575575
)
576576
}
577577
typeck::method_trait(did, m, vstore) => {
578-
typeck::method_trait(did.tr(xcx), m, vstore)
578+
typeck::method_trait(did.tr(xcx), m, vstore)
579579
}
580580
typeck::method_self(did, m) => {
581-
typeck::method_self(did.tr(xcx), m)
581+
typeck::method_self(did.tr(xcx), m)
582+
}
583+
typeck::method_super(trait_did, m) => {
584+
typeck::method_super(trait_did.tr(xcx), m)
582585
}
583586
}
584587
}

src/librustc/middle/privacy.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ use core::prelude::*;
1616

1717
use middle::ty::{ty_struct, ty_enum};
1818
use middle::ty;
19-
use middle::typeck::{method_map, method_origin, method_param, method_self};
19+
use middle::typeck::{method_map, method_origin, method_param, method_self,
20+
method_super};
2021
use middle::typeck::{method_static, method_trait};
2122

2223
use core::dvec::DVec;
@@ -138,7 +139,8 @@ fn check_crate(tcx: ty::ctxt, method_map: &method_map, crate: @ast::crate) {
138139
_
139140
}) |
140141
method_trait(trait_id, method_num, _) |
141-
method_self(trait_id, method_num) => {
142+
method_self(trait_id, method_num) |
143+
method_super(trait_id, method_num) => {
142144
if trait_id.crate == local_crate {
143145
match tcx.items.find(trait_id.node) {
144146
Some(node_item(item, _)) => {

src/librustc/middle/trans/meth.rs

+25-2
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,29 @@ fn trans_method_callee(bcx: block, callee_id: ast::node_id,
193193
method_name);
194194
origin = typeck::method_static(method_id);
195195
}
196+
typeck::method_super(trait_id, method_index) => {
197+
// <self_ty> is the self type for this method call
198+
let self_ty = node_id_type(bcx, self.id);
199+
let tcx = bcx.tcx();
200+
// <impl_id> is the ID of the implementation of
201+
// trait <trait_id> for type <self_ty>
202+
let impl_id = ty::get_impl_id(tcx, trait_id, self_ty);
203+
// Get the supertrait's methods
204+
let supertrait_methods = ty::trait_methods(tcx, trait_id);
205+
// Make sure to fail with a readable error message if
206+
// there's some internal error here
207+
if !(method_index < supertrait_methods.len()) {
208+
tcx.sess.bug(~"trans_method_callee: supertrait method \
209+
index is out of bounds");
210+
}
211+
// Get the method name using the method index in the origin
212+
let method_name = supertrait_methods[method_index].ident;
213+
// Now that we know the impl ID, we can look up the method
214+
// ID from its name
215+
origin = typeck::method_static(method_with_name(bcx.ccx(),
216+
impl_id,
217+
method_name));
218+
}
196219
typeck::method_static(*) | typeck::method_param(*) |
197220
typeck::method_trait(*) => {}
198221
}
@@ -236,8 +259,8 @@ fn trans_method_callee(bcx: block, callee_id: ast::node_id,
236259
vstore,
237260
mentry.explicit_self)
238261
}
239-
typeck::method_self(*) => {
240-
fail ~"method_self should have been handled above"
262+
typeck::method_self(*) | typeck::method_super(*) => {
263+
fail ~"method_self or method_super should have been handled above"
241264
}
242265
}
243266
}

src/librustc/middle/trans/monomorphize.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ fn make_mono_id(ccx: @crate_ctxt, item: ast::def_id, substs: ~[ty::t],
312312
let precise_param_ids = match vtables {
313313
Some(vts) => {
314314
let bounds = ty::lookup_item_type(ccx.tcx, item).bounds;
315-
let mut i = 0u;
315+
let mut i = 0;
316316
vec::map2(*bounds, substs, |bounds, subst| {
317317
let mut v = ~[];
318318
for bounds.each |bound| {

src/librustc/middle/trans/type_use.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,8 @@ fn mark_for_method_call(cx: ctx, e_id: node_id, callee_id: node_id) {
239239
}) => {
240240
cx.uses[param] |= use_tydesc;
241241
}
242-
typeck::method_trait(*) | typeck::method_self(*) => (),
242+
typeck::method_trait(*) | typeck::method_self(*)
243+
| typeck::method_super(*) => (),
243244
}
244245
}
245246
}

src/librustc/middle/ty.rs

+67-28
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ export iter_bound_traits_and_supertraits;
243243
export count_traits_and_supertraits;
244244
export IntVarValue, IntType, UintType;
245245
export creader_cache_key;
246+
export get_impl_id;
246247

247248
// Data types
248249

@@ -486,6 +487,9 @@ type ctxt =
486487

487488
// Records the value mode (read, copy, or move) for every value.
488489
value_modes: HashMap<ast::node_id, ValueMode>,
490+
491+
// Maps a trait onto a mapping from self-ty to impl
492+
trait_impls: HashMap<ast::def_id, HashMap<t, @Impl>>
489493
};
490494

491495
enum tbox_flag {
@@ -1051,7 +1055,9 @@ fn mk_ctxt(s: session::Session,
10511055
supertraits: HashMap(),
10521056
destructor_for_type: HashMap(),
10531057
destructors: HashMap(),
1054-
value_modes: HashMap()}
1058+
value_modes: HashMap(),
1059+
trait_impls: HashMap()
1060+
}
10551061
}
10561062

10571063

@@ -3130,7 +3136,8 @@ fn method_call_bounds(tcx: ctxt, method_map: typeck::method_map,
31303136
trait_id: trt_id,
31313137
method_num: n_mth, _}) |
31323138
typeck::method_trait(trt_id, n_mth, _) |
3133-
typeck::method_self(trt_id, n_mth) => {
3139+
typeck::method_self(trt_id, n_mth) |
3140+
typeck::method_super(trt_id, n_mth) => {
31343141
// ...trait methods bounds, in contrast, include only the
31353142
// method bounds, so we must preprend the tps from the
31363143
// trait itself. This ought to be harmonized.
@@ -4372,9 +4379,14 @@ pure fn determine_inherited_purity(parent_purity: ast::purity,
43724379

43734380
// Iterate over a type parameter's bounded traits and any supertraits
43744381
// of those traits, ignoring kinds.
4382+
// Here, the supertraits are the transitive closure of the supertrait
4383+
// relation on the supertraits from each bounded trait's constraint
4384+
// list.
43754385
fn iter_bound_traits_and_supertraits(tcx: ctxt,
43764386
bounds: param_bounds,
43774387
f: &fn(t) -> bool) {
4388+
let mut fin = false;
4389+
43784390
for bounds.each |bound| {
43794391

43804392
let bound_trait_ty = match *bound {
@@ -4386,34 +4398,45 @@ fn iter_bound_traits_and_supertraits(tcx: ctxt,
43864398
}
43874399
};
43884400

4389-
let mut worklist = ~[];
4390-
4391-
let init_trait_ty = bound_trait_ty;
4392-
4393-
worklist.push(init_trait_ty);
4394-
4401+
let mut supertrait_map = HashMap();
4402+
let mut seen_def_ids = ~[];
43954403
let mut i = 0;
4396-
while i < worklist.len() {
4397-
let init_trait_ty = worklist[i];
4398-
i += 1;
4399-
4400-
let init_trait_id = match ty_to_def_id(init_trait_ty) {
4401-
Some(id) => id,
4402-
None => tcx.sess.bug(
4403-
~"trait type should have def_id")
4404-
};
4405-
4406-
// Add supertraits to worklist
4407-
let supertraits = trait_supertraits(tcx,
4408-
init_trait_id);
4409-
for supertraits.each |supertrait| {
4410-
worklist.push(supertrait.tpt.ty);
4411-
}
4412-
4413-
if !f(init_trait_ty) {
4414-
return;
4404+
let trait_ty_id = ty_to_def_id(bound_trait_ty).expect(
4405+
~"iter_trait_ty_supertraits got a non-trait type");
4406+
let mut trait_ty = bound_trait_ty;
4407+
4408+
debug!("iter_bound_traits_and_supertraits: trait_ty = %s",
4409+
ty_to_str(tcx, trait_ty));
4410+
4411+
// Add the given trait ty to the hash map
4412+
supertrait_map.insert(trait_ty_id, trait_ty);
4413+
seen_def_ids.push(trait_ty_id);
4414+
4415+
if f(trait_ty) {
4416+
// Add all the supertraits to the hash map,
4417+
// executing <f> on each of them
4418+
while i < supertrait_map.size() && !fin {
4419+
let init_trait_id = seen_def_ids[i];
4420+
i += 1;
4421+
// Add supertraits to supertrait_map
4422+
let supertraits = trait_supertraits(tcx, init_trait_id);
4423+
for supertraits.each |supertrait| {
4424+
let super_t = supertrait.tpt.ty;
4425+
let d_id = ty_to_def_id(super_t).expect("supertrait \
4426+
should be a trait ty");
4427+
if !supertrait_map.contains_key(d_id) {
4428+
supertrait_map.insert(d_id, super_t);
4429+
trait_ty = super_t;
4430+
seen_def_ids.push(d_id);
4431+
}
4432+
debug!("A super_t = %s", ty_to_str(tcx, trait_ty));
4433+
if !f(trait_ty) {
4434+
fin = true;
4435+
}
4436+
}
44154437
}
4416-
}
4438+
};
4439+
fin = false;
44174440
}
44184441
}
44194442

@@ -4428,6 +4451,22 @@ fn count_traits_and_supertraits(tcx: ctxt,
44284451
return total;
44294452
}
44304453

4454+
// Given a trait and a type, returns the impl of that type
4455+
fn get_impl_id(tcx: ctxt, trait_id: def_id, self_ty: t) -> def_id {
4456+
match tcx.trait_impls.find(trait_id) {
4457+
Some(ty_to_impl) => match ty_to_impl.find(self_ty) {
4458+
Some(the_impl) => the_impl.did,
4459+
None => // try autoderef!
4460+
match deref(tcx, self_ty, false) {
4461+
Some(some_ty) => get_impl_id(tcx, trait_id, some_ty.ty),
4462+
None => tcx.sess.bug(~"get_impl_id: no impl of trait for \
4463+
this type")
4464+
}
4465+
},
4466+
None => tcx.sess.bug(~"get_impl_id: trait isn't in trait_impls")
4467+
}
4468+
}
4469+
44314470
impl mt : cmp::Eq {
44324471
pure fn eq(&self, other: &mt) -> bool {
44334472
(*self).ty == (*other).ty && (*self).mutbl == (*other).mutbl

0 commit comments

Comments
 (0)