Skip to content

Commit

Permalink
Default methods in traits get through typeck.
Browse files Browse the repository at this point in the history
  • Loading branch information
lkuper committed Aug 8, 2012
1 parent c8bad36 commit 293f371
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 19 deletions.
8 changes: 8 additions & 0 deletions src/rustc/middle/typeck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export vtable_res;
export vtable_origin;
export method_static, method_param, method_trait;
export vtable_static, vtable_param, vtable_trait;
export provided_methods_map;

#[auto_serialize]
enum method_origin {
Expand Down Expand Up @@ -152,6 +153,11 @@ enum vtable_origin {
type vtable_map = hashmap<ast::node_id, vtable_res>;

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

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

Expand All @@ -160,6 +166,7 @@ type crate_ctxt_ = {impl_map: resolve3::ImplMap,
method_map: method_map,
vtable_map: vtable_map,
coherence_info: @coherence::CoherenceInfo,
provided_methods_map: provided_methods_map,
tcx: ty::ctxt};

enum crate_ctxt {
Expand Down Expand Up @@ -302,6 +309,7 @@ fn check_crate(tcx: ty::ctxt,
method_map: std::map::int_hash(),
vtable_map: std::map::int_hash(),
coherence_info: @coherence::CoherenceInfo(),
provided_methods_map: std::map::int_hash(),
tcx: tcx});
collect::collect_item_types(ccx, crate);
coherence::check_coherence(ccx, crate);
Expand Down
169 changes: 150 additions & 19 deletions src/rustc/middle/typeck/coherence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import metadata::csearch::{each_path, get_impl_traits, get_impls_for_mod};
import metadata::cstore::{cstore, iter_crate_data};
import metadata::decoder::{dl_def, dl_field, dl_impl};
import middle::resolve3::Impl;
import middle::resolve3::{Impl, MethodInfo};
import middle::ty::{get, lookup_item_type, subst, t, ty_box};
import middle::ty::{ty_uniq, ty_ptr, ty_rptr, ty_enum};
import middle::ty::{ty_class, ty_nil, ty_bot, ty_bool, ty_int, ty_uint};
Expand Down Expand Up @@ -108,6 +108,16 @@ fn get_base_type_def_id(inference_context: infer_ctxt,
}
}


fn method_to_MethodInfo(ast_method: @method) -> @MethodInfo {
@{
did: local_def(ast_method.id),
n_tps: ast_method.tps.len(),
ident: ast_method.ident,
self_type: ast_method.self_ty.node
}
}

class CoherenceInfo {
// Contains implementations of methods that are inherent to a type.
// Methods in these implementations don't need to be exported.
Expand Down Expand Up @@ -151,10 +161,70 @@ class CoherenceChecker {
self.privileged_types = new_def_hash();
}

// Create a mapping containing a MethodInfo for every provided
// method in every trait.
fn build_provided_methods_map(crate: @crate) {

let pmm = self.crate_context.provided_methods_map;

visit_crate(*crate, (), mk_simple_visitor(@{
visit_item: |item| {
match item.node {
item_trait(_, _, trait_methods) => {
for trait_methods.each |trait_method| {
debug!{"(building provided methods map) checking \
trait `%s` with id %d", *item.ident, item.id};

match trait_method {
required(_) => { /* fall through */}
provided(m) => {
// For every provided method in the
// trait, store a MethodInfo.
let mi = method_to_MethodInfo(m);

match pmm.find(item.id) {
some(mis) => {
// If the trait already has an
// entry in the
// provided_methods_map, we just
// need to add this method to
// that entry.
debug!{"(building provided \
methods map) adding \
method `%s` to entry for \
existing trait",
*mi.ident};
let mut method_infos = mis;
push(method_infos, mi);
pmm.insert(item.id, method_infos);
}
none => {
// If the trait doesn't have an
// entry yet, create one.
debug!{"(building provided \
methods map) creating new \
entry for method `%s`",
*mi.ident};
pmm.insert(item.id, ~[mi]);
}
}
}
}
}
}
_ => {
// Nothing to do.
}
};
}
with *default_simple_visitor()
}));
}

fn check_coherence(crate: @crate) {

// Check implementations. This populates the tables containing the
// inherent methods and extension methods.

visit_crate(*crate, (), mk_simple_visitor(@{
visit_item: |item| {
debug!{"(checking coherence) item '%s'", *item.ident};
Expand Down Expand Up @@ -430,15 +500,13 @@ class CoherenceChecker {
// trait was defined in this
// crate.

let def_map = self.crate_context.tcx
.def_map;
let trait_def = def_map.get
(trait_ref.ref_id);
let trait_id =
def_id_of_def(trait_def);
if trait_id.crate != local_crate {
let session = self.crate_context
.tcx.sess;
let trait_def_id =
self.trait_ref_to_trait_def_id(
trait_ref);

if trait_def_id.crate != local_crate {
let session =
self.crate_context.tcx.sess;
session.span_err(item.span,
~"cannot \
provide an \
Expand Down Expand Up @@ -466,6 +534,13 @@ class CoherenceChecker {
}));
}
fn trait_ref_to_trait_def_id(trait_ref: @trait_ref) -> def_id {
let def_map = self.crate_context.tcx.def_map;
let trait_def = def_map.get(trait_ref.ref_id);
let trait_id = def_id_of_def(trait_def);
return trait_id;
}
fn gather_privileged_types(items: ~[@item]) -> @dvec<def_id> {
let results = @dvec();
for items.each |item| {
Expand All @@ -487,16 +562,70 @@ class CoherenceChecker {
// Converts an implementation in the AST to an Impl structure.
fn create_impl_from_item(item: @item) -> @Impl {
fn add_provided_methods(inherent_methods: ~[@MethodInfo],
all_provided_methods: ~[@MethodInfo])
-> ~[@MethodInfo] {
let mut methods = inherent_methods;
// If there's no inherent method with the same name as a
// provided method, add that provided method to `methods`.
for all_provided_methods.each |provided_method| {
let mut method_inherent_to_impl = false;
for inherent_methods.each |inherent_method| {
if provided_method.ident == inherent_method.ident {
method_inherent_to_impl = true;
}
}
if !method_inherent_to_impl {
debug!{"(creating impl) adding provided method `%s` to \
impl", *provided_method.ident};
push(methods, provided_method);
}
}

return methods;
}

match item.node {
item_impl(ty_params, _, _, ast_methods) => {
item_impl(ty_params, trait_refs, _, ast_methods) => {
let mut methods = ~[];

for ast_methods.each |ast_method| {
push(methods, @{
did: local_def(ast_method.id),
n_tps: ast_method.tps.len(),
ident: ast_method.ident,
self_type: ast_method.self_ty.node
});
push(methods,
method_to_MethodInfo(ast_method));
}

// For each trait that the impl implements, see what
// methods are provided. For each of those methods,
// if a method of that name is not inherent to the
// impl, use the provided definition in the trait.
for trait_refs.each |trait_ref| {

let trait_did = self.trait_ref_to_trait_def_id(trait_ref);

match self.crate_context.provided_methods_map
.find(trait_did.node) {
none => {
debug!{"(creating impl) trait with node_id `%d` \
has no provided methods", trait_did.node};
/* fall through */
}
some(all_provided)
=> {
debug!{"(creating impl) trait with node_id `%d` \
has provided methods", trait_did.node};
// Selectively add only those provided
// methods that aren't inherent to the
// trait.

// XXX: could probably be doing this with filter.
methods = add_provided_methods(methods,
all_provided);
}
}
}

return @{
Expand Down Expand Up @@ -669,6 +798,8 @@ class CoherenceChecker {
}

fn check_coherence(crate_context: @crate_ctxt, crate: @crate) {
CoherenceChecker(crate_context).check_coherence(crate);
let coherence_checker = @CoherenceChecker(crate_context);
(*coherence_checker).build_provided_methods_map(crate);
(*coherence_checker).check_coherence(crate);
}

0 comments on commit 293f371

Please sign in to comment.