about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/rustc/middle/typeck/coherence.rs206
1 files changed, 197 insertions, 9 deletions
diff --git a/src/rustc/middle/typeck/coherence.rs b/src/rustc/middle/typeck/coherence.rs
index 365d945fa3d..09dbd77e9bc 100644
--- a/src/rustc/middle/typeck/coherence.rs
+++ b/src/rustc/middle/typeck/coherence.rs
@@ -11,16 +11,20 @@ import middle::ty::{ty_fn, ty_trait, ty_tup, ty_var, ty_var_integral};
 import middle::ty::{ty_param, ty_self, ty_constr, ty_type, ty_opaque_box};
 import middle::ty::{ty_opaque_closure_ptr, ty_unboxed_vec, new_ty_hash};
 import middle::ty::{subst};
-import middle::typeck::infer::{infer_ctxt, mk_eqty, new_infer_ctxt};
-import syntax::ast::{crate, def_id, item, item_impl, method, region_param};
-import syntax::ast::{trait_ref};
+import middle::typeck::infer::{infer_ctxt, mk_subty, new_infer_ctxt};
+import syntax::ast::{crate, def_id, item, item_class, item_const, item_enum};
+import syntax::ast::{item_fn, item_foreign_mod, item_impl, item_mac};
+import syntax::ast::{item_mod, item_trait, item_ty, local_crate, method};
+import syntax::ast::{node_id, region_param, rp_none, rp_self, trait_ref};
 import syntax::ast_util::{def_id_of_def, new_def_hash};
-import syntax::visit::{default_simple_visitor, mk_simple_visitor};
-import syntax::visit::{visit_crate};
+import syntax::visit::{default_simple_visitor, default_visitor};
+import syntax::visit::{mk_simple_visitor, mk_vt, visit_crate, visit_item};
+import syntax::visit::{visit_mod};
+import util::ppaux::ty_to_str;
 
 import dvec::{dvec, extensions};
 import result::{extensions};
