about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/traits/specialize/mod.rs14
-rw-r--r--src/librustc/ty/maps.rs4
-rw-r--r--src/librustc/ty/trait_def.rs117
3 files changed, 108 insertions, 27 deletions
diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs
index b3956e813c4..0e5779f9d17 100644
--- a/src/librustc/traits/specialize/mod.rs
+++ b/src/librustc/traits/specialize/mod.rs
@@ -293,7 +293,19 @@ pub(super) fn specialization_graph_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx
                                                       -> Rc<specialization_graph::Graph> {
     let mut sg = specialization_graph::Graph::new();
 
-    for &impl_def_id in tcx.trait_impls_of(trait_id).iter() {
+    let mut trait_impls: Vec<DefId> = tcx.trait_impls_of(trait_id).iter().collect();
+
+    // The coherence checking implementation seems to rely on impls being
+    // iterated over (roughly) in definition order, so we are sorting by
+    // negated CrateNum (so remote definitions are visited first) and then
+    // by a flattend version of the DefIndex.
+    trait_impls.sort_unstable_by_key(|def_id| {
+        (-(def_id.krate.as_u32() as i64),
+         def_id.index.address_space().index(),
+         def_id.index.as_array_index())
+    });
+
+    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);
diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs
index 188ef289ba9..0926da2005d 100644
--- a/src/librustc/ty/maps.rs
+++ b/src/librustc/ty/maps.rs
@@ -850,10 +850,10 @@ define_maps! { <'tcx>
     [] const_is_rvalue_promotable_to_static: ConstIsRvaluePromotableToStatic(DefId) -> bool,
     [] is_mir_available: IsMirAvailable(DefId) -> bool,
 
-    [] trait_impls_of: TraitImpls(DefId) -> Rc<Vec<DefId>>,
+    [] trait_impls_of: TraitImpls(DefId) -> ty::trait_def::TraitImpls,
     // Note that TraitDef::for_each_relevant_impl() will do type simplication for you.
     [] relevant_trait_impls_for: relevant_trait_impls_for((DefId, SimplifiedType))
-        -> Rc<Vec<DefId>>,
+        -> ty::trait_def::TraitImpls,
     [] specialization_graph_of: SpecializationGraph(DefId) -> Rc<specialization_graph::Graph>,
     [] is_object_safe: ObjectSafety(DefId) -> bool,
 }
diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs
index b0357a35b83..eb60f9d1010 100644
--- a/src/librustc/ty/trait_def.rs
+++ b/src/librustc/ty/trait_def.rs
@@ -35,6 +35,60 @@ pub struct TraitDef {
     pub def_path_hash: u64,
 }
 
+// We don't store the list of impls in a flat list because each cached list of
+// `relevant_impls_for` we would then duplicate all blanket impls. By keeping
+// blanket and non-blanket impls separate, we can share the list of blanket
+// impls.
+#[derive(Clone)]
+pub struct TraitImpls {
+    blanket_impls: Rc<Vec<DefId>>,
+    non_blanket_impls: Rc<Vec<DefId>>,
+}
+
+impl TraitImpls {
+    pub fn iter(&self) -> TraitImplsIter {
+        TraitImplsIter {
+            blanket_impls: self.blanket_impls.clone(),
+            non_blanket_impls: self.non_blanket_impls.clone(),
+            index: 0
+        }
+    }
+}
+
+#[derive(Clone)]
+pub struct TraitImplsIter {
+    blanket_impls: Rc<Vec<DefId>>,
+    non_blanket_impls: Rc<Vec<DefId>>,
+    index: usize,
+}
+
+impl Iterator for TraitImplsIter {
+    type Item = DefId;
+
+    fn next(&mut self) -> Option<DefId> {
+        if self.index < self.blanket_impls.len() {
+            let bi_index = self.index;
+            self.index += 1;
+            Some(self.blanket_impls[bi_index])
+        } else {
+            let nbi_index = self.index - self.blanket_impls.len();
+            if nbi_index < self.non_blanket_impls.len() {
+                self.index += 1;
+                Some(self.non_blanket_impls[nbi_index])
+            } else {
+                None
+            }
+        }
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        let items_left = (self.blanket_impls.len() + self.non_blanket_impls.len()) - self.index;
+        (items_left, Some(items_left))
+    }
+}
+
+impl ExactSizeIterator for TraitImplsIter {}
+
 impl<'a, 'gcx, 'tcx> TraitDef {
     pub fn new(def_id: DefId,
                unsafety: hir::Unsafety,
@@ -58,7 +112,7 @@ impl<'a, 'gcx, 'tcx> TraitDef {
     }
 
     pub fn for_each_impl<F: FnMut(DefId)>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, mut f: F) {
-        for &impl_def_id in tcx.trait_impls_of(self.def_id).iter() {
+        for impl_def_id in tcx.trait_impls_of(self.def_id).iter() {
             f(impl_def_id);
         }
     }
@@ -89,7 +143,7 @@ impl<'a, 'gcx, 'tcx> TraitDef {
             tcx.trait_impls_of(self.def_id)
         };
 
