From a1b4afe0670fb1603b056f317a301ed527064ef5 Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Thu, 21 Mar 2013 16:44:13 -0400
Subject: [PATCH] Update coherence rules to be more flexible for `impl Trait
 for Type`

---
 src/librustc/middle/typeck/coherence.rs | 91 +++++++++++++------------
 1 file changed, 47 insertions(+), 44 deletions(-)

diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs
index 824ac594e74..0b3eca7c07d 100644
--- a/src/librustc/middle/typeck/coherence.rs
+++ b/src/librustc/middle/typeck/coherence.rs
@@ -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.
 pub fn get_base_type_def_id(inference_context: @mut InferCtxt,
                             span: span,
@@ -161,8 +187,7 @@ pub fn CoherenceChecker(crate_context: @mut CrateCtxt) -> CoherenceChecker {
         crate_context: crate_context,
         inference_context: new_infer_ctxt(crate_context.tcx),
 
-        base_type_def_ids: HashMap(),
-        privileged_implementations: HashMap()
+        base_type_def_ids: HashMap()
     }
 }
 
@@ -174,11 +199,6 @@ pub struct CoherenceChecker {
     // definition 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 {
@@ -615,27 +635,11 @@ pub impl CoherenceChecker {
                         visit_mod(module_, item.span, item.id, (), visitor);
                     }
                     item_impl(_, opt_trait, _, _) => {
-                        let mut ok = false;
-                        match self.base_type_def_ids.find(
-                            &local_def(item.id)) {
-
-                            None => {
-                                // 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 {
+                        // `for_ty` is `Type` in `impl Trait for Type`
+                        let for_ty =
+                            ty::node_id_to_type(self.crate_context.tcx,
+                                                item.id);
+                        if !type_is_defined_in_local_crate(for_ty) {
                             // This implementation is not in scope of its base
                             // type. This still might be OK if the trait is
                             // defined in the same crate.
@@ -655,25 +659,24 @@ pub impl CoherenceChecker {
                                                       implement a trait or \
                                                       new type instead");
                                 }
-                                _ => ()
-                          }
 
-                          for opt_trait.each |trait_ref| {
-                                // This is OK if and only if the trait was
-                                // defined in this crate.
+                                Some(trait_ref) => {
+                                    // This is OK if and only if the trait was
+                                    // defined in this crate.
 
-                                let trait_def_id =
-                                    self.trait_ref_to_trait_def_id(
-                                        *trait_ref);
+                                    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 \
-                                                       extension \
-                                                       implementation for a \
-                                                       trait not defined in \
-                                                       this crate");
+                                    if trait_def_id.crate != local_crate {
+                                        let session = self.crate_context.tcx.sess;
+                                        session.span_err(item.span,
+                                                         ~"cannot provide an \
+                                                           extension \
+                                                           implementation for a \
+                                                           trait not defined in \
+                                                           this crate");
+                                    }
                                 }
                             }
                         }