about summary refs log tree commit diff
path: root/compiler/rustc_resolve/src/late/supertraits.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_resolve/src/late/supertraits.rs')
-rw-r--r--compiler/rustc_resolve/src/late/supertraits.rs60
1 files changed, 60 insertions, 0 deletions
diff --git a/compiler/rustc_resolve/src/late/supertraits.rs b/compiler/rustc_resolve/src/late/supertraits.rs
new file mode 100644
index 00000000000..2130c33bd77
--- /dev/null
+++ b/compiler/rustc_resolve/src/late/supertraits.rs
@@ -0,0 +1,60 @@
+use smallvec::{smallvec, SmallVec};
+
+use rustc_data_structures::fx::FxHashSet;
+use rustc_hir::def_id::DefId;
+use rustc_middle::ty::{self, TyCtxt};
+
+pub struct Elaborator<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    stack: SmallVec<[(DefId, SmallVec<[ty::BoundVariableKind; 8]>); 8]>,
+    visited: FxHashSet<DefId>,
+}
+
+#[allow(dead_code)]
+pub fn supertraits<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Elaborator<'tcx> {
+    Elaborator { tcx, stack: smallvec![(def_id, smallvec![])], visited: Default::default() }
+}
+
+impl<'tcx> Elaborator<'tcx> {
+    fn elaborate(&mut self, def_id: DefId, bound_vars: &SmallVec<[ty::BoundVariableKind; 8]>) {
+        let tcx = self.tcx;
+
+        let predicates = tcx.super_predicates_of(def_id);
+        let obligations = predicates.predicates.iter().filter_map(|&(pred, _)| {
+            let bound_predicate = pred.kind();
+            match bound_predicate.skip_binder() {
+                ty::PredicateKind::Trait(data, _) => {
+                    // The order here needs to match what we would get from `subst_supertrait`
+                    let pred_bound_vars = bound_predicate.bound_vars();
+                    let mut all_bound_vars = bound_vars.clone();
+                    all_bound_vars.extend(pred_bound_vars.iter());
+                    let super_def_id = data.trait_ref.def_id;
+                    Some((super_def_id, all_bound_vars))
+                }
+                _ => None,
+            }
+        });
+
+        let visited = &mut self.visited;
+        let obligations = obligations.filter(|o| visited.insert(o.0));
+        self.stack.extend(obligations);
+    }
+}
+
+impl<'tcx> Iterator for Elaborator<'tcx> {
+    type Item = (DefId, SmallVec<[ty::BoundVariableKind; 8]>);
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        (self.stack.len(), None)
+    }
+
+    fn next(&mut self) -> Option<Self::Item> {
+        match self.stack.pop() {
+            Some((def_id, bound_vars)) => {
+                self.elaborate(def_id, &bound_vars);
+                Some((def_id, bound_vars))
+            }
+            None => None,
+        }
+    }
+}