summaryrefslogtreecommitdiffstats
path: root/vendor/chalk-solve-0.87.0/src/logging_db/id_collector.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/chalk-solve-0.87.0/src/logging_db/id_collector.rs')
-rw-r--r--vendor/chalk-solve-0.87.0/src/logging_db/id_collector.rs162
1 files changed, 162 insertions, 0 deletions
diff --git a/vendor/chalk-solve-0.87.0/src/logging_db/id_collector.rs b/vendor/chalk-solve-0.87.0/src/logging_db/id_collector.rs
new file mode 100644
index 000000000..41aa38166
--- /dev/null
+++ b/vendor/chalk-solve-0.87.0/src/logging_db/id_collector.rs
@@ -0,0 +1,162 @@
+use super::RecordedItemId;
+use crate::RustIrDatabase;
+use chalk_ir::{
+ interner::Interner,
+ visit::TypeVisitor,
+ visit::{TypeSuperVisitable, TypeVisitable},
+ AliasTy, DebruijnIndex, TyKind, WhereClause,
+};
+use std::ops::ControlFlow;
+
+use indexmap::IndexSet;
+
+/// Collects the identifiers needed to resolve all the names for a given
+/// set of identifers, excluding identifiers we already have.
+///
+/// When recording identifiers to print, the `LoggingRustIrDatabase` only
+/// records identifiers the solver uses. But the solver assumes well-formedness,
+/// and thus skips over many names referenced in the definitions.
+///
+/// For instance, if we have:
+///
+/// ```rust,ignore
+/// struct S {}
+///
+/// trait Parent {}
+/// trait Child where Self: Parent {}
+/// impl Parent for S {}
+/// impl Child for S {}
+/// ```
+///
+/// And our goal is `S: Child`, we will only render `S`, `impl Child for S`, and
+/// `trait Child`. This will not parse because the `Child` trait's definition
+/// references parent. IdCollector solves this by collecting all of the directly
+/// related identifiers, allowing those to be rendered as well, ensuring name
+/// resolution is successful.
+pub fn collect_unrecorded_ids<I: Interner, DB: RustIrDatabase<I>>(
+ db: &DB,
+ identifiers: &'_ IndexSet<RecordedItemId<I>>,
+) -> IndexSet<RecordedItemId<I>> {
+ let mut collector = IdCollector {
+ db,
+ found_identifiers: IndexSet::new(),
+ };
+ for id in identifiers {
+ match *id {
+ RecordedItemId::Adt(adt_id) => {
+ collector
+ .db
+ .adt_datum(adt_id)
+ .visit_with(&mut collector, DebruijnIndex::INNERMOST);
+ }
+ RecordedItemId::FnDef(fn_def) => {
+ collector
+ .db
+ .fn_def_datum(fn_def)
+ .visit_with(&mut collector, DebruijnIndex::INNERMOST);
+ }
+ RecordedItemId::Generator(_generator_id) => unimplemented!(),
+ RecordedItemId::Trait(trait_id) => {
+ let trait_datum = collector.db.trait_datum(trait_id);
+
+ trait_datum.visit_with(&mut collector, DebruijnIndex::INNERMOST);
+ for assoc_ty_id in &trait_datum.associated_ty_ids {
+ let assoc_ty_datum = collector.db.associated_ty_data(*assoc_ty_id);
+ assoc_ty_datum
+ .bounds_on_self(collector.db.interner())
+ .visit_with(&mut collector, DebruijnIndex::INNERMOST);
+ assoc_ty_datum.visit_with(&mut collector, DebruijnIndex::INNERMOST);
+ }
+ }
+ RecordedItemId::OpaqueTy(opaque_id) => {
+ collector
+ .db
+ .opaque_ty_data(opaque_id)
+ .visit_with(&mut collector, DebruijnIndex::INNERMOST);
+ collector
+ .db
+ .hidden_opaque_type(opaque_id)
+ .visit_with(&mut collector, DebruijnIndex::INNERMOST);
+ }
+ RecordedItemId::Impl(impl_id) => {
+ let impl_datum = collector.db.impl_datum(impl_id);
+ for id in &impl_datum.associated_ty_value_ids {
+ let assoc_ty_value = collector.db.associated_ty_value(*id);
+ assoc_ty_value.visit_with(&mut collector, DebruijnIndex::INNERMOST);
+ }
+ impl_datum.visit_with(&mut collector, DebruijnIndex::INNERMOST);
+ }
+ }
+ }
+ collector
+ .found_identifiers
+ .difference(identifiers)
+ .copied()
+ .collect()
+}
+
+struct IdCollector<'i, I: Interner, DB: RustIrDatabase<I>> {
+ db: &'i DB,
+ found_identifiers: IndexSet<RecordedItemId<I>>,
+}
+
+impl<'i, I: Interner, DB: RustIrDatabase<I>> IdCollector<'i, I, DB> {
+ fn record(&mut self, id: impl Into<RecordedItemId<I>>) {
+ self.found_identifiers.insert(id.into());
+ }
+
+ fn visit_alias(&mut self, alias: &AliasTy<I>) {
+ match alias {
+ AliasTy::Projection(projection_ty) => {
+ let assoc_ty_datum = self.db.associated_ty_data(projection_ty.associated_ty_id);
+ self.record(assoc_ty_datum.trait_id)
+ }
+ AliasTy::Opaque(opaque_ty) => self.record(opaque_ty.opaque_ty_id),
+ }
+ }
+}
+
+impl<'i, I: Interner, DB: RustIrDatabase<I>> TypeVisitor<I> for IdCollector<'i, I, DB> {
+ type BreakTy = ();
+
+ fn as_dyn(&mut self) -> &mut dyn TypeVisitor<I, BreakTy = Self::BreakTy> {
+ self
+ }
+ fn interner(&self) -> I {
+ self.db.interner()
+ }
+
+ fn visit_ty(
+ &mut self,
+ ty: &chalk_ir::Ty<I>,
+ outer_binder: chalk_ir::DebruijnIndex,
+ ) -> ControlFlow<()> {
+ match ty.kind(self.db.interner()) {
+ TyKind::Adt(adt, _) => self.record(*adt),
+ TyKind::FnDef(fn_def, _) => self.record(*fn_def),
+ TyKind::OpaqueType(opaque, _) => self.record(*opaque),
+ TyKind::Alias(alias) => self.visit_alias(alias),
+ TyKind::BoundVar(..) => (),
+ TyKind::Dyn(..) => (),
+ TyKind::Function(..) => (),
+ TyKind::InferenceVar(..) => (),
+ TyKind::Placeholder(..) => (),
+ _ => {}
+ }
+ ty.super_visit_with(self, outer_binder)
+ }
+
+ fn visit_where_clause(
+ &mut self,
+ where_clause: &WhereClause<I>,
+ outer_binder: DebruijnIndex,
+ ) -> ControlFlow<()> {
+ match where_clause {
+ WhereClause::Implemented(trait_ref) => self.record(trait_ref.trait_id),
+ WhereClause::AliasEq(alias_eq) => self.visit_alias(&alias_eq.alias),
+ WhereClause::LifetimeOutlives(_lifetime_outlives) => (),
+ WhereClause::TypeOutlives(_type_outlives) => (),
+ }
+ where_clause.super_visit_with(self.as_dyn(), outer_binder)
+ }
+}