Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle supertrait calls in default methods #4537

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions src/librustc/middle/astencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,7 @@ impl method_origin: tr {
fn tr(xcx: extended_decode_ctxt) -> method_origin {
match self {
typeck::method_static(did) => {
typeck::method_static(did.tr(xcx))
typeck::method_static(did.tr(xcx))
}
typeck::method_param(ref mp) => {
typeck::method_param(
Expand All @@ -573,10 +573,13 @@ impl method_origin: tr {
)
}
typeck::method_trait(did, m, vstore) => {
typeck::method_trait(did.tr(xcx), m, vstore)
typeck::method_trait(did.tr(xcx), m, vstore)
}
typeck::method_self(did, m) => {
typeck::method_self(did.tr(xcx), m)
typeck::method_self(did.tr(xcx), m)
}
typeck::method_super(trait_did, m) => {
typeck::method_super(trait_did.tr(xcx), m)
}
}
}
Expand Down
6 changes: 4 additions & 2 deletions src/librustc/middle/privacy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ use core::prelude::*;

use middle::ty::{ty_struct, ty_enum};
use middle::ty;
use middle::typeck::{method_map, method_origin, method_param, method_self};
use middle::typeck::{method_map, method_origin, method_param, method_self,
method_super};
use middle::typeck::{method_static, method_trait};

use core::dvec::DVec;
Expand Down Expand Up @@ -138,7 +139,8 @@ fn check_crate(tcx: ty::ctxt, method_map: &method_map, crate: @ast::crate) {
_
}) |
method_trait(trait_id, method_num, _) |
method_self(trait_id, method_num) => {
method_self(trait_id, method_num) |
method_super(trait_id, method_num) => {
if trait_id.crate == local_crate {
match tcx.items.find(trait_id.node) {
Some(node_item(item, _)) => {
Expand Down
27 changes: 25 additions & 2 deletions src/librustc/middle/trans/meth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,29 @@ fn trans_method_callee(bcx: block, callee_id: ast::node_id,
method_name);
origin = typeck::method_static(method_id);
}
typeck::method_super(trait_id, method_index) => {
// <self_ty> is the self type for this method call
let self_ty = node_id_type(bcx, self.id);
let tcx = bcx.tcx();
// <impl_id> is the ID of the implementation of
// trait <trait_id> for type <self_ty>
let impl_id = ty::get_impl_id(tcx, trait_id, self_ty);
// Get the supertrait's methods
let supertrait_methods = ty::trait_methods(tcx, trait_id);
// Make sure to fail with a readable error message if
// there's some internal error here
if !(method_index < supertrait_methods.len()) {
tcx.sess.bug(~"trans_method_callee: supertrait method \
index is out of bounds");
}
// Get the method name using the method index in the origin
let method_name = supertrait_methods[method_index].ident;
// Now that we know the impl ID, we can look up the method
// ID from its name
origin = typeck::method_static(method_with_name(bcx.ccx(),
impl_id,
method_name));
}
typeck::method_static(*) | typeck::method_param(*) |
typeck::method_trait(*) => {}
}
Expand Down Expand Up @@ -233,8 +256,8 @@ fn trans_method_callee(bcx: block, callee_id: ast::node_id,
vstore,
mentry.explicit_self)
}
typeck::method_self(*) => {
fail ~"method_self should have been handled above"
typeck::method_self(*) | typeck::method_super(*) => {
fail ~"method_self or method_super should have been handled above"
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/trans/monomorphize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ fn make_mono_id(ccx: @crate_ctxt, item: ast::def_id, substs: ~[ty::t],
let precise_param_ids = match vtables {
Some(vts) => {
let bounds = ty::lookup_item_type(ccx.tcx, item).bounds;
let mut i = 0u;
let mut i = 0;
vec::map2(*bounds, substs, |bounds, subst| {
let mut v = ~[];
for bounds.each |bound| {
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/trans/type_use.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,8 @@ fn mark_for_method_call(cx: ctx, e_id: node_id, callee_id: node_id) {
}) => {
cx.uses[param] |= use_tydesc;
}
typeck::method_trait(*) | typeck::method_self(*) => (),
typeck::method_trait(*) | typeck::method_self(*)
| typeck::method_super(*) => (),
}
}
}
Expand Down
95 changes: 67 additions & 28 deletions src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ export AutoRef;
export AutoRefKind, AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn;
export iter_bound_traits_and_supertraits;
export count_traits_and_supertraits;
export get_impl_id;

// Data types

Expand Down Expand Up @@ -471,6 +472,9 @@ type ctxt =

// Records the value mode (read, copy, or move) for every value.
value_modes: HashMap<ast::node_id, ValueMode>,

// Maps a trait onto a mapping from self-ty to impl
trait_impls: HashMap<ast::def_id, HashMap<t, @Impl>>
};

enum tbox_flag {
Expand Down Expand Up @@ -1023,7 +1027,9 @@ fn mk_ctxt(s: session::Session,
supertraits: HashMap(),
destructor_for_type: HashMap(),
destructors: HashMap(),
value_modes: HashMap()}
value_modes: HashMap(),
trait_impls: HashMap()
}
}


Expand Down Expand Up @@ -3090,7 +3096,8 @@ fn method_call_bounds(tcx: ctxt, method_map: typeck::method_map,
trait_id: trt_id,
method_num: n_mth, _}) |
typeck::method_trait(trt_id, n_mth, _) |
typeck::method_self(trt_id, n_mth) => {
typeck::method_self(trt_id, n_mth) |
typeck::method_super(trt_id, n_mth) => {
// ...trait methods bounds, in contrast, include only the
// method bounds, so we must preprend the tps from the
// trait itself. This ought to be harmonized.
Expand Down Expand Up @@ -4329,9 +4336,14 @@ pure fn determine_inherited_purity(parent_purity: ast::purity,

// Iterate over a type parameter's bounded traits and any supertraits
// of those traits, ignoring kinds.
// Here, the supertraits are the transitive closure of the supertrait
// relation on the supertraits from each bounded trait's constraint
// list.
fn iter_bound_traits_and_supertraits(tcx: ctxt,
bounds: param_bounds,
f: &fn(t) -> bool) {
let mut fin = false;

for bounds.each |bound| {

let bound_trait_ty = match *bound {
Expand All @@ -4343,34 +4355,45 @@ fn iter_bound_traits_and_supertraits(tcx: ctxt,
}
};

let mut worklist = ~[];

let init_trait_ty = bound_trait_ty;

worklist.push(init_trait_ty);

let mut supertrait_map = HashMap();
let mut seen_def_ids = ~[];
let mut i = 0;
while i < worklist.len() {
let init_trait_ty = worklist[i];
i += 1;

let init_trait_id = match ty_to_def_id(init_trait_ty) {
Some(id) => id,
None => tcx.sess.bug(
~"trait type should have def_id")
};

// Add supertraits to worklist
let supertraits = trait_supertraits(tcx,
init_trait_id);
for supertraits.each |supertrait| {
worklist.push(supertrait.tpt.ty);
}

if !f(init_trait_ty) {
return;
let trait_ty_id = ty_to_def_id(bound_trait_ty).expect(
~"iter_trait_ty_supertraits got a non-trait type");
let mut trait_ty = bound_trait_ty;

debug!("iter_bound_traits_and_supertraits: trait_ty = %s",
ty_to_str(tcx, trait_ty));

// Add the given trait ty to the hash map
supertrait_map.insert(trait_ty_id, trait_ty);
seen_def_ids.push(trait_ty_id);

if f(trait_ty) {
// Add all the supertraits to the hash map,
// executing <f> on each of them
while i < supertrait_map.size() && !fin {
let init_trait_id = seen_def_ids[i];
i += 1;
// Add supertraits to supertrait_map
let supertraits = trait_supertraits(tcx, init_trait_id);
for supertraits.each |supertrait| {
let super_t = supertrait.tpt.ty;
let d_id = ty_to_def_id(super_t).expect("supertrait \
should be a trait ty");
if !supertrait_map.contains_key(d_id) {
supertrait_map.insert(d_id, super_t);
trait_ty = super_t;
seen_def_ids.push(d_id);
}
debug!("A super_t = %s", ty_to_str(tcx, trait_ty));
if !f(trait_ty) {
fin = true;
}
}
}
}
};
fin = false;
}
}

Expand All @@ -4385,6 +4408,22 @@ fn count_traits_and_supertraits(tcx: ctxt,
return total;
}

// Given a trait and a type, returns the impl of that type
fn get_impl_id(tcx: ctxt, trait_id: def_id, self_ty: t) -> def_id {
match tcx.trait_impls.find(trait_id) {
Some(ty_to_impl) => match ty_to_impl.find(self_ty) {
Some(the_impl) => the_impl.did,
None => // try autoderef!
match deref(tcx, self_ty, false) {
Some(some_ty) => get_impl_id(tcx, trait_id, some_ty.ty),
None => tcx.sess.bug(~"get_impl_id: no impl of trait for \
this type")
}
},
None => tcx.sess.bug(~"get_impl_id: trait isn't in trait_impls")
}
}

impl mt : cmp::Eq {
pure fn eq(&self, other: &mt) -> bool {
(*self).ty == (*other).ty && (*self).mutbl == (*other).mutbl
Expand Down
92 changes: 66 additions & 26 deletions src/librustc/middle/typeck/check/method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ use middle::typeck::check;
use middle::typeck::coherence::get_base_type_def_id;
use middle::typeck::infer;
use middle::typeck::{method_map_entry, method_origin, method_param};
use middle::typeck::{method_self, method_static, method_trait};
use middle::typeck::{method_self, method_static, method_trait, method_super};
use util::common::indenter;
use util::ppaux::expr_repr;

Expand Down Expand Up @@ -529,30 +529,66 @@ impl LookupContext {
did: def_id,
substs: &ty::substs) {
let tcx = self.tcx();
let methods = ty::trait_methods(tcx, did); // XXX: Inherited methods.
let index;
// First, try self methods
let mut method = None;
let methods = ty::trait_methods(tcx, did);
let mut index = None;
let mut trait_did = None;
match vec::position(*methods, |m| m.ident == self.m_name) {
Some(i) => index = i,
None => return
Some(i) => {
index = Some(i);
trait_did = Some(did);
method = Some((methods[i].self_ty, methods[i].tps.len()));
}
None => ()
}
let method = &methods[index];

let rcvr_substs = { self_ty: Some(self_ty), ../*bad*/copy *substs };
let (rcvr_ty, rcvr_substs) =
self.create_rcvr_ty_and_substs_for_method(
method.self_ty,
self_ty,
move rcvr_substs,
TransformTypeNormally);
// No method found yet? Check each supertrait
if method.is_none() {
for ty::trait_supertraits(tcx, did).each() |trait_ref| {
let supertrait_methods =
ty::trait_methods(tcx, trait_ref.def_id);
match vec::position(*supertrait_methods,
|m| m.ident == self.m_name) {
Some(i) => {
index = Some(i);
trait_did = Some(trait_ref.def_id);
method = Some((supertrait_methods[i].self_ty,
supertrait_methods[i].tps.len()));
break;
}
None => ()
}
}
}
match (method, index, trait_did) {
(Some((method_self_ty, method_num_tps)),
Some(index), Some(trait_did)) => {

self.inherent_candidates.push(Candidate {
rcvr_ty: rcvr_ty,
rcvr_substs: move rcvr_substs,
explicit_self: method.self_ty,
num_method_tps: method.tps.len(),
self_mode: get_mode_from_self_type(method.self_ty),
origin: method_self(did, index)
});
// We've found a method -- return it
let rcvr_substs = { self_ty: Some(self_ty), ..copy *substs };
let (rcvr_ty, rcvr_substs) =
self.create_rcvr_ty_and_substs_for_method(
method_self_ty,
self_ty,
move rcvr_substs,
TransformTypeNormally);
let origin = if trait_did == did {
method_self(trait_did, index)
}
else {
method_super(trait_did, index)
};
self.inherent_candidates.push(Candidate {
rcvr_ty: rcvr_ty,
rcvr_substs: move rcvr_substs,
explicit_self: method_self_ty,
num_method_tps: method_num_tps,
self_mode: get_mode_from_self_type(method_self_ty),
origin: origin
});
}
_ => return
}
}

fn push_inherent_impl_candidates_for_type(did: def_id) {
Expand Down Expand Up @@ -1034,7 +1070,8 @@ impl LookupContext {
* vtable and hence cannot be monomorphized. */

match candidate.origin {
method_static(*) | method_param(*) | method_self(*) => {
method_static(*) | method_param(*) |
method_self(*) | method_super(*) => {
return; // not a call to a trait instance
}
method_trait(*) => {}
Expand All @@ -1058,7 +1095,8 @@ impl LookupContext {
// No code can call the finalize method explicitly.
let bad;
match candidate.origin {
method_static(method_id) | method_self(method_id, _) => {
method_static(method_id) | method_self(method_id, _)
| method_super(method_id, _) => {
bad = self.tcx().destructors.contains_key(method_id);
}
method_param(method_param { trait_id: trait_id, _ }) |
Expand Down Expand Up @@ -1088,7 +1126,8 @@ impl LookupContext {
method_param(ref mp) => {
type_of_trait_method(self.tcx(), mp.trait_id, mp.method_num)
}
method_trait(did, idx, _) | method_self(did, idx) => {
method_trait(did, idx, _) | method_self(did, idx) |
method_super(did, idx) => {
type_of_trait_method(self.tcx(), did, idx)
}
};
Expand All @@ -1109,7 +1148,8 @@ impl LookupContext {
method_param(ref mp) => {
self.report_param_candidate(idx, (*mp).trait_id)
}
method_trait(trait_did, _, _) | method_self(trait_did, _) => {
method_trait(trait_did, _, _) | method_self(trait_did, _)
| method_super(trait_did, _) => {
self.report_param_candidate(idx, trait_did)
}
}
Expand Down
Loading