-        for &impl_def_id in relevant_impls.iter() {
+        for impl_def_id in relevant_impls.iter() {
             f(impl_def_id);
         }
     }
@@ -98,8 +152,8 @@ impl<'a, 'gcx, 'tcx> TraitDef {
 // Query provider for `trait_impls_of`.
 pub(super) fn trait_impls_of_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                 trait_id: DefId)
-                                                -> Rc<Vec<DefId>> {
-    let mut impls = if trait_id.is_local() {
+                                                -> TraitImpls {
+    let remote_impls = if trait_id.is_local() {
         // Traits defined in the current crate can't have impls in upstream
         // crates, so we don't bother querying the cstore.
         Vec::new()
@@ -107,46 +161,61 @@ pub(super) fn trait_impls_of_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         tcx.sess.cstore.implementations_of_trait(Some(trait_id))
     };
 
-    impls.extend(tcx.hir
-                    .trait_impls(trait_id)
-                    .iter()
-                    .map(|&node_id| tcx.hir.local_def_id(node_id))
-                    .filter(|&impl_def_id| {
-                        let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
-                        !trait_ref.references_error()
-                    }));
-    Rc::new(impls)
+    let mut blanket_impls = Vec::new();
+    let mut non_blanket_impls = Vec::new();
+
+    let local_impls = tcx.hir
+                         .trait_impls(trait_id)
+                         .into_iter()
+                         .map(|&node_id| tcx.hir.local_def_id(node_id));
+
+     for impl_def_id in local_impls.chain(remote_impls.into_iter()) {
+        let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+        if impl_def_id.is_local() && impl_trait_ref.references_error() {
+            continue
+        }
+
+        if fast_reject::simplify_type(tcx, impl_trait_ref.self_ty(), false).is_some() {
+            non_blanket_impls.push(impl_def_id);
+        } else {
+            blanket_impls.push(impl_def_id);
+        }
+    }
+
+    TraitImpls {
+        blanket_impls: Rc::new(blanket_impls),
+        non_blanket_impls: Rc::new(non_blanket_impls),
+    }
 }
 
 // Query provider for `relevant_trait_impls_for`.
 pub(super) fn relevant_trait_impls_provider<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     (trait_id, self_ty): (DefId, fast_reject::SimplifiedType))
-    -> Rc<Vec<DefId>>
+    -> TraitImpls
 {
     let all_trait_impls = tcx.trait_impls_of(trait_id);
 
     let relevant: Vec<DefId> = all_trait_impls
+        .non_blanket_impls
         .iter()
-        .map(|&impl_def_id| impl_def_id)
+        .cloned()
         .filter(|&impl_def_id| {
             let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
             let impl_simple_self_ty = fast_reject::simplify_type(tcx,
                                                                  impl_trait_ref.self_ty(),
-                                                                 false);
-            if let Some(impl_simple_self_ty) = impl_simple_self_ty {
-                impl_simple_self_ty == self_ty
-            } else {
-                // blanket impl (?)
-                true
-            }
+                                                                 false).unwrap();
+            impl_simple_self_ty == self_ty
         })
         .collect();
 
-    if all_trait_impls.len() == relevant.len() {
+    if all_trait_impls.non_blanket_impls.len() == relevant.len() {
         // If we didn't filter anything out, re-use the existing vec.
         all_trait_impls
     } else {
-        Rc::new(relevant)
+        TraitImpls {
+            blanket_impls: all_trait_impls.blanket_impls.clone(),
+            non_blanket_impls: Rc::new(relevant),
+        }
     }
 }