aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_db/src/helpers
diff options
context:
space:
mode:
authorKirill Bulatov <[email protected]>2021-01-17 00:22:19 +0000
committerKirill Bulatov <[email protected]>2021-01-17 00:57:38 +0000
commit09c11054a1b4886fdfd8f0bbb119aae0f264af1a (patch)
tree002d34cf02c156e7301e0e79f9cd127a4204723e /crates/ide_db/src/helpers
parent68626e4ef5acfea05812b68f41efa2bcd5bea448 (diff)
Do trait solving in batch
Diffstat (limited to 'crates/ide_db/src/helpers')
-rw-r--r--crates/ide_db/src/helpers/import_assets.rs192
1 files changed, 97 insertions, 95 deletions
diff --git a/crates/ide_db/src/helpers/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs
index a080b6ca7..517abbb4b 100644
--- a/crates/ide_db/src/helpers/import_assets.rs
+++ b/crates/ide_db/src/helpers/import_assets.rs
@@ -1,6 +1,6 @@
1//! Look up accessible paths for items. 1//! Look up accessible paths for items.
2use either::Either; 2use either::Either;
3use hir::{AsAssocItem, AssocItem, Module, ModuleDef, PrefixKind, Semantics}; 3use hir::{AsAssocItem, AssocItem, Crate, MacroDef, Module, ModuleDef, PrefixKind, Semantics};
4use rustc_hash::FxHashSet; 4use rustc_hash::FxHashSet;
5use syntax::{ast, AstNode}; 5use syntax::{ast, AstNode};
6 6
@@ -168,73 +168,8 @@ impl ImportAssets {
168 sema: &Semantics<RootDatabase>, 168 sema: &Semantics<RootDatabase>,
169 prefixed: Option<hir::PrefixKind>, 169 prefixed: Option<hir::PrefixKind>,
170 ) -> Vec<(hir::ModPath, hir::ItemInNs)> { 170 ) -> Vec<(hir::ModPath, hir::ItemInNs)> {
171 let db = sema.db;
172 let mut trait_candidates = FxHashSet::default();
173 let current_crate = self.module_with_candidate.krate(); 171 let current_crate = self.module_with_candidate.krate();
174 172
175 let filter = |candidate: Either<hir::ModuleDef, hir::MacroDef>| {
176 // TODO kb process all traits at once instead?
177 trait_candidates.clear();
178 match &self.import_candidate {
179 ImportCandidate::TraitAssocItem(trait_candidate) => {
180 let canidate_assoc_item = match candidate {
181 Either::Left(module_def) => module_def.as_assoc_item(db),
182 _ => None,
183 }?;
184 trait_candidates.insert(canidate_assoc_item.containing_trait(db)?.into());
185
186 trait_candidate
187 .receiver_ty
188 .iterate_path_candidates(
189 db,
190 current_crate,
191 &trait_candidates,
192 None,
193 |_, assoc| {
194 if canidate_assoc_item == assoc {
195 if let AssocItem::Function(f) = assoc {
196 if f.self_param(db).is_some() {
197 return None;
198 }
199 }
200 Some(assoc_to_module_def(assoc))
201 } else {
202 None
203 }
204 },
205 )
206 .map(Either::Left)
207 }
208 ImportCandidate::TraitMethod(trait_candidate) => {
209 let canidate_assoc_item = match candidate {
210 Either::Left(module_def) => module_def.as_assoc_item(db),
211 _ => None,
212 }?;
213 trait_candidates.insert(canidate_assoc_item.containing_trait(db)?.into());
214
215 trait_candidate
216 .receiver_ty
217 .iterate_method_candidates(
218 db,
219 current_crate,
220 &trait_candidates,
221 None,
222 |_, function| {
223 let assoc = function.as_assoc_item(db)?;
224 if canidate_assoc_item == assoc {
225 Some(assoc_to_module_def(assoc))
226 } else {
227 None
228 }
229 },
230 )
231 .map(ModuleDef::from)
232 .map(Either::Left)
233 }
234 _ => Some(candidate),
235 }
236 };
237
238 let unfiltered_imports = match self.name_to_import() { 173 let unfiltered_imports = match self.name_to_import() {
239 NameToImport::Exact(exact_name) => { 174 NameToImport::Exact(exact_name) => {
240 imports_locator::find_exact_imports(sema, current_crate, exact_name.clone()) 175 imports_locator::find_exact_imports(sema, current_crate, exact_name.clone())
@@ -261,42 +196,109 @@ impl ImportAssets {
261 } 196 }
262 }; 197 };
263 198
264 let mut res = unfiltered_imports 199 let db = sema.db;
265 .filter_map(filter) 200 let mut res =
266 .filter_map(|candidate| { 201 applicable_defs(self.import_candidate(), current_crate, db, unfiltered_imports)
267 let item: hir::ItemInNs = candidate.clone().either(Into::into, Into::into); 202 .filter_map(|candidate| {
203 let item: hir::ItemInNs = candidate.clone().either(Into::into, Into::into);
268 204
269 let item_to_search = match self.import_candidate { 205 let item_to_search = match self.import_candidate {
270 ImportCandidate::TraitAssocItem(_) | ImportCandidate::TraitMethod(_) => { 206 ImportCandidate::TraitAssocItem(_) | ImportCandidate::TraitMethod(_) => {
271 let canidate_trait = match candidate { 207 let canidate_trait = match candidate {
272 Either::Left(module_def) => { 208 Either::Left(module_def) => {
273 module_def.as_assoc_item(db)?.containing_trait(db) 209 module_def.as_assoc_item(db)?.containing_trait(db)
274 } 210 }
275 _ => None, 211 _ => None,
276 }?; 212 }?;
277 ModuleDef::from(canidate_trait).into() 213 ModuleDef::from(canidate_trait).into()
278 } 214 }
279 _ => item, 215 _ => item,
280 }; 216 };
281 217
282 if let Some(prefix_kind) = prefixed { 218 if let Some(prefix_kind) = prefixed {
283 self.module_with_candidate.find_use_path_prefixed( 219 self.module_with_candidate.find_use_path_prefixed(
284 db, 220 db,
285 item_to_search, 221 item_to_search,
286 prefix_kind, 222 prefix_kind,
287 ) 223 )
288 } else { 224 } else {
289 self.module_with_candidate.find_use_path(db, item_to_search) 225 self.module_with_candidate.find_use_path(db, item_to_search)
290 } 226 }
291 .map(|path| (path, item)) 227 .map(|path| (path, item))
292 }) 228 })
293 .filter(|(use_path, _)| use_path.len() > 1) 229 .filter(|(use_path, _)| use_path.len() > 1)
294 .collect::<Vec<_>>(); 230 .collect::<Vec<_>>();
295 res.sort_by_cached_key(|(path, _)| path.clone()); 231 res.sort_by_cached_key(|(path, _)| path.clone());
296 res 232 res
297 } 233 }
298} 234}
299 235
236fn applicable_defs<'a>(
237 import_candidate: &ImportCandidate,
238 current_crate: Crate,
239 db: &RootDatabase,
240 unfiltered_imports: Box<dyn Iterator<Item = Either<ModuleDef, MacroDef>> + 'a>,
241) -> Box<dyn Iterator<Item = Either<ModuleDef, MacroDef>> + 'a> {
242 let receiver_ty = match import_candidate {
243 ImportCandidate::Path(_) => return unfiltered_imports,
244 ImportCandidate::TraitAssocItem(candidate) | ImportCandidate::TraitMethod(candidate) => {
245 &candidate.receiver_ty
246 }
247 };
248
249 let mut required_assoc_items = FxHashSet::default();
250
251 let trait_candidates = unfiltered_imports
252 .filter_map(|input| match input {
253 Either::Left(module_def) => module_def.as_assoc_item(db),
254 _ => None,
255 })
256 .filter_map(|assoc| {
257 let assoc_item_trait = assoc.containing_trait(db)?;
258 required_assoc_items.insert(assoc);
259 Some(assoc_item_trait.into())
260 })
261 .collect();
262
263 let mut applicable_defs = FxHashSet::default();
264
265 match import_candidate {
266 ImportCandidate::Path(_) => unreachable!(),
267 ImportCandidate::TraitAssocItem(_) => receiver_ty.iterate_path_candidates(
268 db,
269 current_crate,
270 &trait_candidates,
271 None,
272 |_, assoc| {
273 if required_assoc_items.contains(&assoc) {
274 if let AssocItem::Function(f) = assoc {
275 if f.self_param(db).is_some() {
276 return None;
277 }
278 }
279 applicable_defs.insert(Either::Left(assoc_to_module_def(assoc)));
280 }
281 None::<()>
282 },
283 ),
284 ImportCandidate::TraitMethod(_) => receiver_ty.iterate_method_candidates(
285 db,
286 current_crate,
287 &trait_candidates,
288 None,
289 |_, function| {
290 let assoc = function.as_assoc_item(db)?;
291 if required_assoc_items.contains(&assoc) {
292 applicable_defs.insert(Either::Left(assoc_to_module_def(assoc)));
293 }
294 None::<()>
295 },
296 ),
297 };
298
299 Box::new(applicable_defs.into_iter())
300}
301
300fn assoc_to_module_def(assoc: AssocItem) -> ModuleDef { 302fn assoc_to_module_def(assoc: AssocItem) -> ModuleDef {
301 match assoc { 303 match assoc {
302 AssocItem::Function(f) => f.into(), 304 AssocItem::Function(f) => f.into(),