rustc: Make coherence aware of multiple-traits-per-impl

This commit is contained in:
Patrick Walton 2012-07-18 17:07:56 -07:00
parent 5506bf1480
commit 635a959363

View file

@ -111,6 +111,7 @@ fn get_base_type_def_id(inference_context: infer_ctxt,
class CoherenceInfo { class CoherenceInfo {
// Contains implementations of methods that are inherent to a type. // Contains implementations of methods that are inherent to a type.
// Methods in these implementations don't need to be exported. // Methods in these implementations don't need to be exported.
let inherent_methods: hashmap<def_id,@dvec<@Impl>>; let inherent_methods: hashmap<def_id,@dvec<@Impl>>;
// Contains implementations of methods associated with a trait. For these, // Contains implementations of methods associated with a trait. For these,
@ -129,14 +130,17 @@ class CoherenceChecker {
// A mapping from implementations to the corresponding base type // A mapping from implementations to the corresponding base type
// definition ID. // definition ID.
let base_type_def_ids: hashmap<def_id,def_id>; let base_type_def_ids: hashmap<def_id,def_id>;
// A set of implementations in privileged scopes; i.e. those // A set of implementations in privileged scopes; i.e. those
// implementations that are defined in the same scope as their base types. // implementations that are defined in the same scope as their base types.
let privileged_implementations: hashmap<node_id,()>; let privileged_implementations: hashmap<node_id,()>;
// The set of types that we are currently in the privileged scope of. This // The set of types that we are currently in the privileged scope of. This
// is used while we traverse the AST while checking privileged scopes. // is used while we traverse the AST while checking privileged scopes.
let privileged_types: hashmap<def_id,()>; let privileged_types: hashmap<def_id,()>;
new(crate_context: @crate_ctxt) { new(crate_context: @crate_ctxt) {
@ -158,17 +162,7 @@ class CoherenceChecker {
alt item.node { alt item.node {
item_impl(_, associated_traits, self_type, _) { item_impl(_, associated_traits, self_type, _) {
// XXX: Accept an array of traits. self.check_implementation(item, associated_traits);
let optional_associated_trait;
if associated_traits.len() == 0 {
optional_associated_trait = none;
} else {
optional_associated_trait =
some(associated_traits[0]);
}
self.check_implementation(item,
optional_associated_trait);
} }
_ { _ {
// Nothing to do. // Nothing to do.
@ -195,47 +189,49 @@ class CoherenceChecker {
self.add_external_crates(); self.add_external_crates();
} }
fn check_implementation(item: @item, fn check_implementation(item: @item, associated_traits: ~[@trait_ref]) {
optional_associated_trait: option<@trait_ref>) {
let self_type = self.crate_context.tcx.tcache.get(local_def(item.id)); let self_type = self.crate_context.tcx.tcache.get(local_def(item.id));
alt optional_associated_trait {
none {
#debug("(checking implementation) no associated trait for \
item '%s'",
*item.ident);
alt get_base_type_def_id(self.inference_context, // If there are no traits, then this implementation must have a
item.span, // base type.
self_type.ty) {
none { if associated_traits.len() == 0 {
let session = self.crate_context.tcx.sess; #debug("(checking implementation) no associated traits for item \
session.span_err(item.span, '%s'",
~"no base type found for inherent \ *item.ident);
implementation; implement a \
trait instead"); alt get_base_type_def_id(self.inference_context,
} item.span,
some(_) { self_type.ty) {
// Nothing to do. none {
} let session = self.crate_context.tcx.sess;
session.span_err(item.span,
~"no base type found for inherent \
implementation; implement a \
trait instead");
}
some(_) {
// Nothing to do.
} }
} }
some(associated_trait) { }
let def = self.crate_context.tcx.def_map.get
(associated_trait.ref_id);
#debug("(checking implementation) adding impl for trait \
'%s', item '%s'",
ast_map::node_id_to_str(self.crate_context.tcx.items,
associated_trait.ref_id),
*item.ident);
let implementation = self.create_impl_from_item(item); for associated_traits.each |associated_trait| {
self.add_trait_method(def_id_of_def(def), implementation); let def = self.crate_context.tcx.def_map.get
} (associated_trait.ref_id);
#debug("(checking implementation) adding impl for trait \
'%s', item '%s'",
ast_map::node_id_to_str(self.crate_context.tcx.items,
associated_trait.ref_id),
*item.ident);
let implementation = self.create_impl_from_item(item);
self.add_trait_method(def_id_of_def(def), implementation);
} }
// Add the implementation to the mapping from implementation to base // Add the implementation to the mapping from implementation to base
// type def ID, if there is a base type for this implementation. // type def ID, if there is a base type for this implementation.
alt get_base_type_def_id(self.inference_context, alt get_base_type_def_id(self.inference_context,
item.span, item.span,
self_type.ty) { self_type.ty) {
@ -326,6 +322,7 @@ class CoherenceChecker {
// Converts a polytype to a monotype by replacing all parameters with // Converts a polytype to a monotype by replacing all parameters with
// type variables. // type variables.
fn universally_quantify_polytype(polytype: ty_param_bounds_and_ty) -> t { fn universally_quantify_polytype(polytype: ty_param_bounds_and_ty) -> t {
let self_region = let self_region =
if !polytype.rp {none} if !polytype.rp {none}
@ -385,14 +382,6 @@ class CoherenceChecker {
} }
} }
item_impl(_, associated_traits, _, _) { item_impl(_, associated_traits, _, _) {
// XXX: Accept an array of traits.
let optional_trait_ref;
if associated_traits.len() == 0 {
optional_trait_ref = none;
} else {
optional_trait_ref = some(associated_traits[0]);
}
alt self.base_type_def_ids.find(local_def(item.id)) { alt self.base_type_def_ids.find(local_def(item.id)) {
none { none {
// Nothing to do. // Nothing to do.
@ -411,56 +400,50 @@ class CoherenceChecker {
} else { } else {
// This implementation is not in scope of // This implementation is not in scope of
// its base type. This still might be OK // its base type. This still might be OK
// if the trait is defined in the same // if the traits are defined in the same
// crate. // crate.
alt optional_trait_ref { if associated_traits.len() == 0 {
none { // There is no trait to implement, so
// There is no trait to implement, // this is an error.
// so this is an error.
let session = let session =
self.crate_context.tcx.sess; self.crate_context.tcx.sess;
session.span_err(item.span,
~"cannot implement \
inherent methods \
for a type outside \
the scope the type \
was defined in; \
define and \
implement a trait \
instead");
}
for associated_traits.each |trait_ref| {
// This is OK if and only if the
// 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;
session.span_err(item.span, session.span_err(item.span,
~"cannot \ ~"cannot \
implement \ provide an \
inherent \ extension \
methods for a \ implementa\
type outside \ tion \
the scope the \ for a trait \
type was \ not defined \
defined in; \ in this \
define and \ crate");
implement a \
trait instead");
}
some(trait_ref) {
// This is OK if and only if the
// 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;
session.span_err(item.span,
~"cannot \
provide \
an \
extension \
implementa\
tion \
for a \
trait not \
defined \
in this \
crate");
}
} }
} }
} }