auto merge of #5515 : nikomatsakis/rust/issue-5514-flexible-coherence-rules, r=pcwalton

See issue #5514

r? @pcwalton
This commit is contained in:
bors 2013-03-23 12:36:53 -07:00
commit a56ec8c134
1 changed files with 47 additions and 44 deletions

View File

@ -104,6 +104,32 @@ pub fn get_base_type(inference_context: @mut InferCtxt,
} }
} }
pub fn type_is_defined_in_local_crate(original_type: t) -> bool {
/*!
*
* For coherence, when we have `impl Trait for Type`, we need to
* guarantee that `Type` is "local" to the
* crate. For our purposes, this means that it must contain
* some nominal type defined in this crate.
*/
let mut found_nominal = false;
do ty::walk_ty(original_type) |t| {
match get(t).sty {
ty_enum(def_id, _) |
ty_trait(def_id, _, _) |
ty_struct(def_id, _) => {
if def_id.crate == ast::local_crate {
found_nominal = true;
}
}
_ => { }
}
}
return found_nominal;
}
// Returns the def ID of the base type, if there is one. // Returns the def ID of the base type, if there is one.
pub fn get_base_type_def_id(inference_context: @mut InferCtxt, pub fn get_base_type_def_id(inference_context: @mut InferCtxt,
span: span, span: span,
@ -161,8 +187,7 @@ pub fn CoherenceChecker(crate_context: @mut CrateCtxt) -> CoherenceChecker {
crate_context: crate_context, crate_context: crate_context,
inference_context: new_infer_ctxt(crate_context.tcx), inference_context: new_infer_ctxt(crate_context.tcx),
base_type_def_ids: HashMap(), base_type_def_ids: HashMap()
privileged_implementations: HashMap()
} }
} }
@ -174,11 +199,6 @@ pub struct CoherenceChecker {
// definition ID. // definition ID.
base_type_def_ids: HashMap<def_id,def_id>, base_type_def_ids: HashMap<def_id,def_id>,
// A set of implementations in privileged scopes; i.e. those
// implementations that are defined in the same scope as their base types.
privileged_implementations: HashMap<node_id,()>,
} }
pub impl CoherenceChecker { pub impl CoherenceChecker {
@ -615,27 +635,11 @@ pub impl CoherenceChecker {
visit_mod(module_, item.span, item.id, (), visitor); visit_mod(module_, item.span, item.id, (), visitor);
} }
item_impl(_, opt_trait, _, _) => { item_impl(_, opt_trait, _, _) => {
let mut ok = false; // `for_ty` is `Type` in `impl Trait for Type`
match self.base_type_def_ids.find( let for_ty =
&local_def(item.id)) { ty::node_id_to_type(self.crate_context.tcx,
item.id);
None => { if !type_is_defined_in_local_crate(for_ty) {
// Nothing to do.
}
Some(base_type_def_id) => {
// Check to see whether the implementation is
// in the same crate as its base type.
if base_type_def_id.crate == local_crate {
// Record that this implementation is OK.
self.privileged_implementations.insert
(item.id, ());
ok = true;
}
}
}
if !ok {
// This implementation is not in scope of its base // This implementation is not in scope of its base
// type. This still might be OK if the trait is // type. This still might be OK if the trait is
// defined in the same crate. // defined in the same crate.
@ -655,25 +659,24 @@ pub impl CoherenceChecker {
implement a trait or \ implement a trait or \
new type instead"); new type instead");
} }
_ => ()
}
for opt_trait.each |trait_ref| { Some(trait_ref) => {
// This is OK if and only if the trait was // This is OK if and only if the trait was
// defined in this crate. // defined in this crate.
let trait_def_id = let trait_def_id =
self.trait_ref_to_trait_def_id( self.trait_ref_to_trait_def_id(
*trait_ref); trait_ref);
if trait_def_id.crate != local_crate { if trait_def_id.crate != local_crate {
let session = self.crate_context.tcx.sess; let session = self.crate_context.tcx.sess;
session.span_err(item.span, session.span_err(item.span,
~"cannot provide an \ ~"cannot provide an \
extension \ extension \
implementation for a \ implementation for a \
trait not defined in \ trait not defined in \
this crate"); this crate");
}
} }
} }
} }