From a5c707aadc0da2e3a12af48cc1bed20884827702 Mon Sep 17 00:00:00 2001
From: Gianni Ciccarelli <gianni.ciccarelli@gmail.com>
Date: Tue, 3 Apr 2018 07:26:22 +0000
Subject: [PATCH 1/2] intersection impls

---
 src/librustc/traits/coherence.rs              |  14 +-
 src/librustc/traits/specialize/mod.rs         |  39 +-
 .../traits/specialize/specialization_graph.rs | 355 ++++++++++++------
 ...herence-conflicting-negative-trait-impl.rs |   1 +
 .../specialization/intersection-impl.rs       |  36 ++
 .../specialization/intersection-impl-2.rs     |  63 ++++
 .../specialization/intersection-impl.rs       |  42 +++
 7 files changed, 423 insertions(+), 127 deletions(-)
 create mode 100644 src/test/compile-fail/specialization/intersection-impl.rs
 create mode 100644 src/test/run-pass/specialization/intersection-impl-2.rs
 create mode 100644 src/test/run-pass/specialization/intersection-impl.rs

diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs
index 31f8af1f96872..1a763587f0eb7 100644
--- a/src/librustc/traits/coherence.rs
+++ b/src/librustc/traits/coherence.rs
@@ -8,15 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! See rustc guide chapters on [trait-resolution] and [trait-specialization] for more info on how
-//! this works.
-//!
-//! [trait-resolution]: https://rust-lang-nursery.github.io/rustc-guide/trait-resolution.html
-//! [trait-specialization]: https://rust-lang-nursery.github.io/rustc-guide/trait-specialization.html
+//! See `README.md` for high-level documentation
 
 use hir::def_id::{DefId, LOCAL_CRATE};
 use syntax_pos::DUMMY_SP;
-use traits::{self, Normalized, SelectionContext, Obligation, ObligationCause};
+use traits::{self, Normalized, SelectionContext, Obligation, ObligationCause, Reveal};
 use traits::IntercrateMode;
 use traits::select::IntercrateAmbiguityCause;
 use ty::{self, Ty, TyCtxt};
@@ -123,7 +119,7 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
     // types into scope; instead, we replace the generic types with
     // fresh type variables, and hence we do our evaluations in an
     // empty environment.
-    let param_env = ty::ParamEnv::empty();
+    let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
 
     let a_impl_header = with_fresh_ty_vars(selcx, param_env, a_def_id);
     let b_impl_header = with_fresh_ty_vars(selcx, param_env, b_def_id);
@@ -140,7 +136,7 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
         Err(_) => return None
     };
 
-    debug!("overlap: unification check succeeded");
+    debug!("overlap: unification check succeeded {:?}", obligations);
 
     // Are any of the obligations unsatisfiable? If so, no overlap.
     let infcx = selcx.infcx();
@@ -281,7 +277,7 @@ pub fn orphan_check<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
 ///     is bad, because the only local type with `T` as a subtree is
 ///     `LocalType<T>`, and `Vec<->` is between it and the type parameter.
 ///     - similarly, `FundamentalPair<LocalType<T>, T>` is bad, because
-///     the second occurrence of `T` is not a subtree of *any* local type.
+///     the second occurence of `T` is not a subtree of *any* local type.
 ///     - however, `LocalType<Vec<T>>` is OK, because `T` is a subtree of
 ///     `LocalType<Vec<T>>`, which is local and has no types between it and
 ///     the type parameter.
diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs
index 30b2c55afa194..11e7e4f6b9a1a 100644
--- a/src/librustc/traits/specialize/mod.rs
+++ b/src/librustc/traits/specialize/mod.rs
@@ -42,6 +42,7 @@ pub struct OverlapError {
     pub trait_desc: String,
     pub self_desc: Option<String>,
     pub intercrate_ambiguity_causes: Vec<IntercrateAmbiguityCause>,
+    pub used_to_be_allowed: bool,
 }
 
 /// Given a subst for the requested impl, translate it to a subst
@@ -324,29 +325,48 @@ pub(super) fn specialization_graph_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx
          def_id.index.as_array_index())
     });
 
