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