]> git.proxmox.com Git - rustc.git/blob - vendor/chalk-solve/src/logging_db/id_collector.rs
New upstream version 1.47.0~beta.2+dfsg1
[rustc.git] / vendor / chalk-solve / src / logging_db / id_collector.rs
1 use super::RecordedItemId;
2 use crate::RustIrDatabase;
3 use chalk_ir::{
4 interner::Interner,
5 visit::Visitor,
6 visit::{SuperVisit, Visit},
7 AliasTy, DebruijnIndex, TyData, TypeName, WhereClause,
8 };
9 use std::collections::BTreeSet;
10
11 /// Collects the identifiers needed to resolve all the names for a given
12 /// set of identifers, excluding identifiers we already have.
13 ///
14 /// When recording identifiers to print, the `LoggingRustIrDatabase` only
15 /// records identifiers the solver uses. But the solver assumes well-formedness,
16 /// and thus skips over many names referenced in the definitions.
17 ///
18 /// For instance, if we have:
19 ///
20 /// ```rust,ignore
21 /// struct S {}
22 ///
23 /// trait Parent {}
24 /// trait Child where Self: Parent {}
25 /// impl Parent for S {}
26 /// impl Child for S {}
27 /// ```
28 ///
29 /// And our goal is `S: Child`, we will only render `S`, `impl Child for S`, and
30 /// `trait Child`. This will not parse because the `Child` trait's definition
31 /// references parent. IdCollector solves this by collecting all of the directly
32 /// related identifiers, allowing those to be rendered as well, ensuring name
33 /// resolution is successful.
34 pub fn collect_unrecorded_ids<'i, I: Interner, DB: RustIrDatabase<I>>(
35 db: &'i DB,
36 identifiers: &'_ BTreeSet<RecordedItemId<I>>,
37 ) -> BTreeSet<RecordedItemId<I>> {
38 let mut collector = IdCollector {
39 db,
40 found_identifiers: BTreeSet::new(),
41 };
42 for id in identifiers {
43 match *id {
44 RecordedItemId::Adt(adt_id) => {
45 collector
46 .db
47 .adt_datum(adt_id)
48 .visit_with(&mut collector, DebruijnIndex::INNERMOST);
49 }
50 RecordedItemId::FnDef(fn_def) => {
51 collector
52 .db
53 .fn_def_datum(fn_def)
54 .visit_with(&mut collector, DebruijnIndex::INNERMOST);
55 }
56 RecordedItemId::Trait(trait_id) => {
57 let trait_datum = collector.db.trait_datum(trait_id);
58
59 trait_datum.visit_with(&mut collector, DebruijnIndex::INNERMOST);
60 for assoc_ty_id in &trait_datum.associated_ty_ids {
61 let assoc_ty_datum = collector.db.associated_ty_data(*assoc_ty_id);
62 assoc_ty_datum
63 .bounds_on_self(collector.db.interner())
64 .visit_with(&mut collector, DebruijnIndex::INNERMOST);
65 assoc_ty_datum.visit_with(&mut collector, DebruijnIndex::INNERMOST)
66 }
67 }
68 RecordedItemId::OpaqueTy(opaque_id) => {
69 collector
70 .db
71 .opaque_ty_data(opaque_id)
72 .visit_with(&mut collector, DebruijnIndex::INNERMOST);
73 collector
74 .db
75 .hidden_opaque_type(opaque_id)
76 .visit_with(&mut collector, DebruijnIndex::INNERMOST);
77 }
78 RecordedItemId::Impl(impl_id) => {
79 let impl_datum = collector.db.impl_datum(impl_id);
80 for id in &impl_datum.associated_ty_value_ids {
81 let assoc_ty_value = collector.db.associated_ty_value(*id);
82 assoc_ty_value.visit_with(&mut collector, DebruijnIndex::INNERMOST);
83 }
84 impl_datum.visit_with(&mut collector, DebruijnIndex::INNERMOST);
85 }
86 }
87 }
88 collector
89 .found_identifiers
90 .difference(identifiers)
91 .copied()
92 .collect()
93 }
94
95 struct IdCollector<'i, I: Interner, DB: RustIrDatabase<I>> {
96 db: &'i DB,
97 found_identifiers: BTreeSet<RecordedItemId<I>>,
98 }
99
100 impl<'i, I: Interner, DB: RustIrDatabase<I>> IdCollector<'i, I, DB> {
101 fn record(&mut self, id: impl Into<RecordedItemId<I>>) {
102 self.found_identifiers.insert(id.into());
103 }
104 }
105
106 impl<'i, I: Interner, DB: RustIrDatabase<I>> Visitor<'i, I> for IdCollector<'i, I, DB>
107 where
108 I: 'i,
109 {
110 type Result = ();
111 fn as_dyn(&mut self) -> &mut dyn Visitor<'i, I, Result = Self::Result> {
112 self
113 }
114 fn interner(&self) -> &'i I {
115 self.db.interner()
116 }
117
118 fn visit_ty(
119 &mut self,
120 ty: &chalk_ir::Ty<I>,
121 outer_binder: chalk_ir::DebruijnIndex,
122 ) -> Self::Result {
123 let ty_data = ty.data(self.db.interner());
124 match ty_data {
125 TyData::Apply(apply_ty) => match apply_ty.name {
126 TypeName::Adt(adt) => self.record(adt),
127 TypeName::FnDef(fn_def) => self.record(fn_def),
128 TypeName::OpaqueType(opaque) => self.record(opaque),
129 _ => {}
130 },
131 TyData::Alias(alias) => match alias {
132 AliasTy::Projection(projection_ty) => {
133 let assoc_ty_datum = self.db.associated_ty_data(projection_ty.associated_ty_id);
134 self.record(assoc_ty_datum.trait_id)
135 }
136 AliasTy::Opaque(opaque_ty) => {
137 self.record(opaque_ty.opaque_ty_id);
138 }
139 },
140 TyData::BoundVar(..) => (),
141 TyData::Dyn(..) => (),
142 TyData::Function(..) => (),
143 TyData::InferenceVar(..) => (),
144 TyData::Placeholder(..) => (),
145 }
146 ty.super_visit_with(self, outer_binder)
147 }
148
149 fn visit_where_clause(
150 &mut self,
151 where_clause: &WhereClause<I>,
152 outer_binder: DebruijnIndex,
153 ) -> Self::Result {
154 match where_clause {
155 WhereClause::Implemented(trait_ref) => self.record(trait_ref.trait_id),
156 WhereClause::AliasEq(alias_eq) => match &alias_eq.alias {
157 AliasTy::Projection(projection_ty) => {
158 let assoc_ty_datum = self.db.associated_ty_data(projection_ty.associated_ty_id);
159 self.record(assoc_ty_datum.trait_id)
160 }
161 AliasTy::Opaque(opaque_ty) => {
162 self.record(opaque_ty.opaque_ty_id);
163 }
164 },
165 WhereClause::LifetimeOutlives(_lifetime_outlives) => (),
166 WhereClause::TypeOutlives(_type_outlives) => (),
167 }
168 where_clause.super_visit_with(self.as_dyn(), outer_binder)
169 }
170 }