+    let mut overlaps = Vec::new();
+
     for impl_def_id in trait_impls {
         if impl_def_id.is_local() {
-            // This is where impl overlap checking happens:
             let insert_result = sg.insert(tcx, impl_def_id);
-            // Report error if there was one.
-            let (overlap, used_to_be_allowed) = match insert_result {
-                Err(overlap) => (Some(overlap), false),
-                Ok(opt_overlap) => (opt_overlap, true)
+            match insert_result {
+                Ok(Some(mut opt_overlaps)) => {
+                    // record any overlap that occurs between two impl
+                    // later those recordings are processed to establish
+                    // if an intersection impl is present between two overlapping impls
+                    // if no an overlap error is emitted
+                    for opt_overlap in opt_overlaps {
+                        overlaps.push((impl_def_id, opt_overlap));
+                    }
+                },
+                _ => {},
             };
 
-            if let Some(overlap) = overlap {
+        } else {
+            let parent = tcx.impl_parent(impl_def_id).unwrap_or(trait_id);
+            sg.record_impl_from_cstore(tcx, parent, impl_def_id)
+        }
+    }
+
+    if overlaps.len() > 0 {
+        // Build the graph only if there is at least an overlap
+        let (graph, nodes_idx) = sg.build_graph();
+        for (impl_def_id, overlap) in overlaps {
+            if !sg.check_overlap(&graph, &nodes_idx, impl_def_id, overlap.with_impl) {
+
                 let msg = format!("conflicting implementations of trait `{}`{}:{}",
                     overlap.trait_desc,
                     overlap.self_desc.clone().map_or(
                         String::new(), |ty| {
                             format!(" for type `{}`", ty)
                         }),
-                    if used_to_be_allowed { " (E0119)" } else { "" }
+                    if overlap.used_to_be_allowed { " (E0119)" } else { "" }
                 );
                 let impl_span = tcx.sess.codemap().def_span(
                     tcx.span_of_impl(impl_def_id).unwrap()
                 );
-                let mut err = if used_to_be_allowed {
+                let mut err = if overlap.used_to_be_allowed {
                     tcx.struct_span_lint_node(
                         lint::builtin::INCOHERENT_FUNDAMENTAL_IMPLS,
                         tcx.hir.as_local_node_id(impl_def_id).unwrap(),
@@ -386,9 +406,6 @@ pub(super) fn specialization_graph_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx
 
                 err.emit();
             }
-        } else {
-            let parent = tcx.impl_parent(impl_def_id).unwrap_or(trait_id);
-            sg.record_impl_from_cstore(tcx, parent, impl_def_id)
         }
     }
 
diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs
index e56a8662f3eb4..590460b06c2a4 100644
--- a/src/librustc/traits/specialize/specialization_graph.rs
+++ b/src/librustc/traits/specialize/specialization_graph.rs
@@ -12,8 +12,8 @@ use super::OverlapError;
 
 use hir::def_id::DefId;
 use ich::{self, StableHashingContext};
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
-                                           StableHasherResult};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult};
+use rustc_data_structures::graph::{Graph as DataStructuresGraph, NodeIndex, INCOMING};
 use traits;
 use ty::{self, TyCtxt, TypeFoldable};
 use ty::fast_reject::{self, SimplifiedType};
@@ -39,9 +39,9 @@ use util::nodemap::{DefIdMap, FxHashMap};
 ///   has at most one parent.
 #[derive(RustcEncodable, RustcDecodable)]
 pub struct Graph {
-    // all impls have a parent; the "root" impls have as their parent the def_id
+    // all impls have one or more parents; the "root" impls have as their parent the def_id
     // of the trait
-    parent: DefIdMap<DefId>,
+    parent: DefIdMap<Vec<DefId>>,
 
     // the "root" impls are found by looking up the trait's def_id.
     children: DefIdMap<Children>,
@@ -60,7 +60,6 @@ struct Children {
     // A similar division is used within `TraitDef`, but the lists there collect
     // together *all* the impls for a trait, and are populated prior to building
     // the specialization graph.
-
     /// Impls of the trait.
     nonblanket_impls: FxHashMap<fast_reject::SimplifiedType, Vec<DefId>>,
 
@@ -89,12 +88,13 @@ impl<'a, 'gcx, 'tcx> Children {
     }
 
     /// Insert an impl into this set of children without comparing to any existing impls
-    fn insert_blindly(&mut self,
-                      tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                      impl_def_id: DefId) {
+    fn insert_blindly(&mut self, tcx: TyCtxt<'a, 'gcx, 'tcx>, impl_def_id: DefId) {
         let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
         if let Some(sty) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false) {
-            self.nonblanket_impls.entry(sty).or_insert(vec![]).push(impl_def_id)
+            self.nonblanket_impls
+                .entry(sty)
+                .or_insert(vec![])
+                .push(impl_def_id)
         } else {
             self.blanket_impls.push(impl_def_id)
         }
@@ -102,21 +102,26 @@ impl<'a, 'gcx, 'tcx> Children {
 
     /// Attempt to insert an impl into this set of children, while comparing for
     /// specialization relationships.
-    fn insert(&mut self,
-              tcx: TyCtxt<'a, 'gcx, 'tcx>,
-              impl_def_id: DefId,
-              simplified_self: Option<SimplifiedType>)
-              -> Result<Inserted, OverlapError>
-    {
+    fn insert(
+        &mut self,
+        tcx: TyCtxt<'a, 'gcx, 'tcx>,
+        impl_def_id: DefId,
+        simplified_self: Option<SimplifiedType>,
+    ) -> Result<Vec<Inserted>, OverlapError> {
         let mut last_lint = None;
 
+        // Nodes could specialize more than one parent
+        // so every impl must visited in order to properly place it
+        let mut inserted_results = Vec::new();
+
         for slot in match simplified_self {
             Some(sty) => self.filtered_mut(sty),
             None => self.iter_mut(),
         } {
             let possible_sibling = *slot;
 
-            let overlap_error = |overlap: traits::coherence::OverlapResult| {
+            let overlap_error = |overlap: traits::coherence::OverlapResult,
+                                 used_to_be_allowed: bool| {
                 // overlap, but no specialization; error out
                 let trait_ref = overlap.impl_header.trait_ref.unwrap();
                 let self_ty = trait_ref.self_ty();
@@ -132,45 +137,52 @@ impl<'a, 'gcx, 'tcx> Children {
                         None
                     },
                     intercrate_ambiguity_causes: overlap.intercrate_ambiguity_causes,
+                    used_to_be_allowed: used_to_be_allowed,
                 }
             };
 
             let tcx = tcx.global_tcx();
-            let (le, ge) = traits::overlapping_impls(
+            let (le, ge, overlap_er) = traits::overlapping_impls(
                 tcx,
                 possible_sibling,
                 impl_def_id,
                 traits::IntercrateMode::Issue43355,
                 |overlap| {
                     if tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) {
-                        return Ok((false, false));
+                        return Ok((false, false, None));
                     }
 
                     let le = tcx.specializes((impl_def_id, possible_sibling));
                     let ge = tcx.specializes((possible_sibling, impl_def_id));
 
                     if le == ge {
-                        Err(overlap_error(overlap))
+                        Ok((true, true, Some(overlap_error(overlap, false))))
                     } else {
-                        Ok((le, ge))
+                        Ok((le, ge, None))
                     }
                 },
-                || Ok((false, false)),
+                || Ok((false, false, None)),
             )?;
 
             if le && !ge {
-                debug!("descending as child of TraitRef {:?}",
-                       tcx.impl_trait_ref(possible_sibling).unwrap());
+                debug!(
+                    "descending as child of TraitRef {:?}",
+                    tcx.impl_trait_ref(possible_sibling).unwrap()
+                );
 
                 // the impl specializes possible_sibling
-                return Ok(Inserted::ShouldRecurseOn(possible_sibling));
+                inserted_results.push(Inserted::ShouldRecurseOn(possible_sibling));
             } else if ge && !le {
-                debug!("placing as parent of TraitRef {:?}",
-                       tcx.impl_trait_ref(possible_sibling).unwrap());
-
-                    // possible_sibling specializes the impl
-                    *slot = impl_def_id;
-                return Ok(Inserted::Replaced(possible_sibling));
+                debug!(
+                    "placing as parent of TraitRef {:?}",
+                    tcx.impl_trait_ref(possible_sibling).unwrap()
+                );
+
+                // possible_sibling specializes the impl
+                *slot = impl_def_id;
+                inserted_results.push(Inserted::Replaced(possible_sibling));
+            } else if ge && le {
+                last_lint = overlap_er;
             } else {
                 if !tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) {
                     traits::overlapping_impls(
@@ -178,7 +190,7 @@ impl<'a, 'gcx, 'tcx> Children {
                         possible_sibling,
                         impl_def_id,
                         traits::IntercrateMode::Fixed,
-                        |overlap| last_lint = Some(overlap_error(overlap)),
+                        |overlap| last_lint = Some(overlap_error(overlap, true)),
                         || (),
                     );
                 }
@@ -187,20 +199,28 @@ impl<'a, 'gcx, 'tcx> Children {
             }
         }
 
+        if inserted_results.len() > 0 {
+            return Ok(inserted_results);
+        }
+
         // no overlap with any potential siblings, so add as a new sibling
         debug!("placing as new sibling");
         self.insert_blindly(tcx, impl_def_id);
-        Ok(Inserted::BecameNewSibling(last_lint))
+        Ok(vec![Inserted::BecameNewSibling(last_lint)])
     }
 
-    fn iter_mut(&'a mut self) -> Box<dyn Iterator<Item = &'a mut DefId> + 'a> {
-        let nonblanket = self.nonblanket_impls.iter_mut().flat_map(|(_, v)| v.iter_mut());
+    fn iter_mut(&'a mut self) -> Box<Iterator<Item = &'a mut DefId> + 'a> {
+        let nonblanket = self.nonblanket_impls
+            .iter_mut()
+            .flat_map(|(_, v)| v.iter_mut());
         Box::new(self.blanket_impls.iter_mut().chain(nonblanket))
     }
 
-    fn filtered_mut(&'a mut self, sty: SimplifiedType)
-                    -> Box<dyn Iterator<Item = &'a mut DefId> + 'a> {
-        let nonblanket = self.nonblanket_impls.entry(sty).or_insert(vec![]).iter_mut();
+    fn filtered_mut(&'a mut self, sty: SimplifiedType) -> Box<Iterator<Item = &'a mut DefId> + 'a> {
+        let nonblanket = self.nonblanket_impls
+            .entry(sty)
+            .or_insert(vec![])
+            .iter_mut();
         Box::new(self.blanket_impls.iter_mut().chain(nonblanket))
     }
 }
@@ -216,83 +236,178 @@ impl<'a, 'gcx, 'tcx> Graph {
     /// Insert a local impl into the specialization graph. If an existing impl
     /// conflicts with it (has overlap, but neither specializes the other),
     /// information about the area of overlap is returned in the `Err`.
-    pub fn insert(&mut self,
-                  tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                  impl_def_id: DefId)
-                  -> Result<Option<OverlapError>, OverlapError> {
+    pub fn insert(
+        &mut self,
+        tcx: TyCtxt<'a, 'gcx, 'tcx>,
+        impl_def_id: DefId,
+    ) -> Result<Option<Vec<OverlapError>>, OverlapError> {
         assert!(impl_def_id.is_local());
 
         let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
         let trait_def_id = trait_ref.def_id;
 
-        debug!("insert({:?}): inserting TraitRef {:?} into specialization graph",
-               impl_def_id, trait_ref);
+        debug!(
+            "insert({:?}): inserting TraitRef {:?} into specialization graph",
+            impl_def_id, trait_ref
+        );
 
         // if the reference itself contains an earlier error (e.g., due to a
         // resolution failure), then we just insert the impl at the top level of
         // the graph and claim that there's no overlap (in order to suppress
         // bogus errors).
         if trait_ref.references_error() {
-            debug!("insert: inserting dummy node for erroneous TraitRef {:?}, \
-                    impl_def_id={:?}, trait_def_id={:?}",
-                   trait_ref, impl_def_id, trait_def_id);
-
-            self.parent.insert(impl_def_id, trait_def_id);
-            self.children.entry(trait_def_id).or_insert(Children::new())
+            debug!(
+                "insert: inserting dummy node for erroneous TraitRef {:?}, \
+                 impl_def_id={:?}, trait_def_id={:?}",
+                trait_ref, impl_def_id, trait_def_id
+            );
+
+            self.parent_insert(impl_def_id, trait_def_id);
+            self.children
+                .entry(trait_def_id)
+                .or_insert(Children::new())
                 .insert_blindly(tcx, impl_def_id);
             return Ok(None);
         }
 
-        let mut parent = trait_def_id;
-        let mut last_lint = None;
+        let parent = trait_def_id;
         let simplified = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false);
 
-        // Descend the specialization tree, where `parent` is the current parent node
-        loop {
-            use self::Inserted::*;
-
-            let insert_result = self.children.entry(parent).or_insert(Children::new())
-                .insert(tcx, impl_def_id, simplified)?;
+        let mut last_lints = vec![];
+        // Recusively descend the specialization tree, where `parent` is the current parent node
+        self.recursive_insert(parent, tcx, impl_def_id, simplified, &mut last_lints);
+        Ok(Some(last_lints))
+    }
 
-            match insert_result {
-                BecameNewSibling(opt_lint) => {
-                    last_lint = opt_lint;
-                    break;
-                }
-                Replaced(new_child) => {
-                    self.parent.insert(new_child, impl_def_id);
-                    let mut new_children = Children::new();
-                    new_children.insert_blindly(tcx, new_child);
-                    self.children.insert(impl_def_id, new_children);
-                    break;
-                }
-                ShouldRecurseOn(new_parent) => {
-                    parent = new_parent;
+    fn recursive_insert(
+        &mut self,
+        parent: DefId,
+        tcx: TyCtxt<'a, 'gcx, 'tcx>,
+        impl_def_id: DefId,
+        simplified: Option<SimplifiedType>,
+        last_lints: &mut Vec<OverlapError>,
+    ) {
+        use self::Inserted::*;
+        match self.children
+            .entry(parent)
+            .or_insert(Children::new())
+            .insert(tcx, impl_def_id, simplified)
+        {
+            Ok(insert_results) => for insert_result in insert_results {
+                match insert_result {
+                    BecameNewSibling(opt_lint) => {
+                        if opt_lint.is_some() {
+                            last_lints.push(opt_lint.unwrap());
+                        }
+                        self.parent_insert(impl_def_id, parent);
+                    }
+                    Replaced(new_child) => {
+                        self.parent_insert(new_child, impl_def_id);
+                        let mut new_children = Children::new();
+                        new_children.insert_blindly(tcx, new_child);
+                        self.children.insert(impl_def_id, new_children);
+                        self.parent_insert(impl_def_id, parent);
+                    }
+                    ShouldRecurseOn(new_parent) => {
+                        self.recursive_insert(new_parent, tcx, impl_def_id, simplified, last_lints);
+                    }
                 }
-            }
+            },
+            _ => {}
         }
+    }
 
-        self.parent.insert(impl_def_id, parent);
-        Ok(last_lint)
+    fn parent_insert(&mut self, key: DefId, value: DefId) -> Option<DefId> {
+        if self.parent.contains_key(&key) {
+            let mut impl_vec = self.parent.get(&key).unwrap().clone();
+            impl_vec.push(value);
+            self.parent.insert(key, impl_vec);
+            Some(value)
+        } else {
+            if self.parent.insert(key, vec![value]).is_some() {
+                Some(value)
+            } else {
+                None
+            }
+        }
     }
 
     /// Insert cached metadata mapping from a child impl back to its parent.
-    pub fn record_impl_from_cstore(&mut self,
-                                   tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                                   parent: DefId,
-                                   child: DefId) {
-        if self.parent.insert(child, parent).is_some() {
-            bug!("When recording an impl from the crate store, information about its parent \
-                  was already present.");
+    pub fn record_impl_from_cstore(
+        &mut self,
+        tcx: TyCtxt<'a, 'gcx, 'tcx>,
+        parent: DefId,
+        child: DefId,
+    ) {
+        if self.parent_insert(child, parent).is_some() {
+            bug!(
+                "When recording an impl from the crate store, information about its parent \
+                 was already present."
+            );
         }
 
-        self.children.entry(parent).or_insert(Children::new()).insert_blindly(tcx, child);
+        self.children
+            .entry(parent)
+            .or_insert(Children::new())
+            .insert_blindly(tcx, child);
+    }
+
+    /// Returns the def-id of the parent impl(s) for a given impl.
+    /// An impl A has a parent impl B if A matches a strict subset of the types that B matches.
+    pub fn parents(&self, child: DefId) -> Vec<DefId> {
+        self.parent.get(&child).unwrap().clone()
+    }
+
+    pub fn build_graph(&self) -> (DataStructuresGraph<DefId, String>, DefIdMap<NodeIndex>) {
+        let mut sg_graph: DataStructuresGraph<DefId, String> = DataStructuresGraph::new();
+        let mut nodes_idx = Default::default();
+        for (key, val) in self.parent.iter() {
+            let idx = self.node_idx(&mut sg_graph, &mut nodes_idx, *key);
+            for parent in val {
+                let pidx = self.node_idx(&mut sg_graph, &mut nodes_idx, *parent);
+                sg_graph.add_edge(idx, pidx, format!("fromt {:?} to {:?}", key, parent));
+                debug!("from {:?} to {:?}", key, parent);
+            }
+        }
+
+        (sg_graph, nodes_idx)
+    }
+
+    /// Return true if impl1 and impl2 are allowed to overlap:
+    /// They have an intersection impl
+    pub fn check_overlap(
+        &self,
+        sg_graph: &DataStructuresGraph<DefId, String>,
+        nodes_idx: &DefIdMap<NodeIndex>,
+        impl1: DefId,
+        impl2: DefId,
+    ) -> bool {
+        let impl1_idx = *nodes_idx.get(&impl1).unwrap();
+        let impl2_idx = *nodes_idx.get(&impl2).unwrap();
+
+        let impl1_incoming_nodes = sg_graph.nodes_in_postorder(INCOMING, impl1_idx);
+        let impl2_incoming_nodes = sg_graph.nodes_in_postorder(INCOMING, impl2_idx);
+
+        debug!("check overlap {:?} {:?}", impl1, impl2);
+        debug!("impl1_incoming_nodes {:?}", impl1_incoming_nodes);
+        debug!("impl2_incoming_nodes {:?}", impl2_incoming_nodes);
+
+        impl1_incoming_nodes[0] == impl2_incoming_nodes[0]
     }
 
-    /// The parent of a given impl, which is the def id of the trait when the
-    /// impl is a "specialization root".
-    pub fn parent(&self, child: DefId) -> DefId {
-        *self.parent.get(&child).unwrap()
+    fn node_idx(
+        &self,
+        sg_graph: &mut DataStructuresGraph<DefId, String>,
+        nodes_idx: &mut DefIdMap<NodeIndex>,
+        node: DefId,
+    ) -> NodeIndex {
+        if nodes_idx.get(&node).is_some() {
+            *nodes_idx.get(&node).unwrap()
+        } else {
+            let idx = sg_graph.add_node(node);
+            nodes_idx.insert(node, idx);
+            idx
+        }
     }
 }
 
@@ -332,22 +447,43 @@ impl<'a, 'gcx, 'tcx> Node {
 pub struct Ancestors {
     trait_def_id: DefId,
     specialization_graph: Lrc<Graph>,
-    current_source: Option<Node>,
+    current_source: Option<Vec<Node>>,
 }
 
 impl Iterator for Ancestors {
     type Item = Node;
     fn next(&mut self) -> Option<Node> {
+        // Visit and return the graph nodes from bottom to top
+        // When multiple parents are found return each one of them
+        // prior to move up in the graph
         let cur = self.current_source.take();
-        if let Some(Node::Impl(cur_impl)) = cur {
-            let parent = self.specialization_graph.parent(cur_impl);
-            if parent == self.trait_def_id {
-                self.current_source = Some(Node::Trait(parent));
-            } else {
-                self.current_source = Some(Node::Impl(parent));
+        match cur {
+            Some(mut cur_vec) => {
+                let next_value = cur_vec[0];
+                if let Node::Impl(cur_impl) = next_value {
+                    let parents = self.specialization_graph.parents(cur_impl);
+
+                    let mut ncur = vec![];
+                    ncur.append(&mut cur_vec[1..].to_vec());
+                    for parent in parents {
+                        let node = if parent == self.trait_def_id {
+                            Node::Trait(parent)
+                        } else {
+                            Node::Impl(parent)
+                        };
+
+                        if ncur.iter().find(|n| n.def_id() == node.def_id()).is_none() {
+                            ncur.push(node);
+                        }
+                    }
+
+                    self.current_source = Some(ncur);
+                }
+
+                Some(next_value)
             }
+            None => None,
         }
-        cur
     }
 }
 
@@ -375,34 +511,39 @@ impl<'a, 'gcx, 'tcx> Ancestors {
         trait_item_name: Name,
         trait_item_kind: ty::AssociatedKind,
         trait_def_id: DefId,
-    ) -> impl Iterator<Item = NodeItem<ty::AssociatedItem>> + Captures<'gcx> + Captures<'tcx> + 'a {
+    ) -> impl Iterator<Item = NodeItem<ty::AssociatedItem>> + Captures<'gcx> + Captures<'tcx> + 'a
+    {
         self.flat_map(move |node| {
-            node.items(tcx).filter(move |impl_item| {
-                impl_item.kind == trait_item_kind &&
-                tcx.hygienic_eq(impl_item.name, trait_item_name, trait_def_id)
-            }).map(move |item| NodeItem { node: node, item: item })
+            node.items(tcx)
+                .filter(move |impl_item| {
+                    impl_item.kind == trait_item_kind
+                        && tcx.hygienic_eq(impl_item.name, trait_item_name, trait_def_id)
+                })
+                .map(move |item| NodeItem {
+                    node: node,
+                    item: item,
+                })
         })
     }
 }
 
 /// Walk up the specialization ancestors of a given impl, starting with that
 /// impl itself.
-pub fn ancestors(tcx: TyCtxt,
-                 trait_def_id: DefId,
-                 start_from_impl: DefId)
-                 -> Ancestors {
+pub fn ancestors(tcx: TyCtxt, trait_def_id: DefId, start_from_impl: DefId) -> Ancestors {
     let specialization_graph = tcx.specialization_graph_of(trait_def_id);
     Ancestors {
         trait_def_id,
         specialization_graph,
-        current_source: Some(Node::Impl(start_from_impl)),
+        current_source: Some(vec![Node::Impl(start_from_impl)]),
     }
 }
 
 impl<'a> HashStable<StableHashingContext<'a>> for Children {
-    fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'a>,
-                                          hasher: &mut StableHasher<W>) {
+    fn hash_stable<W: StableHasherResult>(
+        &self,
+        hcx: &mut StableHashingContext<'a>,
+        hasher: &mut StableHasher<W>,
+    ) {
         let Children {
             ref nonblanket_impls,
             ref blanket_impls,
diff --git a/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs b/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs
index 8e9d1eff34580..80e61d7b9b43a 100644
--- a/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs
+++ b/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs
@@ -21,6 +21,7 @@ impl<T: MyTrait> !Send for TestType<T> {}
 //~^ ERROR conflicting implementations of trait `std::marker::Send`
 
 unsafe impl<T:'static> Send for TestType<T> {}
+//~^ ERROR conflicting implementations of trait `std::marker::Send`
 
 impl !Send for TestType<i32> {}
 //~^ ERROR conflicting implementations of trait `std::marker::Send`
diff --git a/src/test/compile-fail/specialization/intersection-impl.rs b/src/test/compile-fail/specialization/intersection-impl.rs
new file mode 100644
index 0000000000000..de1df63abf9af
--- /dev/null
+++ b/src/test/compile-fail/specialization/intersection-impl.rs
@@ -0,0 +1,36 @@
+// Copyright 2015 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.
+
+#![feature(specialization)]
+
+// test conflicting implementation error
+// should an intersection impl help be shown?
+
+trait MyClone {
+    fn clone(&self) -> Self;
+}
+
+impl<T: Copy> MyClone for T {
+    fn clone(&self) -> T {
+        *self
+    }
+}
+
+impl<T: Clone> MyClone for Option<T> {
+    fn clone(&self) -> Option<T> {
+        match *self {
+            Some(ref v) => Some(v.clone()),
+            None => None,
+        }
+    }
+}
+//~^^^^^^^^ ERROR conflicting implementations of trait `MyClone` for type `std::option::Option<_>`
+
+fn main() {}
diff --git a/src/test/run-pass/specialization/intersection-impl-2.rs b/src/test/run-pass/specialization/intersection-impl-2.rs
new file mode 100644
index 0000000000000..a3229a7b310e5
--- /dev/null
+++ b/src/test/run-pass/specialization/intersection-impl-2.rs
@@ -0,0 +1,63 @@
+// Copyright 2015 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.
+
+#![feature(specialization)]
+
+trait A { }
+trait B { }
+trait C { }
+
+trait MyTrait {
+    fn foo(&self) -> &'static str;
+}
+
+impl<T: A> MyTrait for T {
+    default fn foo(&self) -> &'static str {
+        "implements_A"
+    }
+}
+impl<T: B> MyTrait for T {
+    default fn foo(&self) -> &'static str {
+        "implements_B"
+    }
+}
+
+// This would be OK:
+impl<T: A + B> MyTrait for T {
+    default fn foo(&self) -> &'static str {
+        "implements_A+B"
+    }
+}
+// But what about this:
+impl<T: A + B + C> MyTrait for T {
+    fn foo(&self) -> &'static str {
+        "implements_A+B+C"
+    }
+}
+
+struct S_A;
+struct S_B;
+struct S_AB;
+struct S_ABC;
+
+impl A for S_A {}
+impl B for S_B {}
+impl A for S_AB {}
+impl B for S_AB {}
+impl A for S_ABC {}
+impl B for S_ABC {}
+impl C for S_ABC {}
+
+fn main() {
+    assert!(S_A.foo() == "implements_A_");
+    assert!(S_B.foo() == "implements_B");
+    assert!(S_AB.foo() == "implements_A+B");
+    assert!(S_ABC.foo() == "implements_A+B+C");
+}
diff --git a/src/test/run-pass/specialization/intersection-impl.rs b/src/test/run-pass/specialization/intersection-impl.rs
new file mode 100644
index 0000000000000..eb9f0cb643d5a
--- /dev/null
+++ b/src/test/run-pass/specialization/intersection-impl.rs
@@ -0,0 +1,42 @@
+// Copyright 2015 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.
+
+#![feature(specialization)]
+
+// Test if two impls are allowed to overlap if a third
+// impl is the intersection of them
+
+trait MyClone {
+    fn my_clone(&self) -> &'static str;
+}
+
+impl<T: Copy> MyClone for T {
+    default fn my_clone(&self) -> &'static str {
+        "impl_a"
+    }
+}
+
+impl<T: Clone> MyClone for Option<T> {
+    default fn my_clone(&self) -> &'static str {
+        "impl_b"
+    }
+}
+
+impl<T:Copy> MyClone for Option<T> {
+    fn my_clone(&self) -> &'static str {
+        "impl_c"
+    }
+}
+
+fn main() {
+    assert!(42i32.my_clone() == "impl_a");
+    assert!(Some(Box::new(42i32)).my_clone() == "impl_b");
+    assert!(Some(42i32).my_clone() == "impl_c");
+}

From 5067f542fe288c76c91feaa291a3b361aa886caa Mon Sep 17 00:00:00 2001
From: Gianni Ciccarelli <gianni.ciccarelli@gmail.com>
Date: Tue, 29 May 2018 08:57:50 +0000
Subject: [PATCH 2/2] Intersection impls

check if the intersection impl is complete
---
 src/librustc/traits/coherence.rs              |  14 +-
 src/librustc/traits/specialize/mod.rs         |  65 +++---
 .../traits/specialize/specialization_graph.rs | 199 +++++++++++-------
 .../intersection-impl-not-complete.rs         |  30 +++
 .../specialization/intersection-impl-2.rs     |  63 ------
 src/test/ui/e0119/issue-28981.stderr          |   4 +-
 6 files changed, 197 insertions(+), 178 deletions(-)
 create mode 100644 src/test/compile-fail/specialization/intersection-impl-not-complete.rs
 delete mode 100644 src/test/run-pass/specialization/intersection-impl-2.rs

diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs
index 1a763587f0eb7..31f8af1f96872 100644
--- a/src/librustc/traits/coherence.rs
+++ b/src/librustc/traits/coherence.rs
@@ -8,11 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! See `README.md` for high-level documentation
+//! See rustc guide chapters on [trait-resolution] and [trait-specialization] for more info on how
+//! this works.
+//!
+//! [trait-resolution]: https://rust-lang-nursery.github.io/rustc-guide/trait-resolution.html
+//! [trait-specialization]: https://rust-lang-nursery.github.io/rustc-guide/trait-specialization.html
 
 use hir::def_id::{DefId, LOCAL_CRATE};
 use syntax_pos::DUMMY_SP;
-use traits::{self, Normalized, SelectionContext, Obligation, ObligationCause, Reveal};
+use traits::{self, Normalized, SelectionContext, Obligation, ObligationCause};
 use traits::IntercrateMode;
 use traits::select::IntercrateAmbiguityCause;
 use ty::{self, Ty, TyCtxt};
@@ -119,7 +123,7 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
     // types into scope; instead, we replace the generic types with
     // fresh type variables, and hence we do our evaluations in an
     // empty environment.
-    let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
+    let param_env = ty::ParamEnv::empty();
 
     let a_impl_header = with_fresh_ty_vars(selcx, param_env, a_def_id);
     let b_impl_header = with_fresh_ty_vars(selcx, param_env, b_def_id);
@@ -136,7 +140,7 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
         Err(_) => return None
     };
 
-    debug!("overlap: unification check succeeded {:?}", obligations);
+    debug!("overlap: unification check succeeded");
 
     // Are any of the obligations unsatisfiable? If so, no overlap.
     let infcx = selcx.infcx();
@@ -277,7 +281,7 @@ pub fn orphan_check<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
 ///     is bad, because the only local type with `T` as a subtree is
 ///     `LocalType<T>`, and `Vec<->` is between it and the type parameter.
 ///     - similarly, `FundamentalPair<LocalType<T>, T>` is bad, because
-///     the second occurence of `T` is not a subtree of *any* local type.
+///     the second occurrence of `T` is not a subtree of *any* local type.
 ///     - however, `LocalType<Vec<T>>` is OK, because `T` is a subtree of
 ///     `LocalType<Vec<T>>`, which is local and has no types between it and
 ///     the type parameter.
diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs
index 11e7e4f6b9a1a..80beeafb072a8 100644
--- a/src/librustc/traits/specialize/mod.rs
+++ b/src/librustc/traits/specialize/mod.rs
@@ -339,10 +339,9 @@ pub(super) fn specialization_graph_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx
                     for opt_overlap in opt_overlaps {
                         overlaps.push((impl_def_id, opt_overlap));
                     }
-                },
-                _ => {},
+                }
+                _ => {}
             };
-
         } else {
             let parent = tcx.impl_parent(impl_def_id).unwrap_or(trait_id);
             sg.record_impl_from_cstore(tcx, parent, impl_def_id)
@@ -353,47 +352,55 @@ pub(super) fn specialization_graph_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx
         // Build the graph only if there is at least an overlap
         let (graph, nodes_idx) = sg.build_graph();
         for (impl_def_id, overlap) in overlaps {
-            if !sg.check_overlap(&graph, &nodes_idx, impl_def_id, overlap.with_impl) {
-
-                let msg = format!("conflicting implementations of trait `{}`{}:{}",
+            if !sg.check_overlap(&graph, &nodes_idx, impl_def_id, overlap.with_impl, tcx) {
+                let msg = format!(
+                    "conflicting implementations of trait `{}`{}:{}",
                     overlap.trait_desc,
-                    overlap.self_desc.clone().map_or(
-                        String::new(), |ty| {
-                            format!(" for type `{}`", ty)
-                        }),
-                    if overlap.used_to_be_allowed { " (E0119)" } else { "" }
-                );
-                let impl_span = tcx.sess.codemap().def_span(
-                    tcx.span_of_impl(impl_def_id).unwrap()
+                    overlap
+                        .self_desc
+                        .clone()
+                        .map_or(String::new(), |ty| format!(" for type `{}`", ty)),
+                    if overlap.used_to_be_allowed {
+                        " (E0119)"
+                    } else {
+                        ""
+                    }
                 );
+                let impl_span = tcx.sess
+                    .codemap()
+                    .def_span(tcx.span_of_impl(impl_def_id).unwrap());
                 let mut err = if overlap.used_to_be_allowed {
                     tcx.struct_span_lint_node(
                         lint::builtin::INCOHERENT_FUNDAMENTAL_IMPLS,
                         tcx.hir.as_local_node_id(impl_def_id).unwrap(),
                         impl_span,
-                        &msg)
+                        &msg,
+                    )
                 } else {
-                    struct_span_err!(tcx.sess,
-                                     impl_span,
-                                     E0119,
-                                     "{}",
-                                     msg)
+                    struct_span_err!(tcx.sess, impl_span, E0119, "{}", msg)
                 };
 
                 match tcx.span_of_impl(overlap.with_impl) {
                     Ok(span) => {
-                        err.span_label(tcx.sess.codemap().def_span(span),
-                                       format!("first implementation here"));
-                        err.span_label(impl_span,
-                                       format!("conflicting implementation{}",
-                                                overlap.self_desc
-                                                    .map_or(String::new(),
-                                                            |ty| format!(" for `{}`", ty))));
+                        err.span_label(
+                            tcx.sess.codemap().def_span(span),
+                            format!("first implementation here"),
+                        );
+                        err.span_label(
+                            impl_span,
+                            format!(
+                                "conflicting implementation{}",
+                                overlap
+                                    .self_desc
+                                    .map_or(String::new(), |ty| format!(" for `{}`", ty))
+                            ),
+                        );
                     }
                     Err(cname) => {
                         let msg = match to_pretty_impl_header(tcx, overlap.with_impl) {
-                            Some(s) => format!(
-                                "conflicting implementation in crate `{}`:\n- {}", cname, s),
+                            Some(s) => {
+                                format!("conflicting implementation in crate `{}`:\n- {}", cname, s)
+                            }
                             None => format!("conflicting implementation in crate `{}`", cname),
                         };
                         err.note(&msg);
diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs
index 590460b06c2a4..7d9dfa8d79626 100644
--- a/src/librustc/traits/specialize/specialization_graph.rs
+++ b/src/librustc/traits/specialize/specialization_graph.rs
@@ -12,15 +12,19 @@ use super::OverlapError;
 
 use hir::def_id::DefId;
 use ich::{self, StableHashingContext};
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
+                                           StableHasherResult};
 use rustc_data_structures::graph::{Graph as DataStructuresGraph, NodeIndex, INCOMING};
-use traits;
+use traits::{self, ObligationCause, TraitEngine};
 use ty::{self, TyCtxt, TypeFoldable};
 use ty::fast_reject::{self, SimplifiedType};
 use rustc_data_structures::sync::Lrc;
-use syntax::ast::Name;
+use syntax::ast::{Name, DUMMY_NODE_ID};
 use util::captures::Captures;
 use util::nodemap::{DefIdMap, FxHashMap};
+use super::FulfillmentContext;
+use std::collections::HashSet;
+use syntax_pos::DUMMY_SP;
 
 /// A per-trait graph of impls in specialization order. At the moment, this
 /// graph forms a tree rooted with the trait itself, with all other nodes
@@ -88,13 +92,12 @@ impl<'a, 'gcx, 'tcx> Children {
     }
 
     /// Insert an impl into this set of children without comparing to any existing impls
-    fn insert_blindly(&mut self, tcx: TyCtxt<'a, 'gcx, 'tcx>, impl_def_id: DefId) {
+    fn insert_blindly(&mut self,
+                      tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                      impl_def_id: DefId) {
         let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
         if let Some(sty) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false) {
-            self.nonblanket_impls
-                .entry(sty)
-                .or_insert(vec![])
-                .push(impl_def_id)
+            self.nonblanket_impls.entry(sty).or_insert(vec![]).push(impl_def_id)
         } else {
             self.blanket_impls.push(impl_def_id)
         }
@@ -102,12 +105,12 @@ impl<'a, 'gcx, 'tcx> Children {
 
     /// Attempt to insert an impl into this set of children, while comparing for
     /// specialization relationships.
-    fn insert(
-        &mut self,
-        tcx: TyCtxt<'a, 'gcx, 'tcx>,
-        impl_def_id: DefId,
-        simplified_self: Option<SimplifiedType>,
-    ) -> Result<Vec<Inserted>, OverlapError> {
+    fn insert(&mut self,
+              tcx: TyCtxt<'a, 'gcx, 'tcx>,
+              impl_def_id: DefId,
+              simplified_self: Option<SimplifiedType>)
+              -> Result<Vec<Inserted>, OverlapError>
+    {
         let mut last_lint = None;
 
         // Nodes could specialize more than one parent
@@ -165,18 +168,14 @@ impl<'a, 'gcx, 'tcx> Children {
             )?;
 
             if le && !ge {
-                debug!(
-                    "descending as child of TraitRef {:?}",
-                    tcx.impl_trait_ref(possible_sibling).unwrap()
-                );
+                debug!("descending as child of TraitRef {:?}",
+                       tcx.impl_trait_ref(possible_sibling).unwrap());
 
                 // the impl specializes possible_sibling
                 inserted_results.push(Inserted::ShouldRecurseOn(possible_sibling));
             } else if ge && !le {
-                debug!(
-                    "placing as parent of TraitRef {:?}",
-                    tcx.impl_trait_ref(possible_sibling).unwrap()
-                );
+                debug!("placing as parent of TraitRef {:?}",
+                       tcx.impl_trait_ref(possible_sibling).unwrap());
 
                 // possible_sibling specializes the impl
                 *slot = impl_def_id;
@@ -209,18 +208,14 @@ impl<'a, 'gcx, 'tcx> Children {
         Ok(vec![Inserted::BecameNewSibling(last_lint)])
     }
 
-    fn iter_mut(&'a mut self) -> Box<Iterator<Item = &'a mut DefId> + 'a> {
-        let nonblanket = self.nonblanket_impls
-            .iter_mut()
-            .flat_map(|(_, v)| v.iter_mut());
+    fn iter_mut(&'a mut self) -> Box<dyn Iterator<Item = &'a mut DefId> + 'a> {
+        let nonblanket = self.nonblanket_impls.iter_mut().flat_map(|(_, v)| v.iter_mut());
         Box::new(self.blanket_impls.iter_mut().chain(nonblanket))
     }
 
-    fn filtered_mut(&'a mut self, sty: SimplifiedType) -> Box<Iterator<Item = &'a mut DefId> + 'a> {
-        let nonblanket = self.nonblanket_impls
-            .entry(sty)
-            .or_insert(vec![])
-            .iter_mut();
+    fn filtered_mut(&'a mut self, sty: SimplifiedType)
+                    -> Box<dyn Iterator<Item = &'a mut DefId> + 'a> {
+        let nonblanket = self.nonblanket_impls.entry(sty).or_insert(vec![]).iter_mut();
         Box::new(self.blanket_impls.iter_mut().chain(nonblanket))
     }
 }
@@ -236,36 +231,29 @@ impl<'a, 'gcx, 'tcx> Graph {
     /// Insert a local impl into the specialization graph. If an existing impl
     /// conflicts with it (has overlap, but neither specializes the other),
     /// information about the area of overlap is returned in the `Err`.
-    pub fn insert(
-        &mut self,
-        tcx: TyCtxt<'a, 'gcx, 'tcx>,
-        impl_def_id: DefId,
-    ) -> Result<Option<Vec<OverlapError>>, OverlapError> {
+    pub fn insert(&mut self,
+                  tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                  impl_def_id: DefId)
+                  -> Result<Option<Vec<OverlapError>>, OverlapError> {
         assert!(impl_def_id.is_local());
 
         let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
         let trait_def_id = trait_ref.def_id;
 
-        debug!(
-            "insert({:?}): inserting TraitRef {:?} into specialization graph",
-            impl_def_id, trait_ref
-        );
+        debug!("insert({:?}): inserting TraitRef {:?} into specialization graph",
+               impl_def_id, trait_ref);
 
         // if the reference itself contains an earlier error (e.g., due to a
         // resolution failure), then we just insert the impl at the top level of
         // the graph and claim that there's no overlap (in order to suppress
         // bogus errors).
         if trait_ref.references_error() {
-            debug!(
-                "insert: inserting dummy node for erroneous TraitRef {:?}, \
-                 impl_def_id={:?}, trait_def_id={:?}",
-                trait_ref, impl_def_id, trait_def_id
-            );
+            debug!("insert: inserting dummy node for erroneous TraitRef {:?}, \
+                    impl_def_id={:?}, trait_def_id={:?}",
+                   trait_ref, impl_def_id, trait_def_id);
 
             self.parent_insert(impl_def_id, trait_def_id);
-            self.children
-                .entry(trait_def_id)
-                .or_insert(Children::new())
+            self.children.entry(trait_def_id).or_insert(Children::new())
                 .insert_blindly(tcx, impl_def_id);
             return Ok(None);
         }
@@ -333,12 +321,10 @@ impl<'a, 'gcx, 'tcx> Graph {
     }
 
     /// Insert cached metadata mapping from a child impl back to its parent.
-    pub fn record_impl_from_cstore(
-        &mut self,
-        tcx: TyCtxt<'a, 'gcx, 'tcx>,
-        parent: DefId,
-        child: DefId,
-    ) {
+    pub fn record_impl_from_cstore(&mut self,
+                                   tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                                   parent: DefId,
+                                   child: DefId) {
         if self.parent_insert(child, parent).is_some() {
             bug!(
                 "When recording an impl from the crate store, information about its parent \
@@ -346,10 +332,7 @@ impl<'a, 'gcx, 'tcx> Graph {
             );
         }
 
-        self.children
-            .entry(parent)
-            .or_insert(Children::new())
-            .insert_blindly(tcx, child);
+        self.children.entry(parent).or_insert(Children::new()).insert_blindly(tcx, child);
     }
 
     /// Returns the def-id of the parent impl(s) for a given impl.
@@ -381,18 +364,81 @@ impl<'a, 'gcx, 'tcx> Graph {
         nodes_idx: &DefIdMap<NodeIndex>,
         impl1: DefId,
         impl2: DefId,
+        tcx: TyCtxt<'a, 'tcx, 'tcx>,
     ) -> bool {
+
         let impl1_idx = *nodes_idx.get(&impl1).unwrap();
         let impl2_idx = *nodes_idx.get(&impl2).unwrap();
 
+        // two impls are allowed to overlap if they have a mutual postdominator in the graph.
+        // That postdominator is the specializing impl.
         let impl1_incoming_nodes = sg_graph.nodes_in_postorder(INCOMING, impl1_idx);
         let impl2_incoming_nodes = sg_graph.nodes_in_postorder(INCOMING, impl2_idx);
 
-        debug!("check overlap {:?} {:?}", impl1, impl2);
-        debug!("impl1_incoming_nodes {:?}", impl1_incoming_nodes);
-        debug!("impl2_incoming_nodes {:?}", impl2_incoming_nodes);
+        if impl1_incoming_nodes[0] == impl2_incoming_nodes[0] {
+
+            // a mutual postdominator has been found but the intersection impls
+            // could not be complete.
+            // The query below tries to answer to the following
+            // Does the exist a set of types such that
+            //  - impl A applies and impl B applies
+            //  - but impl C does not apply
+            let mut result = true;
+            let int_impl = sg_graph.node_data(impl1_incoming_nodes[0]);
+            tcx.infer_ctxt().enter(|infcx| {
+
+                let param_env1 = tcx.param_env(impl1);
+                let param_env2 = tcx.param_env(impl2);
+
+                let mut combined_param_envs_vec =
+                    param_env1
+                        .caller_bounds
+                        .iter()
+                        .chain(param_env2.caller_bounds.iter())
+                        .map(|p| *p)
+                        .collect::<Vec<_>>();
+
+                let combined_param_envs: HashSet<_> =
+                    combined_param_envs_vec
+                        .drain(..)
+                        .collect();
+
+                // Combine the param envs of the overlapping impls into a single param env.
+                let param_env = ty::ParamEnv::new(
+                    tcx.intern_predicates(
+                        combined_param_envs
+                            .into_iter()
+                            .collect::<Vec<_>>()
+                            .as_slice()
+                    ),
+                    param_env1.reveal
+                );
+
+                let predicates = tcx.predicates_of(*int_impl);
+                let ty = tcx.type_of(*int_impl);
+
+                let mut fulfill_cx = FulfillmentContext::new();
+                for predicate in predicates.predicates {
+                    if let ty::Predicate::Trait(trait_predicate) = predicate {
+                        fulfill_cx.register_bound(
+                            &infcx,
+                            param_env,
+                            ty,
+                            trait_predicate.skip_binder().trait_ref.def_id,
+                            ObligationCause::misc(DUMMY_SP, DUMMY_NODE_ID),
+                        );
+                    }
+                }
 
-        impl1_incoming_nodes[0] == impl2_incoming_nodes[0]
+                fulfill_cx.select_all_or_error(&infcx).unwrap_or_else(|_| {
+                    result = false;
+                });
+            });
+
+            result
+        } else {
+            false
+        }
     }
 
     fn node_idx(
@@ -511,25 +557,22 @@ impl<'a, 'gcx, 'tcx> Ancestors {
         trait_item_name: Name,
         trait_item_kind: ty::AssociatedKind,
         trait_def_id: DefId,
-    ) -> impl Iterator<Item = NodeItem<ty::AssociatedItem>> + Captures<'gcx> + Captures<'tcx> + 'a
-    {
+    ) -> impl Iterator<Item = NodeItem<ty::AssociatedItem>> + Captures<'gcx> + Captures<'tcx> + 'a {
         self.flat_map(move |node| {
-            node.items(tcx)
-                .filter(move |impl_item| {
-                    impl_item.kind == trait_item_kind
-                        && tcx.hygienic_eq(impl_item.name, trait_item_name, trait_def_id)
-                })
-                .map(move |item| NodeItem {
-                    node: node,
-                    item: item,
-                })
+            node.items(tcx).filter(move |impl_item| {
+                impl_item.kind == trait_item_kind &&
+                tcx.hygienic_eq(impl_item.name, trait_item_name, trait_def_id)
+            }).map(move |item| NodeItem { node: node, item: item })
         })
     }
 }
 
 /// Walk up the specialization ancestors of a given impl, starting with that
 /// impl itself.
-pub fn ancestors(tcx: TyCtxt, trait_def_id: DefId, start_from_impl: DefId) -> Ancestors {
+pub fn ancestors(tcx: TyCtxt,
+                 trait_def_id: DefId,
+                 start_from_impl: DefId)
+                 -> Ancestors {
     let specialization_graph = tcx.specialization_graph_of(trait_def_id);
     Ancestors {
         trait_def_id,
@@ -539,11 +582,9 @@ pub fn ancestors(tcx: TyCtxt, trait_def_id: DefId, start_from_impl: DefId) -> An
 }
 
 impl<'a> HashStable<StableHashingContext<'a>> for Children {
-    fn hash_stable<W: StableHasherResult>(
-        &self,
-        hcx: &mut StableHashingContext<'a>,
-        hasher: &mut StableHasher<W>,
-    ) {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a>,
+                                          hasher: &mut StableHasher<W>) {
         let Children {
             ref nonblanket_impls,
             ref blanket_impls,
diff --git a/src/test/compile-fail/specialization/intersection-impl-not-complete.rs b/src/test/compile-fail/specialization/intersection-impl-not-complete.rs
new file mode 100644
index 0000000000000..59b774c6168ea
--- /dev/null
+++ b/src/test/compile-fail/specialization/intersection-impl-not-complete.rs
@@ -0,0 +1,30 @@
+// Copyright 2015 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.
+
+#![feature(specialization)]
+
+// test if the intersecion impl is complete
+
+trait A { }
+trait B { }
+trait C { }
+
+trait MyTrait { }
+
+impl<T: A> MyTrait for T { }
+impl<T: B> MyTrait for T { }
+//~^ ERROR conflicting implementations of trait `MyTrait`
+
+// This would be OK:
+//impl<T: A + B> MyTrait for T { }
+// But what about this:
+impl<T: A + B + C> MyTrait for T { }
+
+fn main() {}
diff --git a/src/test/run-pass/specialization/intersection-impl-2.rs b/src/test/run-pass/specialization/intersection-impl-2.rs
deleted file mode 100644
index a3229a7b310e5..0000000000000
--- a/src/test/run-pass/specialization/intersection-impl-2.rs
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2015 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.
-
-#![feature(specialization)]
-
-trait A { }
-trait B { }
-trait C { }
-
-trait MyTrait {
-    fn foo(&self) -> &'static str;
-}
-
-impl<T: A> MyTrait for T {
-    default fn foo(&self) -> &'static str {
-        "implements_A"
-    }
-}
-impl<T: B> MyTrait for T {
-    default fn foo(&self) -> &'static str {
-        "implements_B"
-    }
-}
-
-// This would be OK:
-impl<T: A + B> MyTrait for T {
-    default fn foo(&self) -> &'static str {
-        "implements_A+B"
-    }
-}
-// But what about this:
-impl<T: A + B + C> MyTrait for T {
-    fn foo(&self) -> &'static str {
-        "implements_A+B+C"
-    }
-}
-
-struct S_A;
-struct S_B;
-struct S_AB;
-struct S_ABC;
-
-impl A for S_A {}
-impl B for S_B {}
-impl A for S_AB {}
-impl B for S_AB {}
-impl A for S_ABC {}
-impl B for S_ABC {}
-impl C for S_ABC {}
-
-fn main() {
-    assert!(S_A.foo() == "implements_A_");
-    assert!(S_B.foo() == "implements_B");
-    assert!(S_AB.foo() == "implements_A+B");
-    assert!(S_ABC.foo() == "implements_A+B+C");
-}
diff --git a/src/test/ui/e0119/issue-28981.stderr b/src/test/ui/e0119/issue-28981.stderr
index afcbab4a5c6c0..9d600fcac07cf 100644
--- a/src/test/ui/e0119/issue-28981.stderr
+++ b/src/test/ui/e0119/issue-28981.stderr
@@ -1,11 +1,11 @@
-error[E0119]: conflicting implementations of trait `std::ops::Deref` for type `&_`:
+error[E0119]: conflicting implementations of trait `std::ops::Deref` for type `std::cell::Ref<'_, _>`:
   --> $DIR/issue-28981.rs:15:1
    |
 LL | impl<Foo> Deref for Foo { } //~ ERROR must be used
    | ^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: conflicting implementation in crate `core`:
-           - impl<'a, T> std::ops::Deref for &'a T
+           - impl<'b, T> std::ops::Deref for std::cell::Ref<'b, T>
              where T: ?Sized;
 
 error[E0210]: type parameter `Foo` must be used as the type parameter for some local type (e.g. `MyStruct<Foo>`)