Skip to content

Commit 293f371

Browse files
committedAug 8, 2012
Default methods in traits get through typeck.
1 parent c8bad36 commit 293f371

File tree

2 files changed

+158
-19
lines changed

2 files changed

+158
-19
lines changed
 

‎src/rustc/middle/typeck.rs

+8
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ export vtable_res;
7979
export vtable_origin;
8080
export method_static, method_param, method_trait;
8181
export vtable_static, vtable_param, vtable_trait;
82+
export provided_methods_map;
8283

8384
#[auto_serialize]
8485
enum method_origin {
@@ -152,6 +153,11 @@ enum vtable_origin {
152153
type vtable_map = hashmap<ast::node_id, vtable_res>;
153154

154155
type ty_param_substs_and_ty = {substs: ty::substs, ty: ty::t};
156+
// Stores information about provided methods, aka "default methods" in traits.
157+
// Maps from a trait's def_id to a MethodInfo about
158+
// that method in that trait.
159+
type provided_methods_map = hashmap<ast::node_id,
160+
~[@resolve3::MethodInfo]>;
155161

156162
type ty_table = hashmap<ast::def_id, ty::t>;
157163

@@ -160,6 +166,7 @@ type crate_ctxt_ = {impl_map: resolve3::ImplMap,
160166
method_map: method_map,
161167
vtable_map: vtable_map,
162168
coherence_info: @coherence::CoherenceInfo,
169+
provided_methods_map: provided_methods_map,
163170
tcx: ty::ctxt};
164171

165172
enum crate_ctxt {
@@ -302,6 +309,7 @@ fn check_crate(tcx: ty::ctxt,
302309
method_map: std::map::int_hash(),
303310
vtable_map: std::map::int_hash(),
304311
coherence_info: @coherence::CoherenceInfo(),
312+
provided_methods_map: std::map::int_hash(),
305313
tcx: tcx});
306314
collect::collect_item_types(ccx, crate);
307315
coherence::check_coherence(ccx, crate);

‎src/rustc/middle/typeck/coherence.rs

+150-19
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import metadata::csearch::{each_path, get_impl_traits, get_impls_for_mod};
88
import metadata::cstore::{cstore, iter_crate_data};
99
import metadata::decoder::{dl_def, dl_field, dl_impl};
10-
import middle::resolve3::Impl;
10+
import middle::resolve3::{Impl, MethodInfo};
1111
import middle::ty::{get, lookup_item_type, subst, t, ty_box};
1212
import middle::ty::{ty_uniq, ty_ptr, ty_rptr, ty_enum};
1313
import middle::ty::{ty_class, ty_nil, ty_bot, ty_bool, ty_int, ty_uint};
@@ -108,6 +108,16 @@ fn get_base_type_def_id(inference_context: infer_ctxt,
108108
}
109109
}
110110

111+
112+
fn method_to_MethodInfo(ast_method: @method) -> @MethodInfo {
113+
@{
114+
did: local_def(ast_method.id),
115+
n_tps: ast_method.tps.len(),
116+
ident: ast_method.ident,
117+
self_type: ast_method.self_ty.node
118+
}
119+
}
120+
111121
class CoherenceInfo {
112122
// Contains implementations of methods that are inherent to a type.
113123
// Methods in these implementations don't need to be exported.
@@ -151,10 +161,70 @@ class CoherenceChecker {
151161
self.privileged_types = new_def_hash();
152162
}
153163

164+
// Create a mapping containing a MethodInfo for every provided
165+
// method in every trait.
166+
fn build_provided_methods_map(crate: @crate) {
167+
168+
let pmm = self.crate_context.provided_methods_map;
169+
170+
visit_crate(*crate, (), mk_simple_visitor(@{
171+
visit_item: |item| {
172+
match item.node {
173+
item_trait(_, _, trait_methods) => {
174+
for trait_methods.each |trait_method| {
175+
debug!{"(building provided methods map) checking \
176+
trait `%s` with id %d", *item.ident, item.id};
177+
178+
match trait_method {
179+
required(_) => { /* fall through */}
180+
provided(m) => {
181+
// For every provided method in the
182+
// trait, store a MethodInfo.
183+
let mi = method_to_MethodInfo(m);
184+
185+
match pmm.find(item.id) {
186+
some(mis) => {
187+
// If the trait already has an
188+
// entry in the
189+
// provided_methods_map, we just
190+
// need to add this method to
191+
// that entry.
192+
debug!{"(building provided \
193+
methods map) adding \
194+
method `%s` to entry for \
195+
existing trait",
196+
*mi.ident};
197+
let mut method_infos = mis;
198+
push(method_infos, mi);
199+
pmm.insert(item.id, method_infos);
200+
}
201+
none => {
202+
// If the trait doesn't have an
203+
// entry yet, create one.
204+
debug!{"(building provided \
205+
methods map) creating new \
206+
entry for method `%s`",
207+
*mi.ident};
208+
pmm.insert(item.id, ~[mi]);
209+
}
210+
}
211+
}
212+
}
213+
}
214+
}
215+
_ => {
216+
// Nothing to do.
217+
}
218+
};
219+
}
220+
with *default_simple_visitor()
221+
}));
222+
}
223+
154224
fn check_coherence(crate: @crate) {
225+
155226
// Check implementations. This populates the tables containing the
156227
// inherent methods and extension methods.
157-
158228
visit_crate(*crate, (), mk_simple_visitor(@{
159229
visit_item: |item| {
160230
debug!{"(checking coherence) item '%s'", *item.ident};
@@ -430,15 +500,13 @@ class CoherenceChecker {
430500
// trait was defined in this
431501
// crate.
432502

433-
let def_map = self.crate_context.tcx
434-
.def_map;
435-
let trait_def = def_map.get
436-
(trait_ref.ref_id);
437-
let trait_id =
438-
def_id_of_def(trait_def);
439-
if trait_id.crate != local_crate {
440-
let session = self.crate_context
441-
.tcx.sess;
503+
let trait_def_id =
504+
self.trait_ref_to_trait_def_id(
505+
trait_ref);
506+
507+
if trait_def_id.crate != local_crate {
508+
let session =
509+
self.crate_context.tcx.sess;
442510
session.span_err(item.span,
443511
~"cannot \
444512
provide an \
@@ -466,6 +534,13 @@ class CoherenceChecker {
466534
}));
467535
}
468536
537+
fn trait_ref_to_trait_def_id(trait_ref: @trait_ref) -> def_id {
538+
let def_map = self.crate_context.tcx.def_map;
539+
let trait_def = def_map.get(trait_ref.ref_id);
540+
let trait_id = def_id_of_def(trait_def);
541+
return trait_id;
542+
}
543+
469544
fn gather_privileged_types(items: ~[@item]) -> @dvec<def_id> {
470545
let results = @dvec();
471546
for items.each |item| {
@@ -487,16 +562,70 @@ class CoherenceChecker {
487562
488563
// Converts an implementation in the AST to an Impl structure.
489564
fn create_impl_from_item(item: @item) -> @Impl {
565+
566+
fn add_provided_methods(inherent_methods: ~[@MethodInfo],
567+
all_provided_methods: ~[@MethodInfo])
568+
-> ~[@MethodInfo] {
569+
570+
let mut methods = inherent_methods;
571+
572+
// If there's no inherent method with the same name as a
573+
// provided method, add that provided method to `methods`.
574+
for all_provided_methods.each |provided_method| {
575+
let mut method_inherent_to_impl = false;
576+
for inherent_methods.each |inherent_method| {
577+
if provided_method.ident == inherent_method.ident {
578+
method_inherent_to_impl = true;
579+
}
580+
}
581+
582+
if !method_inherent_to_impl {
583+
debug!{"(creating impl) adding provided method `%s` to \
584+
impl", *provided_method.ident};
585+
push(methods, provided_method);
586+
}
587+
}
588+
589+
return methods;
590+
}
591+
490592
match item.node {
491-
item_impl(ty_params, _, _, ast_methods) => {
593+
item_impl(ty_params, trait_refs, _, ast_methods) => {
492594
let mut methods = ~[];
595+
493596
for ast_methods.each |ast_method| {
494-
push(methods, @{
495-
did: local_def(ast_method.id),
496-
n_tps: ast_method.tps.len(),
497-
ident: ast_method.ident,
498-
self_type: ast_method.self_ty.node
499-
});
597+
push(methods,
598+
method_to_MethodInfo(ast_method));
599+
}
600+
601+
// For each trait that the impl implements, see what
602+
// methods are provided. For each of those methods,
603+
// if a method of that name is not inherent to the
604+
// impl, use the provided definition in the trait.
605+
for trait_refs.each |trait_ref| {
606+
607+
let trait_did = self.trait_ref_to_trait_def_id(trait_ref);
608+
609+
match self.crate_context.provided_methods_map
610+
.find(trait_did.node) {
611+
none => {
612+
debug!{"(creating impl) trait with node_id `%d` \
613+
has no provided methods", trait_did.node};
614+
/* fall through */
615+
}
616+
some(all_provided)
617+
=> {
618+
debug!{"(creating impl) trait with node_id `%d` \
619+
has provided methods", trait_did.node};
620+
// Selectively add only those provided
621+
// methods that aren't inherent to the
622+
// trait.
623+
624+
// XXX: could probably be doing this with filter.
625+
methods = add_provided_methods(methods,
626+
all_provided);
627+
}
628+
}
500629
}
501630

502631
return @{
@@ -669,6 +798,8 @@ class CoherenceChecker {
669798
}
670799

671800
fn check_coherence(crate_context: @crate_ctxt, crate: @crate) {
672-
CoherenceChecker(crate_context).check_coherence(crate);
801+
let coherence_checker = @CoherenceChecker(crate_context);
802+
(*coherence_checker).build_provided_methods_map(crate);
803+
(*coherence_checker).check_coherence(crate);
673804
}
674805

0 commit comments

Comments
 (0)