]> git.lizzy.rs Git - rust.git/commitdiff
Port coherence to use the new trait matching code
authorNiko Matsakis <niko@alum.mit.edu>
Fri, 12 Sep 2014 14:54:08 +0000 (10:54 -0400)
committerNiko Matsakis <niko@alum.mit.edu>
Mon, 15 Sep 2014 19:28:12 +0000 (15:28 -0400)
src/librustc/middle/dead.rs
src/librustc/middle/traits/coherence.rs [new file with mode: 0644]
src/librustc/middle/typeck/coherence.rs [deleted file]
src/librustc/middle/typeck/coherence/mod.rs [new file with mode: 0644]
src/librustc/middle/typeck/coherence/orphan.rs [new file with mode: 0644]
src/librustc/middle/typeck/coherence/overlap.rs [new file with mode: 0644]
src/librustdoc/clean/inline.rs

index 46e3585912a7f6eab3e65d8b6e4e4d22b381663f..850c6ecffaaa1e284b54b8de49f0637555ceafa8 100644 (file)
@@ -470,7 +470,7 @@ fn symbol_is_live(&mut self, id: ast::NodeId,
         match self.tcx.inherent_impls.borrow().find(&local_def(id)) {
             None => (),
             Some(impl_list) => {
-                for impl_did in impl_list.borrow().iter() {
+                for impl_did in impl_list.iter() {
                     for item_did in impl_items.get(impl_did).iter() {
                         if self.live_symbols.contains(&item_did.def_id()
                                                                .node) {
diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs
new file mode 100644 (file)
index 0000000..415eed3
--- /dev/null
@@ -0,0 +1,168 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/*! See `doc.rs` for high-level documentation */
+
+use super::DUMMY_CAUSE;
+use super::{EvaluatedToMatch, EvaluatedToAmbiguity, EvaluatedToUnmatch};
+use super::{evaluate_impl};
+use super::util;
+
+use middle::subst;
+use middle::subst::Subst;
+use middle::ty;
+use middle::typeck::infer::InferCtxt;
+use syntax::ast;
+use syntax::codemap::DUMMY_SP;
+use util::nodemap::DefIdMap;
+use util::ppaux::Repr;
+
+pub fn impl_can_satisfy(infcx: &InferCtxt,
+                        impl1_def_id: ast::DefId,
+                        impl2_def_id: ast::DefId)
+                        -> bool
+{
+    // `impl1` provides an implementation of `Foo<X,Y> for Z`.
+    let impl1_substs =
+        util::fresh_substs_for_impl(infcx, DUMMY_SP, impl1_def_id);
+    let impl1_self_ty =
+        ty::impl_trait_ref(infcx.tcx, impl1_def_id).unwrap()
+            .self_ty()
+            .subst(infcx.tcx, &impl1_substs);
+
+    // Determine whether `impl2` can provide an implementation for those
+    // same types.
+    let param_env = ty::empty_parameter_environment();
+    let unboxed_closures = DefIdMap::new();
+    match evaluate_impl(infcx, &param_env, &unboxed_closures, DUMMY_CAUSE,
+                        impl2_def_id, impl1_self_ty) {
+        EvaluatedToMatch | EvaluatedToAmbiguity => true,
+        EvaluatedToUnmatch => false,
+    }
+}
+
+pub fn impl_is_local(tcx: &ty::ctxt,
+                     impl_def_id: ast::DefId)
+                     -> bool
+{
+    debug!("impl_is_local({})", impl_def_id.repr(tcx));
+
+    // We only except this routine to be invoked on implementations
+    // of a trait, not inherent implementations.
+    let trait_ref = ty::impl_trait_ref(tcx, impl_def_id).unwrap();
+    debug!("trait_ref={}", trait_ref.repr(tcx));
+
+    // If the trait is local to the crate, ok.
+    if trait_ref.def_id.krate == ast::LOCAL_CRATE {
+        debug!("trait {} is local to current crate",
+               trait_ref.def_id.repr(tcx));
+        return true;
+    }
+
+    // Otherwise, self type must be local to the crate.
+    let self_ty = ty::lookup_item_type(tcx, impl_def_id).ty;
+    return ty_is_local(tcx, self_ty);
+}
+
+pub fn ty_is_local(tcx: &ty::ctxt,
+                   ty: ty::t)
+                   -> bool
+{
+    debug!("ty_is_local({})", ty.repr(tcx));
+
+    match ty::get(ty).sty {
+        ty::ty_nil |
+        ty::ty_bot |
+        ty::ty_bool |
+        ty::ty_char |
+        ty::ty_int(..) |
+        ty::ty_uint(..) |
+        ty::ty_float(..) |
+        ty::ty_str(..) => {
+            false
+        }
+
+        ty::ty_unboxed_closure(..) => {
+            // This routine is invoked on types specified by users as
+            // part of an impl and hence an unboxed closure type
+            // cannot appear.
+            tcx.sess.bug("ty_is_local applied to unboxed closure type")
+        }
+
+        ty::ty_bare_fn(..) |
+        ty::ty_closure(..) => {
+            false
+        }
+
+        ty::ty_uniq(t) => {
+            let krate = tcx.lang_items.owned_box().map(|d| d.krate);
+            krate == Some(ast::LOCAL_CRATE) || ty_is_local(tcx, t)
+        }
+
+        ty::ty_box(t) => {
+            let krate = tcx.lang_items.gc().map(|d| d.krate);
+            krate == Some(ast::LOCAL_CRATE) || ty_is_local(tcx, t)
+        }
+
+        ty::ty_vec(t, _) |
+        ty::ty_ptr(ty::mt { ty: t, .. }) |
+        ty::ty_rptr(_, ty::mt { ty: t, .. }) => {
+            ty_is_local(tcx, t)
+        }
+
+        ty::ty_tup(ref ts) => {
+            ts.iter().any(|&t| ty_is_local(tcx, t))
+        }
+
+        ty::ty_enum(def_id, ref substs) |
+        ty::ty_struct(def_id, ref substs) => {
+            def_id.krate == ast::LOCAL_CRATE || {
+                let variances = ty::item_variances(tcx, def_id);
+                subst::ParamSpace::all().iter().any(|&space| {
+                    substs.types.get_slice(space).iter().enumerate().any(
+                        |(i, &t)| {
+                            match *variances.types.get(space, i) {
+                                ty::Bivariant => {
+                                    // If Foo<T> is bivariant with respect to
+                                    // T, then it doesn't matter whether T is
+                                    // local or not, because `Foo<U>` for any
+                                    // U will be a subtype of T.
+                                    false
+                                }
+                                ty::Contravariant |
+                                ty::Covariant |
+                                ty::Invariant => {
+                                    ty_is_local(tcx, t)
+                                }
+                            }
+                        })
+                })
+            }
+        }
+
+        ty::ty_trait(ref tt) => {
+            tt.def_id.krate == ast::LOCAL_CRATE
+        }
+
+        // Type parameters may be bound to types that are not local to
+        // the crate.
+        ty::ty_param(..) => {
+            false
+        }
+
+        ty::ty_infer(..) |
+        ty::ty_open(..) |
+        ty::ty_err => {
+            tcx.sess.bug(
+                format!("ty_is_local invoked on unexpected type: {}",
+                        ty.repr(tcx)).as_slice())
+        }
+    }
+}
diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs
deleted file mode 100644 (file)
index 8de1762..0000000
+++ /dev/null
@@ -1,828 +0,0 @@
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Coherence phase
-//
-// The job of the coherence phase of typechecking is to ensure that each trait
-// has at most one implementation for each type. Then we build a mapping from
-// each trait in the system to its implementations.
-
-
-use metadata::csearch::{each_impl, get_impl_trait, each_implementation_for_trait};
-use metadata::csearch;
-use middle::subst;
-use middle::subst::{Substs};
-use middle::ty::get;
-use middle::ty::{ImplContainer, ImplOrTraitItemId, MethodTraitItemId};
-use middle::ty::{lookup_item_type};
-use middle::ty::{t, ty_bool, ty_char, ty_bot, ty_box, ty_enum, ty_err};
-use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int, ty_nil, ty_open};
-use middle::ty::{ty_param, Polytype, ty_ptr};
-use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup};
-use middle::ty::{ty_uint, ty_unboxed_closure, ty_uniq, ty_bare_fn};
-use middle::ty::{ty_closure};
-use middle::ty::type_is_ty_var;
-use middle::subst::Subst;
-use middle::ty;
-use middle::typeck::CrateCtxt;
-use middle::typeck::infer::combine::Combine;
-use middle::typeck::infer::InferCtxt;
-use middle::typeck::infer::{new_infer_ctxt, resolve_ivar, resolve_type};
-use middle::typeck::infer;
-use util::ppaux::Repr;
-use middle::def::{DefStruct, DefTy};
-use syntax::ast::{Crate, DefId};
-use syntax::ast::{Item, ItemEnum, ItemImpl, ItemMod, ItemStruct};
-use syntax::ast::{LOCAL_CRATE, TraitRef, TyPath};
-use syntax::ast;
-use syntax::ast_map::NodeItem;
-use syntax::ast_map;
-use syntax::ast_util::{local_def};
-use syntax::codemap::{Span, DUMMY_SP};
-use syntax::parse::token;
-use syntax::visit;
-
-use std::collections::HashSet;
-use std::cell::RefCell;
-use std::rc::Rc;
-
-struct UniversalQuantificationResult {
-    monotype: t
-}
-
-fn get_base_type(inference_context: &InferCtxt,
-                 span: Span,
-                 original_type: t)
-                 -> Option<t> {
-    let resolved_type = match resolve_type(inference_context,
-                                           Some(span),
-                                           original_type,
-                                           resolve_ivar) {
-        Ok(resulting_type) if !type_is_ty_var(resulting_type) => resulting_type,
-        _ => {
-            inference_context.tcx.sess.span_fatal(span,
-                                                  "the type of this value must be known in order \
-                                                   to determine the base type");
-        }
-    };
-
-    match get(resolved_type).sty {
-        ty_enum(..) | ty_struct(..) | ty_unboxed_closure(..) => {
-            debug!("(getting base type) found base type");
-            Some(resolved_type)
-        }
-
-        _ if ty::type_is_trait(resolved_type) => {
-            debug!("(getting base type) found base type (trait)");
-            Some(resolved_type)
-        }
-
-        ty_nil | ty_bot | ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) |
-        ty_str(..) | ty_vec(..) | ty_bare_fn(..) | ty_closure(..) | ty_tup(..) |
-        ty_infer(..) | ty_param(..) | ty_err | ty_open(..) |
-        ty_box(_) | ty_uniq(_) | ty_ptr(_) | ty_rptr(_, _) => {
-            debug!("(getting base type) no base type; found {:?}",
-                   get(original_type).sty);
-            None
-        }
-        ty_trait(..) => fail!("should have been caught")
-    }
-}
-
-fn type_is_defined_in_local_crate(tcx: &ty::ctxt, 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;
-    ty::walk_ty(original_type, |t| {
-        match get(t).sty {
-            ty_enum(def_id, _) |
-            ty_struct(def_id, _) |
-            ty_unboxed_closure(def_id, _) => {
-                if def_id.krate == ast::LOCAL_CRATE {
-                    found_nominal = true;
-                }
-            }
-            ty_trait(box ty::TyTrait { def_id, .. }) => {
-                if def_id.krate == ast::LOCAL_CRATE {
-                    found_nominal = true;
-                }
-            }
-            ty_uniq(..) => {
-                match tcx.lang_items.owned_box() {
-                    Some(did) if did.krate == ast::LOCAL_CRATE => {
-                        found_nominal = true;
-                    }
-                    _ => {}
-                }
-            }
-            ty_box(..) => {
-                match tcx.lang_items.gc() {
-                    Some(did) if did.krate == ast::LOCAL_CRATE => {
-                        found_nominal = true;
-                    }
-                    _ => {}
-                }
-            }
-
-            _ => { }
-        }
-    });
-    return found_nominal;
-}
-
-// Returns the def ID of the base type, if there is one.
-fn get_base_type_def_id(inference_context: &InferCtxt,
-                        span: Span,
-                        original_type: t)
-                        -> Option<DefId> {
-    match get_base_type(inference_context, span, original_type) {
-        None => None,
-        Some(base_type) => {
-            match get(base_type).sty {
-                ty_enum(def_id, _) |
-                ty_struct(def_id, _) |
-                ty_unboxed_closure(def_id, _) => {
-                    Some(def_id)
-                }
-                ty_ptr(ty::mt {ty, ..}) |
-                ty_rptr(_, ty::mt {ty, ..}) |
-                ty_uniq(ty) => {
-                    match ty::get(ty).sty {
-                        ty_trait(box ty::TyTrait { def_id, .. }) => {
-                            Some(def_id)
-                        }
-                        _ => {
-                            fail!("get_base_type() returned a type that wasn't an \
-                                   enum, struct, or trait");
-                        }
-                    }
-                }
-                ty_trait(box ty::TyTrait { def_id, .. }) => {
-                    Some(def_id)
-                }
-                _ => {
-                    fail!("get_base_type() returned a type that wasn't an \
-                           enum, struct, or trait");
-                }
-            }
-        }
-    }
-}
-
-struct CoherenceChecker<'a, 'tcx: 'a> {
-    crate_context: &'a CrateCtxt<'a, 'tcx>,
-    inference_context: InferCtxt<'a, 'tcx>,
-}
-
-struct CoherenceCheckVisitor<'a, 'tcx: 'a> {
-    cc: &'a CoherenceChecker<'a, 'tcx>
-}
-
-impl<'a, 'tcx, 'v> visit::Visitor<'v> for CoherenceCheckVisitor<'a, 'tcx> {
-    fn visit_item(&mut self, item: &Item) {
-
-        //debug!("(checking coherence) item '{}'", token::get_ident(item.ident));
-
-        match item.node {
-            ItemImpl(_, ref opt_trait, _, _) => {
-                match opt_trait.clone() {
-                    Some(opt_trait) => {
-                        self.cc.check_implementation(item, [opt_trait]);
-                    }
-                    None => self.cc.check_implementation(item, [])
-                }
-            }
-            _ => {
-                // Nothing to do.
-            }
-        };
-
-        visit::walk_item(self, item);
-    }
-}
-
-struct PrivilegedScopeVisitor<'a, 'tcx: 'a> {
-    cc: &'a CoherenceChecker<'a, 'tcx>
-}
-
-impl<'a, 'tcx, 'v> visit::Visitor<'v> for PrivilegedScopeVisitor<'a, 'tcx> {
-    fn visit_item(&mut self, item: &Item) {
-
-        match item.node {
-            ItemMod(ref module_) => {
-                // Then visit the module items.
-                visit::walk_mod(self, module_);
-            }
-            ItemImpl(_, None, ref ast_ty, _) => {
-                if !self.cc.ast_type_is_defined_in_local_crate(&**ast_ty) {
-                    // This is an error.
-                    let session = &self.cc.crate_context.tcx.sess;
-                    span_err!(session, item.span, E0116,
-                              "cannot associate methods with a type outside the \
-                               crate the type is defined in; define and implement \
-                               a trait or new type instead");
-                }
-            }
-            ItemImpl(_, Some(ref trait_ref), _, _) => {
-                let tcx = self.cc.crate_context.tcx;
-                // `for_ty` is `Type` in `impl Trait for Type`
-                let for_ty = ty::node_id_to_type(tcx, item.id);
-                if !type_is_defined_in_local_crate(tcx, 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.
-
-                    let trait_def_id =
-                        self.cc.trait_ref_to_trait_def_id(trait_ref);
-
-                    if trait_def_id.krate != LOCAL_CRATE {
-                        let session = &self.cc.crate_context.tcx.sess;
-                        span_err!(session, item.span, E0117,
-                                  "cannot provide an extension implementation \
-                                   where both trait and type are not defined in this crate");
-                    }
-                }
-
-                visit::walk_item(self, item);
-            }
-            _ => {
-                visit::walk_item(self, item);
-            }
-        }
-    }
-}
-
-impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
-    fn check(&self, krate: &Crate) {
-        // Check implementations and traits. This populates the tables
-        // containing the inherent methods and extension methods. It also
-        // builds up the trait inheritance table.
-        let mut visitor = CoherenceCheckVisitor { cc: self };
-        visit::walk_crate(&mut visitor, krate);
-
-        // Check that there are no overlapping trait instances
-        self.check_implementation_coherence();
-
-        // Check whether traits with base types are in privileged scopes.
-        self.check_privileged_scopes(krate);
-
-        // Bring in external crates. It's fine for this to happen after the
-        // coherence checks, because we ensure by construction that no errors
-        // can happen at link time.
-        self.add_external_crates();
-
-        // Populate the table of destructors. It might seem a bit strange to
-        // do this here, but it's actually the most convenient place, since
-        // the coherence tables contain the trait -> type mappings.
-        self.populate_destructor_table();
-    }
-
-    fn check_implementation(&self, item: &Item,
-                            associated_traits: &[TraitRef]) {
-        let tcx = self.crate_context.tcx;
-        let impl_did = local_def(item.id);
-        let self_type = ty::lookup_item_type(tcx, impl_did);
-
-        // If there are no traits, then this implementation must have a
-        // base type.
-
-        if associated_traits.len() == 0 {
-            debug!("(checking implementation) no associated traits for item '{}'",
-                   token::get_ident(item.ident));
-
-            match get_base_type_def_id(&self.inference_context,
-                                       item.span,
-                                       self_type.ty) {
-                None => {
-                    let session = &self.crate_context.tcx.sess;
-                    span_err!(session, item.span, E0118,
-                              "no base type found for inherent implementation; \
-                               implement a trait or new type instead");
-                }
-                Some(_) => {
-                    // Nothing to do.
-                }
-            }
-        }
-
-        let impl_items = self.create_impl_from_item(item);
-
-        for associated_trait in associated_traits.iter() {
-            let trait_ref = ty::node_id_to_trait_ref(
-                self.crate_context.tcx, associated_trait.ref_id);
-            debug!("(checking implementation) adding impl for trait '{}', item '{}'",
-                   trait_ref.repr(self.crate_context.tcx),
-                   token::get_ident(item.ident));
-
-            self.add_trait_impl(trait_ref.def_id, impl_did);
-        }
-
-        // Add the implementation to the mapping from implementation to base
-        // type def ID, if there is a base type for this implementation and
-        // the implementation does not have any associated traits.
-        match get_base_type_def_id(&self.inference_context,
-                                   item.span,
-                                   self_type.ty) {
-            None => {
-                // Nothing to do.
-            }
-            Some(base_type_def_id) => {
-                // FIXME: Gather up default methods?
-                if associated_traits.len() == 0 {
-                    self.add_inherent_impl(base_type_def_id, impl_did);
-                }
-            }
-        }
-
-        tcx.impl_items.borrow_mut().insert(impl_did, impl_items);
-    }
-
-    // Creates default method IDs and performs type substitutions for an impl
-    // and trait pair. Then, for each provided method in the trait, inserts a
-    // `ProvidedMethodInfo` instance into the `provided_method_sources` map.
-    fn instantiate_default_methods(
-            &self,
-            impl_id: DefId,
-            trait_ref: &ty::TraitRef,
-            all_impl_items: &mut Vec<ImplOrTraitItemId>) {
-        let tcx = self.crate_context.tcx;
-        debug!("instantiate_default_methods(impl_id={:?}, trait_ref={})",
-               impl_id, trait_ref.repr(tcx));
-
-        let impl_poly_type = ty::lookup_item_type(tcx, impl_id);
-
-        let prov = ty::provided_trait_methods(tcx, trait_ref.def_id);
-        for trait_method in prov.iter() {
-            // Synthesize an ID.
-            let new_id = tcx.sess.next_node_id();
-            let new_did = local_def(new_id);
-
-            debug!("new_did={:?} trait_method={}", new_did, trait_method.repr(tcx));
-
-            // Create substitutions for the various trait parameters.
-            let new_method_ty =
-                Rc::new(subst_receiver_types_in_method_ty(
-                    tcx,
-                    impl_id,
-                    &impl_poly_type,
-                    trait_ref,
-                    new_did,
-                    &**trait_method,
-                    Some(trait_method.def_id)));
-
-            debug!("new_method_ty={}", new_method_ty.repr(tcx));
-            all_impl_items.push(MethodTraitItemId(new_did));
-
-            // construct the polytype for the method based on the
-            // method_ty.  it will have all the generics from the
-            // impl, plus its own.
-            let new_polytype = ty::Polytype {
-                generics: new_method_ty.generics.clone(),
-                ty: ty::mk_bare_fn(tcx, new_method_ty.fty.clone())
-            };
-            debug!("new_polytype={}", new_polytype.repr(tcx));
-
-            tcx.tcache.borrow_mut().insert(new_did, new_polytype);
-            tcx.impl_or_trait_items
-               .borrow_mut()
-               .insert(new_did, ty::MethodTraitItem(new_method_ty));
-
-            // Pair the new synthesized ID up with the
-            // ID of the method.
-            self.crate_context.tcx.provided_method_sources.borrow_mut()
-                .insert(new_did, trait_method.def_id);
-        }
-    }
-
-    fn add_inherent_impl(&self, base_def_id: DefId, impl_def_id: DefId) {
-        let tcx = self.crate_context.tcx;
-        match tcx.inherent_impls.borrow().find(&base_def_id) {
-            Some(implementation_list) => {
-                implementation_list.borrow_mut().push(impl_def_id);
-                return;
-            }
-            None => {}
-        }
-
-        tcx.inherent_impls.borrow_mut().insert(base_def_id,
-                                               Rc::new(RefCell::new(vec!(impl_def_id))));
-    }
-
-    fn add_trait_impl(&self, base_def_id: DefId, impl_def_id: DefId) {
-        ty::record_trait_implementation(self.crate_context.tcx,
-                                        base_def_id,
-                                        impl_def_id);
-    }
-
-    fn check_implementation_coherence(&self) {
-        for trait_id in self.crate_context.tcx.trait_impls.borrow().keys() {
-            self.check_implementation_coherence_of(*trait_id);
-        }
-    }
-
-    fn check_implementation_coherence_of(&self, trait_def_id: DefId) {
-        // Unify pairs of polytypes.
-        self.iter_impls_of_trait_local(trait_def_id, |impl_a| {
-            let polytype_a =
-                self.get_self_type_for_implementation(impl_a);
-
-            // "We have an impl of trait <trait_def_id> for type <polytype_a>,
-            // and that impl is <impl_a>"
-            self.iter_impls_of_trait(trait_def_id, |impl_b| {
-
-                // An impl is coherent with itself
-                if impl_a != impl_b {
-                    let polytype_b = self.get_self_type_for_implementation(
-                            impl_b);
-
-                    if self.polytypes_unify(polytype_a.clone(), polytype_b) {
-                        let session = &self.crate_context.tcx.sess;
-                        span_err!(session, self.span_of_impl(impl_a), E0119,
-                                  "conflicting implementations for trait `{}`",
-                                  ty::item_path_str(self.crate_context.tcx, trait_def_id));
-                        if impl_b.krate == LOCAL_CRATE {
-                            span_note!(session, self.span_of_impl(impl_b),
-                                       "note conflicting implementation here");
-                        } else {
-                            let crate_store = &self.crate_context.tcx.sess.cstore;
-                            let cdata = crate_store.get_crate_data(impl_b.krate);
-                            span_note!(session, self.span_of_impl(impl_a),
-                                       "conflicting implementation in crate `{}`",
-                                       cdata.name);
-                        }
-                    }
-                }
-            })
-        })
-    }
-
-    fn iter_impls_of_trait(&self, trait_def_id: DefId, f: |DefId|) {
-        self.iter_impls_of_trait_local(trait_def_id, |x| f(x));
-
-        if trait_def_id.krate == LOCAL_CRATE {
-            return;
-        }
-
-        let crate_store = &self.crate_context.tcx.sess.cstore;
-        csearch::each_implementation_for_trait(crate_store, trait_def_id, |impl_def_id| {
-            // Is this actually necessary?
-            let _ = lookup_item_type(self.crate_context.tcx, impl_def_id);
-            f(impl_def_id);
-        });
-    }
-
-    fn iter_impls_of_trait_local(&self, trait_def_id: DefId, f: |DefId|) {
-        match self.crate_context.tcx.trait_impls.borrow().find(&trait_def_id) {
-            Some(impls) => {
-                for &impl_did in impls.borrow().iter() {
-                    f(impl_did);
-                }
-            }
-            None => { /* no impls? */ }
-        }
-    }
-
-    fn polytypes_unify(&self,
-                       polytype_a: Polytype,
-                       polytype_b: Polytype)
-                       -> bool {
-        let universally_quantified_a =
-            self.universally_quantify_polytype(polytype_a);
-        let universally_quantified_b =
-            self.universally_quantify_polytype(polytype_b);
-
-        return self.can_unify_universally_quantified(
-            &universally_quantified_a, &universally_quantified_b) ||
-            self.can_unify_universally_quantified(
-            &universally_quantified_b, &universally_quantified_a);
-    }
-
-    // Converts a polytype to a monotype by replacing all parameters with
-    // type variables. Returns the monotype and the type variables created.
-    fn universally_quantify_polytype(&self, polytype: Polytype)
-                                     -> UniversalQuantificationResult
-    {
-        let substitutions =
-            self.inference_context.fresh_substs_for_type(DUMMY_SP,
-                                                         &polytype.generics);
-        let monotype = polytype.ty.subst(self.crate_context.tcx, &substitutions);
-
-        UniversalQuantificationResult {
-            monotype: monotype
-        }
-    }
-
-    fn can_unify_universally_quantified<'a>(&self,
-                                            a: &'a UniversalQuantificationResult,
-                                            b: &'a UniversalQuantificationResult)
-                                            -> bool
-    {
-        infer::can_mk_subty(&self.inference_context,
-                            a.monotype,
-                            b.monotype).is_ok()
-    }
-
-    fn get_self_type_for_implementation(&self, impl_did: DefId)
-                                        -> Polytype {
-        self.crate_context.tcx.tcache.borrow().get_copy(&impl_did)
-    }
-
-    // Privileged scope checking
-    fn check_privileged_scopes(&self, krate: &Crate) {
-        let mut visitor = PrivilegedScopeVisitor{ cc: self };
-        visit::walk_crate(&mut visitor, krate);
-    }
-
-    fn trait_ref_to_trait_def_id(&self, trait_ref: &TraitRef) -> DefId {
-        let def_map = &self.crate_context.tcx.def_map;
-        let trait_def = def_map.borrow().get_copy(&trait_ref.ref_id);
-        let trait_id = trait_def.def_id();
-        return trait_id;
-    }
-
-    /// For coherence, when we have `impl Type`, we need to guarantee that
-    /// `Type` is "local" to the crate. For our purposes, this means that it
-    /// must precisely name some nominal type defined in this crate.
-    fn ast_type_is_defined_in_local_crate(&self, original_type: &ast::Ty) -> bool {
-        match original_type.node {
-            TyPath(_, _, path_id) => {
-                match self.crate_context.tcx.def_map.borrow().get_copy(&path_id) {
-                    DefTy(def_id) | DefStruct(def_id) => {
-                        if def_id.krate != LOCAL_CRATE {
-                            return false;
-                        }
-
-                        // Make sure that this type precisely names a nominal
-                        // type.
-                        match self.crate_context.tcx.map.find(def_id.node) {
-                            None => {
-                                self.crate_context.tcx.sess.span_bug(
-                                    original_type.span,
-                                    "resolve didn't resolve this type?!");
-                            }
-                            Some(NodeItem(item)) => {
-                                match item.node {
-                                    ItemStruct(..) | ItemEnum(..) => true,
-                                    _ => false,
-                                }
-                            }
-                            Some(_) => false,
-                        }
-                    }
-                    _ => false
-                }
-            }
-            _ => false
-        }
-    }
-
-    // Converts an implementation in the AST to a vector of items.
-    fn create_impl_from_item(&self, item: &Item) -> Vec<ImplOrTraitItemId> {
-        match item.node {
-            ItemImpl(_, ref trait_refs, _, ref ast_items) => {
-                let mut items: Vec<ImplOrTraitItemId> =
-                        ast_items.iter()
-                                 .map(|ast_item| {
-                            match *ast_item {
-                                ast::MethodImplItem(ref ast_method) => {
-                                    MethodTraitItemId(
-                                        local_def(ast_method.id))
-                                }
-                            }
-                        }).collect();
-
-                for trait_ref in trait_refs.iter() {
-                    let ty_trait_ref = ty::node_id_to_trait_ref(
-                        self.crate_context.tcx,
-                        trait_ref.ref_id);
-
-                    self.instantiate_default_methods(local_def(item.id),
-                                                     &*ty_trait_ref,
-                                                     &mut items);
-                }
-
-                items
-            }
-            _ => {
-                self.crate_context.tcx.sess.span_bug(item.span,
-                                                     "can't convert a non-impl to an impl");
-            }
-        }
-    }
-
-    fn span_of_impl(&self, impl_did: DefId) -> Span {
-        assert_eq!(impl_did.krate, LOCAL_CRATE);
-        self.crate_context.tcx.map.span(impl_did.node)
-    }
-
-    // External crate handling
-
-    fn add_external_impl(&self,
-                         impls_seen: &mut HashSet<DefId>,
-                         impl_def_id: DefId) {
-        let tcx = self.crate_context.tcx;
-        let impl_items = csearch::get_impl_items(&tcx.sess.cstore,
-                                                 impl_def_id);
-
-        // Make sure we don't visit the same implementation multiple times.
-        if !impls_seen.insert(impl_def_id) {
-            // Skip this one.
-            return
-        }
-        // Good. Continue.
-
-        let _ = lookup_item_type(tcx, impl_def_id);
-        let associated_traits = get_impl_trait(tcx, impl_def_id);
-
-        // Do a sanity check.
-        assert!(associated_traits.is_some());
-
-        // Record all the trait items.
-        for trait_ref in associated_traits.iter() {
-            self.add_trait_impl(trait_ref.def_id, impl_def_id);
-        }
-
-        // For any methods that use a default implementation, add them to
-        // the map. This is a bit unfortunate.
-        for item_def_id in impl_items.iter() {
-            let impl_item = ty::impl_or_trait_item(tcx, item_def_id.def_id());
-            match impl_item {
-                ty::MethodTraitItem(ref method) => {
-                    for &source in method.provided_source.iter() {
-                        tcx.provided_method_sources
-                           .borrow_mut()
-                           .insert(item_def_id.def_id(), source);
-                    }
-                }
-            }
-        }
-
-        tcx.impl_items.borrow_mut().insert(impl_def_id, impl_items);
-    }
-
-    // Adds implementations and traits from external crates to the coherence
-    // info.
-    fn add_external_crates(&self) {
-        let mut impls_seen = HashSet::new();
-
-        let crate_store = &self.crate_context.tcx.sess.cstore;
-        crate_store.iter_crate_data(|crate_number, _crate_metadata| {
-            each_impl(crate_store, crate_number, |def_id| {
-                assert_eq!(crate_number, def_id.krate);
-                self.add_external_impl(&mut impls_seen, def_id)
-            })
-        })
-    }
-
-    //
-    // Destructors
-    //
-
-    fn populate_destructor_table(&self) {
-        let tcx = self.crate_context.tcx;
-        let drop_trait = match tcx.lang_items.drop_trait() {
-            Some(id) => id, None => { return }
-        };
-
-        let impl_items = tcx.impl_items.borrow();
-        let trait_impls = match tcx.trait_impls.borrow().find_copy(&drop_trait) {
-            None => return, // No types with (new-style) dtors present.
-            Some(found_impls) => found_impls
-        };
-
-        for &impl_did in trait_impls.borrow().iter() {
-            let items = impl_items.get(&impl_did);
-            if items.len() < 1 {
-                // We'll error out later. For now, just don't ICE.
-                continue;
-            }
-            let method_def_id = *items.get(0);
-
-            let self_type = self.get_self_type_for_implementation(impl_did);
-            match ty::get(self_type.ty).sty {
-                ty::ty_enum(type_def_id, _) |
-                ty::ty_struct(type_def_id, _) |
-                ty::ty_unboxed_closure(type_def_id, _) => {
-                    tcx.destructor_for_type
-                       .borrow_mut()
-                       .insert(type_def_id, method_def_id.def_id());
-                    tcx.destructors
-                       .borrow_mut()
-                       .insert(method_def_id.def_id());
-                }
-                _ => {
-                    // Destructors only work on nominal types.
-                    if impl_did.krate == ast::LOCAL_CRATE {
-                        {
-                            match tcx.map.find(impl_did.node) {
-                                Some(ast_map::NodeItem(item)) => {
-                                    span_err!(tcx.sess, item.span, E0120,
-                                        "the Drop trait may only be implemented on structures");
-                                }
-                                _ => {
-                                    tcx.sess.bug("didn't find impl in ast \
-                                                  map");
-                                }
-                            }
-                        }
-                    } else {
-                        tcx.sess.bug("found external impl of Drop trait on \
-                                      something other than a struct");
-                    }
-                }
-            }
-        }
-    }
-}
-
-pub fn make_substs_for_receiver_types(tcx: &ty::ctxt,
-                                      trait_ref: &ty::TraitRef,
-                                      method: &ty::Method)
-                                      -> subst::Substs
-{
-    /*!
-     * Substitutes the values for the receiver's type parameters
-     * that are found in method, leaving the method's type parameters
-     * intact.
-     */
-
-    let meth_tps: Vec<ty::t> =
-        method.generics.types.get_slice(subst::FnSpace)
-              .iter()
-              .map(|def| ty::mk_param_from_def(tcx, def))
-              .collect();
-    let meth_regions: Vec<ty::Region> =
-        method.generics.regions.get_slice(subst::FnSpace)
-              .iter()
-              .map(|def| ty::ReEarlyBound(def.def_id.node, def.space,
-                                          def.index, def.name))
-              .collect();
-    trait_ref.substs.clone().with_method(meth_tps, meth_regions)
-}
-
-fn subst_receiver_types_in_method_ty(tcx: &ty::ctxt,
-                                     impl_id: ast::DefId,
-                                     impl_poly_type: &ty::Polytype,
-                                     trait_ref: &ty::TraitRef,
-                                     new_def_id: ast::DefId,
-                                     method: &ty::Method,
-                                     provided_source: Option<ast::DefId>)
-                                     -> ty::Method
-{
-    let combined_substs = make_substs_for_receiver_types(tcx, trait_ref, method);
-
-    debug!("subst_receiver_types_in_method_ty: combined_substs={}",
-           combined_substs.repr(tcx));
-
-    let mut method_generics = method.generics.subst(tcx, &combined_substs);
-
-    // replace the type parameters declared on the trait with those
-    // from the impl
-    for &space in [subst::TypeSpace, subst::SelfSpace].iter() {
-        method_generics.types.replace(
-            space,
-            Vec::from_slice(impl_poly_type.generics.types.get_slice(space)));
-        method_generics.regions.replace(
-            space,
-            Vec::from_slice(impl_poly_type.generics.regions.get_slice(space)));
-    }
-
-    debug!("subst_receiver_types_in_method_ty: method_generics={}",
-           method_generics.repr(tcx));
-
-    let method_fty = method.fty.subst(tcx, &combined_substs);
-
-    debug!("subst_receiver_types_in_method_ty: method_ty={}",
-           method.fty.repr(tcx));
-
-    ty::Method::new(
-        method.ident,
-        method_generics,
-        method_fty,
-        method.explicit_self,
-        method.vis,
-        new_def_id,
-        ImplContainer(impl_id),
-        provided_source
-    )
-}
-
-pub fn check_coherence(crate_context: &CrateCtxt) {
-    CoherenceChecker {
-        crate_context: crate_context,
-        inference_context: new_infer_ctxt(crate_context.tcx),
-    }.check(crate_context.tcx.map.krate());
-}
diff --git a/src/librustc/middle/typeck/coherence/mod.rs b/src/librustc/middle/typeck/coherence/mod.rs
new file mode 100644 (file)
index 0000000..76c5cab
--- /dev/null
@@ -0,0 +1,557 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Coherence phase
+//
+// The job of the coherence phase of typechecking is to ensure that
+// each trait has at most one implementation for each type. This is
+// done by the orphan and overlap modules. Then we build up various
+// mappings. That mapping code resides here.
+
+
+use metadata::csearch::{each_impl, get_impl_trait};
+use metadata::csearch;
+use middle::subst;
+use middle::subst::{Substs};
+use middle::ty::get;
+use middle::ty::{ImplContainer, ImplOrTraitItemId, MethodTraitItemId};
+use middle::ty::{lookup_item_type};
+use middle::ty::{t, ty_bool, ty_char, ty_bot, ty_box, ty_enum, ty_err};
+use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int, ty_nil, ty_open};
+use middle::ty::{ty_param, Polytype, ty_ptr};
+use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup};
+use middle::ty::{ty_uint, ty_unboxed_closure, ty_uniq, ty_bare_fn};
+use middle::ty::{ty_closure};
+use middle::ty::type_is_ty_var;
+use middle::subst::Subst;
+use middle::ty;
+use middle::typeck::CrateCtxt;
+use middle::typeck::infer::combine::Combine;
+use middle::typeck::infer::InferCtxt;
+use middle::typeck::infer::{new_infer_ctxt, resolve_ivar, resolve_type};
+use std::collections::{HashSet};
+use std::cell::RefCell;
+use std::rc::Rc;
+use syntax::ast::{Crate, DefId};
+use syntax::ast::{Item, ItemImpl};
+use syntax::ast::{LOCAL_CRATE, TraitRef};
+use syntax::ast;
+use syntax::ast_map::NodeItem;
+use syntax::ast_map;
+use syntax::ast_util::{local_def};
+use syntax::codemap::{Span};
+use syntax::parse::token;
+use syntax::visit;
+use util::nodemap::{DefIdMap, FnvHashMap};
+use util::ppaux::Repr;
+
+mod orphan;
+mod overlap;
+
+fn get_base_type(inference_context: &InferCtxt,
+                 span: Span,
+                 original_type: t)
+                 -> Option<t> {
+    let resolved_type = match resolve_type(inference_context,
+                                           Some(span),
+                                           original_type,
+                                           resolve_ivar) {
+        Ok(resulting_type) if !type_is_ty_var(resulting_type) => resulting_type,
+        _ => {
+            inference_context.tcx.sess.span_fatal(span,
+                                                  "the type of this value must be known in order \
+                                                   to determine the base type");
+        }
+    };
+
+    match get(resolved_type).sty {
+        ty_enum(..) | ty_struct(..) | ty_unboxed_closure(..) => {
+            debug!("(getting base type) found base type");
+            Some(resolved_type)
+        }
+
+        _ if ty::type_is_trait(resolved_type) => {
+            debug!("(getting base type) found base type (trait)");
+            Some(resolved_type)
+        }
+
+        ty_nil | ty_bot | ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) |
+        ty_str(..) | ty_vec(..) | ty_bare_fn(..) | ty_closure(..) | ty_tup(..) |
+        ty_infer(..) | ty_param(..) | ty_err | ty_open(..) |
+        ty_box(_) | ty_uniq(_) | ty_ptr(_) | ty_rptr(_, _) => {
+            debug!("(getting base type) no base type; found {:?}",
+                   get(original_type).sty);
+            None
+        }
+        ty_trait(..) => fail!("should have been caught")
+    }
+}
+
+// Returns the def ID of the base type, if there is one.
+fn get_base_type_def_id(inference_context: &InferCtxt,
+                        span: Span,
+                        original_type: t)
+                        -> Option<DefId> {
+    match get_base_type(inference_context, span, original_type) {
+        None => None,
+        Some(base_type) => {
+            match get(base_type).sty {
+                ty_enum(def_id, _) |
+                ty_struct(def_id, _) |
+                ty_unboxed_closure(def_id, _) => {
+                    Some(def_id)
+                }
+                ty_ptr(ty::mt {ty, ..}) |
+                ty_rptr(_, ty::mt {ty, ..}) |
+                ty_uniq(ty) => {
+                    match ty::get(ty).sty {
+                        ty_trait(box ty::TyTrait { def_id, .. }) => {
+                            Some(def_id)
+                        }
+                        _ => {
+                            fail!("get_base_type() returned a type that wasn't an \
+                                   enum, struct, or trait");
+                        }
+                    }
+                }
+                ty_trait(box ty::TyTrait { def_id, .. }) => {
+                    Some(def_id)
+                }
+                _ => {
+                    fail!("get_base_type() returned a type that wasn't an \
+                           enum, struct, or trait");
+                }
+            }
+        }
+    }
+}
+
+struct CoherenceChecker<'a, 'tcx: 'a> {
+    crate_context: &'a CrateCtxt<'a, 'tcx>,
+    inference_context: InferCtxt<'a, 'tcx>,
+    inherent_impls: RefCell<DefIdMap<Rc<RefCell<Vec<ast::DefId>>>>>,
+}
+
+struct CoherenceCheckVisitor<'a, 'tcx: 'a> {
+    cc: &'a CoherenceChecker<'a, 'tcx>
+}
+
+impl<'a, 'tcx, 'v> visit::Visitor<'v> for CoherenceCheckVisitor<'a, 'tcx> {
+    fn visit_item(&mut self, item: &Item) {
+
+        //debug!("(checking coherence) item '{}'", token::get_ident(item.ident));
+
+        match item.node {
+            ItemImpl(_, ref opt_trait, _, _) => {
+                match opt_trait.clone() {
+                    Some(opt_trait) => {
+                        self.cc.check_implementation(item, [opt_trait]);
+                    }
+                    None => self.cc.check_implementation(item, [])
+                }
+            }
+            _ => {
+                // Nothing to do.
+            }
+        };
+
+        visit::walk_item(self, item);
+    }
+}
+
+impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
+    fn check(&self, krate: &Crate) {
+        // Check implementations and traits. This populates the tables
+        // containing the inherent methods and extension methods. It also
+        // builds up the trait inheritance table.
+        let mut visitor = CoherenceCheckVisitor { cc: self };
+        visit::walk_crate(&mut visitor, krate);
+
+        // Copy over the inherent impls we gathered up during the walk into
+        // the tcx.
+        let mut tcx_inherent_impls =
+            self.crate_context.tcx.inherent_impls.borrow_mut();
+        for (k, v) in self.inherent_impls.borrow().iter() {
+            tcx_inherent_impls.insert((*k).clone(),
+                                      Rc::new((*v.borrow()).clone()));
+        }
+
+        // Bring in external crates. It's fine for this to happen after the
+        // coherence checks, because we ensure by construction that no errors
+        // can happen at link time.
+        self.add_external_crates();
+
+        // Populate the table of destructors. It might seem a bit strange to
+        // do this here, but it's actually the most convenient place, since
+        // the coherence tables contain the trait -> type mappings.
+        self.populate_destructor_table();
+    }
+
+    fn check_implementation(&self,
+                            item: &Item,
+                            associated_traits: &[TraitRef]) {
+        let tcx = self.crate_context.tcx;
+        let impl_did = local_def(item.id);
+        let self_type = ty::lookup_item_type(tcx, impl_did);
+
+        // If there are no traits, then this implementation must have a
+        // base type.
+
+        let impl_items = self.create_impl_from_item(item);
+
+        for associated_trait in associated_traits.iter() {
+            let trait_ref = ty::node_id_to_trait_ref(
+                self.crate_context.tcx, associated_trait.ref_id);
+            debug!("(checking implementation) adding impl for trait '{}', item '{}'",
+                   trait_ref.repr(self.crate_context.tcx),
+                   token::get_ident(item.ident));
+
+            self.add_trait_impl(trait_ref.def_id, impl_did);
+        }
+
+        // Add the implementation to the mapping from implementation to base
+        // type def ID, if there is a base type for this implementation and
+        // the implementation does not have any associated traits.
+        match get_base_type_def_id(&self.inference_context,
+                                   item.span,
+                                   self_type.ty) {
+            None => {
+                // Nothing to do.
+            }
+            Some(base_type_def_id) => {
+                // FIXME: Gather up default methods?
+                if associated_traits.len() == 0 {
+                    self.add_inherent_impl(base_type_def_id, impl_did);
+                }
+            }
+        }
+
+        tcx.impl_items.borrow_mut().insert(impl_did, impl_items);
+    }
+
+    // Creates default method IDs and performs type substitutions for an impl
+    // and trait pair. Then, for each provided method in the trait, inserts a
+    // `ProvidedMethodInfo` instance into the `provided_method_sources` map.
+    fn instantiate_default_methods(
+            &self,
+            impl_id: DefId,
+            trait_ref: &ty::TraitRef,
+            all_impl_items: &mut Vec<ImplOrTraitItemId>) {
+        let tcx = self.crate_context.tcx;
+        debug!("instantiate_default_methods(impl_id={:?}, trait_ref={})",
+               impl_id, trait_ref.repr(tcx));
+
+        let impl_poly_type = ty::lookup_item_type(tcx, impl_id);
+
+        let prov = ty::provided_trait_methods(tcx, trait_ref.def_id);
+        for trait_method in prov.iter() {
+            // Synthesize an ID.
+            let new_id = tcx.sess.next_node_id();
+            let new_did = local_def(new_id);
+
+            debug!("new_did={:?} trait_method={}", new_did, trait_method.repr(tcx));
+
+            // Create substitutions for the various trait parameters.
+            let new_method_ty =
+                Rc::new(subst_receiver_types_in_method_ty(
+                    tcx,
+                    impl_id,
+                    &impl_poly_type,
+                    trait_ref,
+                    new_did,
+                    &**trait_method,
+                    Some(trait_method.def_id)));
+
+            debug!("new_method_ty={}", new_method_ty.repr(tcx));
+            all_impl_items.push(MethodTraitItemId(new_did));
+
+            // construct the polytype for the method based on the
+            // method_ty.  it will have all the generics from the
+            // impl, plus its own.
+            let new_polytype = ty::Polytype {
+                generics: new_method_ty.generics.clone(),
+                ty: ty::mk_bare_fn(tcx, new_method_ty.fty.clone())
+            };
+            debug!("new_polytype={}", new_polytype.repr(tcx));
+
+            tcx.tcache.borrow_mut().insert(new_did, new_polytype);
+            tcx.impl_or_trait_items
+               .borrow_mut()
+               .insert(new_did, ty::MethodTraitItem(new_method_ty));
+
+            // Pair the new synthesized ID up with the
+            // ID of the method.
+            self.crate_context.tcx.provided_method_sources.borrow_mut()
+                .insert(new_did, trait_method.def_id);
+        }
+    }
+
+    fn add_inherent_impl(&self, base_def_id: DefId, impl_def_id: DefId) {
+        match self.inherent_impls.borrow().find(&base_def_id) {
+            Some(implementation_list) => {
+                implementation_list.borrow_mut().push(impl_def_id);
+                return;
+            }
+            None => {}
+        }
+
+        self.inherent_impls.borrow_mut().insert(
+            base_def_id,
+            Rc::new(RefCell::new(vec!(impl_def_id))));
+    }
+
+    fn add_trait_impl(&self, base_def_id: DefId, impl_def_id: DefId) {
+        debug!("add_trait_impl: base_def_id={} impl_def_id={}",
+               base_def_id, impl_def_id);
+        ty::record_trait_implementation(self.crate_context.tcx,
+                                        base_def_id,
+                                        impl_def_id);
+    }
+
+    fn get_self_type_for_implementation(&self, impl_did: DefId)
+                                        -> Polytype {
+        self.crate_context.tcx.tcache.borrow().get_copy(&impl_did)
+    }
+
+    // Converts an implementation in the AST to a vector of items.
+    fn create_impl_from_item(&self, item: &Item) -> Vec<ImplOrTraitItemId> {
+        match item.node {
+            ItemImpl(_, ref trait_refs, _, ref ast_items) => {
+                let mut items: Vec<ImplOrTraitItemId> =
+                        ast_items.iter()
+                                 .map(|ast_item| {
+                            match *ast_item {
+                                ast::MethodImplItem(ref ast_method) => {
+                                    MethodTraitItemId(
+                                        local_def(ast_method.id))
+                                }
+                            }
+                        }).collect();
+
+                for trait_ref in trait_refs.iter() {
+                    let ty_trait_ref = ty::node_id_to_trait_ref(
+                        self.crate_context.tcx,
+                        trait_ref.ref_id);
+
+                    self.instantiate_default_methods(local_def(item.id),
+                                                     &*ty_trait_ref,
+                                                     &mut items);
+                }
+
+                items
+            }
+            _ => {
+                self.crate_context.tcx.sess.span_bug(item.span,
+                                                     "can't convert a non-impl to an impl");
+            }
+        }
+    }
+
+    // External crate handling
+
+    fn add_external_impl(&self,
+                         impls_seen: &mut HashSet<DefId>,
+                         impl_def_id: DefId) {
+        let tcx = self.crate_context.tcx;
+        let impl_items = csearch::get_impl_items(&tcx.sess.cstore,
+                                                 impl_def_id);
+
+        // Make sure we don't visit the same implementation multiple times.
+        if !impls_seen.insert(impl_def_id) {
+            // Skip this one.
+            return
+        }
+        // Good. Continue.
+
+        let _ = lookup_item_type(tcx, impl_def_id);
+        let associated_traits = get_impl_trait(tcx, impl_def_id);
+
+        // Do a sanity check.
+        assert!(associated_traits.is_some());
+
+        // Record all the trait items.
+        for trait_ref in associated_traits.iter() {
+            self.add_trait_impl(trait_ref.def_id, impl_def_id);
+        }
+
+        // For any methods that use a default implementation, add them to
+        // the map. This is a bit unfortunate.
+        for item_def_id in impl_items.iter() {
+            let impl_item = ty::impl_or_trait_item(tcx, item_def_id.def_id());
+            match impl_item {
+                ty::MethodTraitItem(ref method) => {
+                    for &source in method.provided_source.iter() {
+                        tcx.provided_method_sources
+                           .borrow_mut()
+                           .insert(item_def_id.def_id(), source);
+                    }
+                }
+            }
+        }
+
+        tcx.impl_items.borrow_mut().insert(impl_def_id, impl_items);
+    }
+
+    // Adds implementations and traits from external crates to the coherence
+    // info.
+    fn add_external_crates(&self) {
+        let mut impls_seen = HashSet::new();
+
+        let crate_store = &self.crate_context.tcx.sess.cstore;
+        crate_store.iter_crate_data(|crate_number, _crate_metadata| {
+            each_impl(crate_store, crate_number, |def_id| {
+                assert_eq!(crate_number, def_id.krate);
+                self.add_external_impl(&mut impls_seen, def_id)
+            })
+        })
+    }
+
+    //
+    // Destructors
+    //
+
+    fn populate_destructor_table(&self) {
+        let tcx = self.crate_context.tcx;
+        let drop_trait = match tcx.lang_items.drop_trait() {
+            Some(id) => id, None => { return }
+        };
+
+        let impl_items = tcx.impl_items.borrow();
+        let trait_impls = match tcx.trait_impls.borrow().find_copy(&drop_trait) {
+            None => return, // No types with (new-style) dtors present.
+            Some(found_impls) => found_impls
+        };
+
+        for &impl_did in trait_impls.borrow().iter() {
+            let items = impl_items.get(&impl_did);
+            if items.len() < 1 {
+                // We'll error out later. For now, just don't ICE.
+                continue;
+            }
+            let method_def_id = *items.get(0);
+
+            let self_type = self.get_self_type_for_implementation(impl_did);
+            match ty::get(self_type.ty).sty {
+                ty::ty_enum(type_def_id, _) |
+                ty::ty_struct(type_def_id, _) |
+                ty::ty_unboxed_closure(type_def_id, _) => {
+                    tcx.destructor_for_type
+                       .borrow_mut()
+                       .insert(type_def_id, method_def_id.def_id());
+                    tcx.destructors
+                       .borrow_mut()
+                       .insert(method_def_id.def_id());
+                }
+                _ => {
+                    // Destructors only work on nominal types.
+                    if impl_did.krate == ast::LOCAL_CRATE {
+                        {
+                            match tcx.map.find(impl_did.node) {
+                                Some(ast_map::NodeItem(item)) => {
+                                    span_err!(tcx.sess, item.span, E0120,
+                                        "the Drop trait may only be implemented on structures");
+                                }
+                                _ => {
+                                    tcx.sess.bug("didn't find impl in ast \
+                                                  map");
+                                }
+                            }
+                        }
+                    } else {
+                        tcx.sess.bug("found external impl of Drop trait on \
+                                      something other than a struct");
+                    }
+                }
+            }
+        }
+    }
+}
+
+pub fn make_substs_for_receiver_types(tcx: &ty::ctxt,
+                                      trait_ref: &ty::TraitRef,
+                                      method: &ty::Method)
+                                      -> subst::Substs
+{
+    /*!
+     * Substitutes the values for the receiver's type parameters
+     * that are found in method, leaving the method's type parameters
+     * intact.
+     */
+
+    let meth_tps: Vec<ty::t> =
+        method.generics.types.get_slice(subst::FnSpace)
+              .iter()
+              .map(|def| ty::mk_param_from_def(tcx, def))
+              .collect();
+    let meth_regions: Vec<ty::Region> =
+        method.generics.regions.get_slice(subst::FnSpace)
+              .iter()
+              .map(|def| ty::ReEarlyBound(def.def_id.node, def.space,
+                                          def.index, def.name))
+              .collect();
+    trait_ref.substs.clone().with_method(meth_tps, meth_regions)
+}
+
+fn subst_receiver_types_in_method_ty(tcx: &ty::ctxt,
+                                     impl_id: ast::DefId,
+                                     impl_poly_type: &ty::Polytype,
+                                     trait_ref: &ty::TraitRef,
+                                     new_def_id: ast::DefId,
+                                     method: &ty::Method,
+                                     provided_source: Option<ast::DefId>)
+                                     -> ty::Method
+{
+    let combined_substs = make_substs_for_receiver_types(tcx, trait_ref, method);
+
+    debug!("subst_receiver_types_in_method_ty: combined_substs={}",
+           combined_substs.repr(tcx));
+
+    let mut method_generics = method.generics.subst(tcx, &combined_substs);
+
+    // replace the type parameters declared on the trait with those
+    // from the impl
+    for &space in [subst::TypeSpace, subst::SelfSpace].iter() {
+        method_generics.types.replace(
+            space,
+            Vec::from_slice(impl_poly_type.generics.types.get_slice(space)));
+        method_generics.regions.replace(
+            space,
+            Vec::from_slice(impl_poly_type.generics.regions.get_slice(space)));
+    }
+
+    debug!("subst_receiver_types_in_method_ty: method_generics={}",
+           method_generics.repr(tcx));
+
+    let method_fty = method.fty.subst(tcx, &combined_substs);
+
+    debug!("subst_receiver_types_in_method_ty: method_ty={}",
+           method.fty.repr(tcx));
+
+    ty::Method::new(
+        method.ident,
+        method_generics,
+        method_fty,
+        method.explicit_self,
+        method.vis,
+        new_def_id,
+        ImplContainer(impl_id),
+        provided_source
+    )
+}
+
+pub fn check_coherence(crate_context: &CrateCtxt) {
+    CoherenceChecker {
+        crate_context: crate_context,
+        inference_context: new_infer_ctxt(crate_context.tcx),
+        inherent_impls: RefCell::new(FnvHashMap::new()),
+    }.check(crate_context.tcx.map.krate());
+    orphan::check(crate_context.tcx);
+    overlap::check(crate_context.tcx);
+}
diff --git a/src/librustc/middle/typeck/coherence/orphan.rs b/src/librustc/middle/typeck/coherence/orphan.rs
new file mode 100644 (file)
index 0000000..e7139e1
--- /dev/null
@@ -0,0 +1,75 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/*!
+ * Orphan checker: every impl either implements a trait defined in this
+ * crate or pertains to a type defined in this crate.
+ */
+
+use middle::traits;
+use middle::ty;
+use syntax::ast::{Item, ItemImpl};
+use syntax::ast;
+use syntax::ast_util;
+use syntax::visit;
+use util::ppaux::Repr;
+
+pub fn check(tcx: &ty::ctxt) {
+    let mut orphan = OrphanChecker { tcx: tcx };
+    visit::walk_crate(&mut orphan, tcx.map.krate());
+}
+
+struct OrphanChecker<'cx, 'tcx:'cx> {
+    tcx: &'cx ty::ctxt<'tcx>
+}
+
+impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
+    fn visit_item(&mut self, item: &'v ast::Item) {
+        let def_id = ast_util::local_def(item.id);
+        match item.node {
+            ast::ItemImpl(_, None, _, _) => {
+                // For inherent impls, self type must be a nominal type
+                // defined in this crate.
+                debug!("coherence2::orphan check: inherent impl {}", item.repr(self.tcx));
+                let self_ty = ty::lookup_item_type(self.tcx, def_id).ty;
+                match ty::get(self_ty).sty {
+                    ty::ty_enum(def_id, _) |
+                    ty::ty_struct(def_id, _) => {
+                        if def_id.krate != ast::LOCAL_CRATE {
+                            span_err!(self.tcx.sess, item.span, E0116,
+                                      "cannot associate methods with a type outside the \
+                                      crate the type is defined in; define and implement \
+                                      a trait or new type instead");
+                        }
+                    }
+                    _ => {
+                        span_err!(self.tcx.sess, item.span, E0118,
+                                  "no base type found for inherent implementation; \
+                                   implement a trait or new type instead");
+                    }
+                }
+            }
+            ast::ItemImpl(_, Some(_), _, _) => {
+                // "Trait" impl
+                debug!("coherence2::orphan check: trait impl {}", item.repr(self.tcx));
+                if traits::is_orphan_impl(self.tcx, def_id) {
+                    span_err!(self.tcx.sess, item.span, E0117,
+                              "cannot provide an extension implementation \
+                               where both trait and type are not defined in this crate");
+                }
+            }
+            _ => {
+                // Not an impl
+            }
+        }
+
+        visit::walk_item(self, item);
+    }
+}
diff --git a/src/librustc/middle/typeck/coherence/overlap.rs b/src/librustc/middle/typeck/coherence/overlap.rs
new file mode 100644 (file)
index 0000000..48f71d9
--- /dev/null
@@ -0,0 +1,119 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/*!
+ * Overlap: No two impls for the same trait are implemented for the
+ * same type.
+ */
+
+use middle::traits;
+use middle::ty;
+use middle::typeck::infer::{new_infer_ctxt};
+use middle::typeck::infer;
+use syntax::ast::{DefId};
+use syntax::ast::{LOCAL_CRATE};
+use syntax::ast;
+use syntax::codemap::{Span};
+use util::ppaux::Repr;
+
+pub fn check(tcx: &ty::ctxt) {
+    let overlap = OverlapChecker { tcx: tcx };
+    overlap.check_for_overlapping_impls();
+}
+
+struct OverlapChecker<'cx, 'tcx:'cx> {
+    tcx: &'cx ty::ctxt<'tcx>
+}
+
+impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
+    fn check_for_overlapping_impls(&self) {
+        debug!("check_for_overlapping_impls");
+        let trait_impls = self.tcx.trait_impls.borrow();
+        for trait_def_id in trait_impls.keys() {
+            self.check_for_overlapping_impls_of_trait(*trait_def_id);
+        }
+    }
+
+    fn check_for_overlapping_impls_of_trait(&self,
+                                            trait_def_id: ast::DefId)
+    {
+        debug!("check_for_overlapping_impls_of_trait(trait_def_id={})",
+               trait_def_id.repr(self.tcx));
+
+        // FIXME -- it seems like this method actually pushes
+        // duplicate impls onto the list
+        ty::populate_implementations_for_type_if_necessary(self.tcx,
+                                                           trait_def_id);
+
+        let mut impls = Vec::new();
+        self.push_impls_of_trait(trait_def_id, &mut impls);
+
+        for (i, &impl1_def_id) in impls.iter().enumerate() {
+            if impl1_def_id.krate != ast::LOCAL_CRATE {
+                // we don't need to check impls if both are external;
+                // that's the other crate's job.
+                continue;
+            }
+
+            for &impl2_def_id in impls.slice_from(i+1).iter() {
+                self.check_if_impls_overlap(trait_def_id,
+                                            impl1_def_id,
+                                            impl2_def_id);
+            }
+        }
+    }
+
+    fn check_if_impls_overlap(&self,
+                              trait_def_id: ast::DefId,
+                              impl1_def_id: ast::DefId,
+                              impl2_def_id: ast::DefId)
+    {
+        assert_eq!(impl1_def_id.krate, ast::LOCAL_CRATE);
+
+        debug!("check_if_impls_overlap({}, {}, {})",
+               trait_def_id.repr(self.tcx),
+               impl1_def_id.repr(self.tcx),
+               impl2_def_id.repr(self.tcx));
+
+        let infcx = infer::new_infer_ctxt(self.tcx);
+        if !traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id) {
+            return;
+        }
+
+        span_err!(self.tcx.sess, self.span_of_impl(impl1_def_id), E0119,
+                  "conflicting implementations for trait `{}`",
+                  ty::item_path_str(self.tcx, trait_def_id));
+
+        if impl2_def_id.krate == ast::LOCAL_CRATE {
+            span_note!(self.tcx.sess, self.span_of_impl(impl2_def_id),
+                       "note conflicting implementation here");
+        } else {
+            let crate_store = &self.tcx.sess.cstore;
+            let cdata = crate_store.get_crate_data(impl2_def_id.krate);
+            span_note!(self.tcx.sess, self.span_of_impl(impl1_def_id),
+                       "conflicting implementation in crate `{}`",
+                       cdata.name);
+        }
+    }
+
+    fn push_impls_of_trait(&self,
+                           trait_def_id: ast::DefId,
+                           out: &mut Vec<ast::DefId>) {
+        match self.tcx.trait_impls.borrow().find(&trait_def_id) {
+            Some(impls) => { out.push_all(impls.borrow().as_slice()); }
+            None => { /* no impls */ }
+        }
+    }
+
+    fn span_of_impl(&self, impl_did: ast::DefId) -> Span {
+        assert_eq!(impl_did.krate, ast::LOCAL_CRATE);
+        self.tcx.map.span(impl_did.node)
+    }
+}
index e0afb80ad37f5ee203f30366849e54d619c19791..7272425761e026824f065224208c44e62c9f1a84 100644 (file)
@@ -226,7 +226,7 @@ fn build_impls(cx: &DocContext, tcx: &ty::ctxt,
     match tcx.inherent_impls.borrow().find(&did) {
         None => {}
         Some(i) => {
-            impls.extend(i.borrow().iter().map(|&did| { build_impl(cx, tcx, did) }));
+            impls.extend(i.iter().map(|&did| { build_impl(cx, tcx, did) }));
         }
     }