Merge pull request #20921 from ChayimFriedman2/specialization-ns2
Avoid calling `specializes()` query on crates that do not define `#![feature(specialization)]`
diff --git a/crates/ide-completion/src/tests/flyimport.rs b/crates/ide-completion/src/tests/flyimport.rs
index 0cd4208..e139a5e 100644
--- a/crates/ide-completion/src/tests/flyimport.rs
+++ b/crates/ide-completion/src/tests/flyimport.rs
@@ -1953,3 +1953,25 @@
expect![""],
);
}
+
+#[test]
+fn multiple_matches_with_qualifier() {
+ check(
+ r#"
+//- /foo.rs crate:foo
+pub mod env {
+ pub fn var() {}
+ pub fn _var() {}
+}
+
+//- /bar.rs crate:bar deps:foo
+fn main() {
+ env::var$0
+}
+ "#,
+ expect![[r#"
+ fn _var() (use foo::env) fn()
+ fn var() (use foo::env) fn()
+ "#]],
+ );
+}
diff --git a/crates/ide-db/src/imports/import_assets.rs b/crates/ide-db/src/imports/import_assets.rs
index 0c235c8..50edfca 100644
--- a/crates/ide-db/src/imports/import_assets.rs
+++ b/crates/ide-db/src/imports/import_assets.rs
@@ -1,6 +1,6 @@
//! Look up accessible paths for items.
-use std::ops::ControlFlow;
+use std::{convert::Infallible, ops::ControlFlow};
use hir::{
AsAssocItem, AssocItem, AssocItemContainer, Complete, Crate, FindPathConfig, HasCrate,
@@ -9,6 +9,7 @@
};
use itertools::Itertools;
use rustc_hash::{FxHashMap, FxHashSet};
+use smallvec::SmallVec;
use syntax::{
AstNode, SyntaxNode,
ast::{self, HasName, make},
@@ -416,7 +417,7 @@
NameToImport::Exact(first_qsegment.as_str().to_owned(), true),
AssocSearchMode::Exclude,
)
- .filter_map(|(item, do_not_complete)| {
+ .flat_map(|(item, do_not_complete)| {
// we found imports for `first_qsegment`, now we need to filter these imports by whether
// they result in resolving the rest of the path successfully
validate_resolvable(
@@ -446,10 +447,10 @@
resolved_qualifier: ItemInNs,
unresolved_qualifier: &[Name],
complete_in_flyimport: CompleteInFlyimport,
-) -> Option<LocatedImport> {
+) -> SmallVec<[LocatedImport; 1]> {
let _p = tracing::info_span!("ImportAssets::import_for_item").entered();
- let qualifier = {
+ let qualifier = (|| {
let mut adjusted_resolved_qualifier = resolved_qualifier;
if !unresolved_qualifier.is_empty() {
match resolved_qualifier {
@@ -464,69 +465,80 @@
}
match adjusted_resolved_qualifier {
- ItemInNs::Types(def) => def,
- _ => return None,
+ ItemInNs::Types(def) => Some(def),
+ _ => None,
}
- };
- let import_path_candidate = mod_path(resolved_qualifier)?;
+ })();
+ let Some(qualifier) = qualifier else { return SmallVec::new() };
+ let Some(import_path_candidate) = mod_path(resolved_qualifier) else { return SmallVec::new() };
+ let mut result = SmallVec::new();
let ty = match qualifier {
ModuleDef::Module(module) => {
- return items_locator::items_with_name_in_module(
+ items_locator::items_with_name_in_module::<Infallible>(
db,
module,
candidate.clone(),
AssocSearchMode::Exclude,
- |it| match scope_filter(it) {
- true => ControlFlow::Break(it),
- false => ControlFlow::Continue(()),
+ |item| {
+ if scope_filter(item) {
+ result.push(LocatedImport::new(
+ import_path_candidate.clone(),
+ resolved_qualifier,
+ item,
+ complete_in_flyimport,
+ ));
+ }
+ ControlFlow::Continue(())
},
- )
- .map(|item| {
- LocatedImport::new(
- import_path_candidate,
- resolved_qualifier,
- item,
- complete_in_flyimport,
- )
- });
+ );
+ return result;
}
// FIXME
- ModuleDef::Trait(_) => return None,
+ ModuleDef::Trait(_) => return SmallVec::new(),
ModuleDef::TypeAlias(alias) => alias.ty(db),
ModuleDef::BuiltinType(builtin) => builtin.ty(db),
ModuleDef::Adt(adt) => adt.ty(db),
- _ => return None,
+ _ => return SmallVec::new(),
};
- ty.iterate_path_candidates(db, scope, &FxHashSet::default(), None, None, |assoc| {
- // FIXME: Support extra trait imports
- if assoc.container_or_implemented_trait(db).is_some() {
- return None;
- }
- let name = assoc.name(db)?;
- let is_match = match candidate {
- NameToImport::Prefix(text, true) => name.as_str().starts_with(text),
- NameToImport::Prefix(text, false) => {
- name.as_str().chars().zip(text.chars()).all(|(name_char, candidate_char)| {
- name_char.eq_ignore_ascii_case(&candidate_char)
- })
+ ty.iterate_path_candidates::<Infallible>(
+ db,
+ scope,
+ &FxHashSet::default(),
+ None,
+ None,
+ |assoc| {
+ // FIXME: Support extra trait imports
+ if assoc.container_or_implemented_trait(db).is_some() {
+ return None;
}
- NameToImport::Exact(text, true) => name.as_str() == text,
- NameToImport::Exact(text, false) => name.as_str().eq_ignore_ascii_case(text),
- NameToImport::Fuzzy(text, true) => text.chars().all(|c| name.as_str().contains(c)),
- NameToImport::Fuzzy(text, false) => text
- .chars()
- .all(|c| name.as_str().chars().any(|name_char| name_char.eq_ignore_ascii_case(&c))),
- };
- if !is_match {
- return None;
- }
- Some(LocatedImport::new(
- import_path_candidate.clone(),
- resolved_qualifier,
- assoc_to_item(assoc),
- complete_in_flyimport,
- ))
- })
+ let name = assoc.name(db)?;
+ let is_match = match candidate {
+ NameToImport::Prefix(text, true) => name.as_str().starts_with(text),
+ NameToImport::Prefix(text, false) => {
+ name.as_str().chars().zip(text.chars()).all(|(name_char, candidate_char)| {
+ name_char.eq_ignore_ascii_case(&candidate_char)
+ })
+ }
+ NameToImport::Exact(text, true) => name.as_str() == text,
+ NameToImport::Exact(text, false) => name.as_str().eq_ignore_ascii_case(text),
+ NameToImport::Fuzzy(text, true) => text.chars().all(|c| name.as_str().contains(c)),
+ NameToImport::Fuzzy(text, false) => text.chars().all(|c| {
+ name.as_str().chars().any(|name_char| name_char.eq_ignore_ascii_case(&c))
+ }),
+ };
+ if !is_match {
+ return None;
+ }
+ result.push(LocatedImport::new(
+ import_path_candidate.clone(),
+ resolved_qualifier,
+ assoc_to_item(assoc),
+ complete_in_flyimport,
+ ));
+ None
+ },
+ );
+ result
}
pub fn item_for_path_search(db: &RootDatabase, item: ItemInNs) -> Option<ItemInNs> {