-import std::map::hashmap;
+import std::map::{hashmap, int_hash};
 import uint::range;
 
 class CoherenceInfo {
@@ -43,10 +47,26 @@ class CoherenceChecker {
     let inference_context: infer_ctxt;
     let info: @CoherenceInfo;
 
+    // A mapping from implementations to the corresponding base type
+    // definition ID.
+    let base_type_def_ids: hashmap<node_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.
+    let privileged_implementations: hashmap<node_id,()>;
+
+    // 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.
+    let privileged_types: hashmap<def_id,()>;
+
     new(crate_context: @crate_ctxt) {
         self.crate_context = crate_context;
         self.inference_context = new_infer_ctxt(crate_context.tcx);
         self.info = @CoherenceInfo();
+
+        self.base_type_def_ids = int_hash();
+        self.privileged_implementations = int_hash();
+        self.privileged_types = new_def_hash();
     }
 
     fn check_coherence(crate: @crate) {
@@ -71,6 +91,9 @@ class CoherenceChecker {
         for self.info.extension_methods.each |def_id, items| {
             self.check_implementation_coherence(def_id, items);
         }
+
+        // Check whether traits with base types are in privileged scopes.
+        self.check_privileged_scopes(crate);
     }
 
     fn check_implementation(item: @item,
@@ -121,6 +144,17 @@ class CoherenceChecker {
                 implementation_list.push(item);
             }
         }
+
+        // Add the implementation to the mapping from implementation to base
+        // type def ID, if there is a base type for this implementation.
+        alt self.get_base_type_def_id(self_type.ty) {
+            none {
+                // Nothing to do.
+            }
+            some(base_type_def_id) {
+                self.base_type_def_ids.insert(item.id, base_type_def_id);
+            }
+        }
     }
 
     fn get_base_type(original_type: t) -> option<t> {
@@ -147,6 +181,26 @@ class CoherenceChecker {
         }
     }
 
+    // Returns the def ID of the base type.
+    fn get_base_type_def_id(original_type: t) -> option<def_id> {
+        alt self.get_base_type(original_type) {
+            none {
+                ret none;
+            }
+            some(base_type) {
+                alt get(base_type).struct {
+                    ty_enum(def_id, _) | ty_class(def_id, _) {
+                        ret some(def_id);
+                    }
+                    _ {
+                        fail "get_base_type() returned a type that wasn't an \
+                              enum or class";
+                    }
+                }
+            }
+        }
+    }
+
     fn check_implementation_coherence(_trait_def_id: def_id,
                                       implementations: @dvec<@item>) {
 
@@ -177,7 +231,8 @@ class CoherenceChecker {
 
         let monotype_a = self.universally_quantify_polytype(polytype_a);
         let monotype_b = self.universally_quantify_polytype(polytype_b);
-        ret mk_eqty(self.inference_context, monotype_a, monotype_b).is_ok();
+        ret mk_subty(self.inference_context, monotype_a, monotype_b).is_ok()
+         || mk_subty(self.inference_context, monotype_b, monotype_a).is_ok();
     }
 
     // Converts a polytype to a monotype by replacing all parameters with
@@ -185,10 +240,10 @@ class CoherenceChecker {
     fn universally_quantify_polytype(polytype: ty_param_bounds_and_ty) -> t {
         let self_region;
         alt polytype.rp {
-            ast::rp_none {
+            rp_none {
                 self_region = none;
             }
-            ast::rp_self {
+            rp_self {
                 self_region = some(self.inference_context.next_region_var())
             }
         };
@@ -220,6 +275,139 @@ class CoherenceChecker {
             }
         }
     }
+
+    // Privileged scope checking
+
+    fn check_privileged_scopes(crate: @crate) {
+        visit_crate(*crate, (), mk_vt(@{
+            visit_item: |item, _context, visitor| {
+                alt item.node {
+                    item_mod(module) {
+                        // First, gather up all privileged types.
+                        let privileged_types =
+                            self.gather_privileged_types(module.items);
+                        for privileged_types.each |privileged_type| {
+                            #debug("(checking privileged scopes) entering \
+                                    privileged scope of %d:%d",
+                                   privileged_type.crate,
+                                   privileged_type.node);
+
+                            self.privileged_types.insert(privileged_type, ());
+                        }
+
+                        // Then visit the module items.
+                        visit_mod(module, item.span, item.id, (), visitor);
+
+                        // Finally, remove privileged types from the map.
+                        for privileged_types.each |privileged_type| {
+                            self.privileged_types.remove(privileged_type);
+                        }
+                    }
+                    item_impl(_, _, optional_trait_ref, _, _) {
+                        alt self.base_type_def_ids.find(item.id) {
+                            none {
+                                // Nothing to do.
+                            }
+                            some(base_type_def_id) {
+                                // Check to see whether the implementation is
+                                // in the scope of its base type.
+
+                                let privileged_types = &self.privileged_types;
+                                if privileged_types.
+                                        contains_key(base_type_def_id) {
+
+                                    // Record that this implementation is OK.
+                                    self.privileged_implementations.insert
+                                        (item.id, ());
+                                } else {
+                                    // This implementation is not in scope of
+                                    // its base type. This still might be OK
+                                    // if the trait is defined in the same
+                                    // crate.
+
+                                    alt optional_trait_ref {
+                                        none {
+                                            // There is no trait to implement,
+                                            // so this is an error.
+
+                                            let session =
+                                                self.crate_context.tcx.sess;
+                                            session.span_warn(item.span,
+                                                              "cannot \
+                                                               implement \
+                                                               inherent \
+                                                               methods for a \
+                                                               type outside \
+                                                               the scope the \
+                                                               type was \
+                                                               defined in; \
+                                                               define and \
+                                                               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.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_warn(item.span,
+                                                                  "cannot \
+                                                                   provide \
+                                                                   an \
+                                                                   extension \
+                                                                   implement\
+                                                                      ation \
+                                                                   for a \
+                                                                   trait not \
+                                                                   defined \
+                                                                   in this \
+                                                                   crate");
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+
+                        visit_item(item, (), visitor);
+                    }
+                    _ {
+                        visit_item(item, (), visitor);
+                    }
+                }
+            }
+            with *default_visitor()
+        }));
+    }
+
+    fn gather_privileged_types(items: ~[@item]) -> @dvec<def_id> {
+        let results = @dvec();
+        for items.each |item| {
+            alt item.node {
+                item_class(*) | item_enum(*) {
+                    results.push(local_def(item.id));
+                }
+
+                item_const(*) | item_fn(*) | item_mod(*) |
+                item_foreign_mod(*) | item_ty(*) | item_trait(*) |
+                item_impl(*) | item_mac(*) {
+                    // Nothing to do.
+                }
+            }
+        }
+
+        ret results;
+    }
 }
 
 fn check_coherence(crate_context: @crate_ctxt, crate: @crate) {