summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_middle/src/traits/util.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_middle/src/traits/util.rs')
-rw-r--r--compiler/rustc_middle/src/traits/util.rs49
1 files changed, 49 insertions, 0 deletions
diff --git a/compiler/rustc_middle/src/traits/util.rs b/compiler/rustc_middle/src/traits/util.rs
new file mode 100644
index 000000000..d54b8c599
--- /dev/null
+++ b/compiler/rustc_middle/src/traits/util.rs
@@ -0,0 +1,49 @@
+use rustc_data_structures::fx::FxHashSet;
+
+use crate::ty::{PolyTraitRef, TyCtxt};
+
+/// Given a PolyTraitRef, get the PolyTraitRefs of the trait's (transitive) supertraits.
+///
+/// A simplified version of the same function at `rustc_infer::traits::util::supertraits`.
+pub fn supertraits<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ trait_ref: PolyTraitRef<'tcx>,
+) -> impl Iterator<Item = PolyTraitRef<'tcx>> {
+ Elaborator { tcx, visited: FxHashSet::from_iter([trait_ref]), stack: vec![trait_ref] }
+}
+
+struct Elaborator<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ visited: FxHashSet<PolyTraitRef<'tcx>>,
+ stack: Vec<PolyTraitRef<'tcx>>,
+}
+
+impl<'tcx> Elaborator<'tcx> {
+ fn elaborate(&mut self, trait_ref: PolyTraitRef<'tcx>) {
+ let supertrait_refs = self
+ .tcx
+ .super_predicates_of(trait_ref.def_id())
+ .predicates
+ .into_iter()
+ .flat_map(|(pred, _)| {
+ pred.subst_supertrait(self.tcx, &trait_ref).to_opt_poly_trait_pred()
+ })
+ .map(|t| t.map_bound(|pred| pred.trait_ref))
+ .filter(|supertrait_ref| self.visited.insert(*supertrait_ref));
+
+ self.stack.extend(supertrait_refs);
+ }
+}
+
+impl<'tcx> Iterator for Elaborator<'tcx> {
+ type Item = PolyTraitRef<'tcx>;
+
+ fn next(&mut self) -> Option<PolyTraitRef<'tcx>> {
+ if let Some(trait_ref) = self.stack.pop() {
+ self.elaborate(trait_ref);
+ Some(trait_ref)
+ } else {
+ None
+ }
+ }
+}