Merge pull request #18179 from ChayimFriedman2/omit-trait-completion

feat: Allow excluding specific traits from completion
This commit is contained in:
Lukas Wirth 2025-01-01 14:34:56 +00:00 committed by GitHub
commit 7e639ee3dd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 1028 additions and 100 deletions

View file

@ -258,7 +258,7 @@ fn resolve_impl_trait_item(
&traits_in_scope,
method_resolution::VisibleFromModule::None,
Some(name),
&mut |assoc_item_id| {
&mut |_, assoc_item_id: AssocItemId, _| {
// If two traits in scope define the same item, Rustdoc links to no specific trait (for
// instance, given two methods `a`, Rustdoc simply links to `method.a` with no
// disambiguation) so we just pick the first one we find as well.

View file

@ -5223,21 +5223,18 @@ impl Type {
) -> Option<T> {
let _p = tracing::info_span!("iterate_method_candidates_with_traits").entered();
let mut slot = None;
self.iterate_method_candidates_dyn(
self.iterate_method_candidates_split_inherent(
db,
scope,
traits_in_scope,
with_local_impls,
name,
&mut |assoc_item_id| {
if let AssocItemId::FunctionId(func) = assoc_item_id {
if let Some(res) = callback(func.into()) {
slot = Some(res);
return ControlFlow::Break(());
}
|f| match callback(f) {
it @ Some(_) => {
slot = it;
ControlFlow::Break(())
}
ControlFlow::Continue(())
None => ControlFlow::Continue(()),
},
);
slot
@ -5261,15 +5258,49 @@ impl Type {
)
}
fn iterate_method_candidates_dyn(
/// Allows you to treat inherent and non-inherent methods differently.
///
/// Note that inherent methods may actually be trait methods! For example, in `dyn Trait`, the trait's methods
/// are considered inherent methods.
pub fn iterate_method_candidates_split_inherent(
&self,
db: &dyn HirDatabase,
scope: &SemanticsScope<'_>,
traits_in_scope: &FxHashSet<TraitId>,
with_local_impls: Option<Module>,
name: Option<&Name>,
callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
callback: impl MethodCandidateCallback,
) {
struct Callback<T>(T);
impl<T: MethodCandidateCallback> method_resolution::MethodCandidateCallback for Callback<T> {
fn on_inherent_method(
&mut self,
_adjustments: method_resolution::ReceiverAdjustments,
item: AssocItemId,
_is_visible: bool,
) -> ControlFlow<()> {
if let AssocItemId::FunctionId(func) = item {
self.0.on_inherent_method(func.into())
} else {
ControlFlow::Continue(())
}
}
fn on_trait_method(
&mut self,
_adjustments: method_resolution::ReceiverAdjustments,
item: AssocItemId,
_is_visible: bool,
) -> ControlFlow<()> {
if let AssocItemId::FunctionId(func) = item {
self.0.on_trait_method(func.into())
} else {
ControlFlow::Continue(())
}
}
}
let _p = tracing::info_span!(
"iterate_method_candidates_dyn",
with_local_impls = traits_in_scope.len(),
@ -5294,7 +5325,7 @@ impl Type {
with_local_impls.and_then(|b| b.id.containing_block()).into(),
name,
method_resolution::LookupMode::MethodCall,
&mut |_adj, id, _| callback(id),
&mut Callback(callback),
);
}
@ -5310,33 +5341,61 @@ impl Type {
) -> Option<T> {
let _p = tracing::info_span!("iterate_path_candidates").entered();
let mut slot = None;
self.iterate_path_candidates_dyn(
self.iterate_path_candidates_split_inherent(
db,
scope,
traits_in_scope,
with_local_impls,
name,
&mut |assoc_item_id| {
if let Some(res) = callback(assoc_item_id.into()) {
slot = Some(res);
return ControlFlow::Break(());
|item| match callback(item) {
it @ Some(_) => {
slot = it;
ControlFlow::Break(())
}
ControlFlow::Continue(())
None => ControlFlow::Continue(()),
},
);
slot
}
/// Iterates over inherent methods.
///
/// In some circumstances, inherent methods methods may actually be trait methods!
/// For example, when `dyn Trait` is a receiver, _trait_'s methods would be considered
/// to be inherent methods.
#[tracing::instrument(skip_all, fields(name = ?name))]
fn iterate_path_candidates_dyn(
pub fn iterate_path_candidates_split_inherent(
&self,
db: &dyn HirDatabase,
scope: &SemanticsScope<'_>,
traits_in_scope: &FxHashSet<TraitId>,
with_local_impls: Option<Module>,
name: Option<&Name>,
callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
callback: impl PathCandidateCallback,
) {
struct Callback<T>(T);
impl<T: PathCandidateCallback> method_resolution::MethodCandidateCallback for Callback<T> {
fn on_inherent_method(
&mut self,
_adjustments: method_resolution::ReceiverAdjustments,
item: AssocItemId,
_is_visible: bool,
) -> ControlFlow<()> {
self.0.on_inherent_item(item.into())
}
fn on_trait_method(
&mut self,
_adjustments: method_resolution::ReceiverAdjustments,
item: AssocItemId,
_is_visible: bool,
) -> ControlFlow<()> {
self.0.on_trait_item(item.into())
}
}
let canonical = hir_ty::replace_errors_with_variables(&self.ty);
let krate = scope.krate();
@ -5352,7 +5411,7 @@ impl Type {
traits_in_scope,
with_local_impls.and_then(|b| b.id.containing_block()).into(),
name,
callback,
&mut Callback(callback),
);
}
@ -6060,3 +6119,41 @@ fn push_ty_diagnostics(
);
}
}
pub trait MethodCandidateCallback {
fn on_inherent_method(&mut self, f: Function) -> ControlFlow<()>;
fn on_trait_method(&mut self, f: Function) -> ControlFlow<()>;
}
impl<F> MethodCandidateCallback for F
where
F: FnMut(Function) -> ControlFlow<()>,
{
fn on_inherent_method(&mut self, f: Function) -> ControlFlow<()> {
self(f)
}
fn on_trait_method(&mut self, f: Function) -> ControlFlow<()> {
self(f)
}
}
pub trait PathCandidateCallback {
fn on_inherent_item(&mut self, item: AssocItem) -> ControlFlow<()>;
fn on_trait_item(&mut self, item: AssocItem) -> ControlFlow<()>;
}
impl<F> PathCandidateCallback for F
where
F: FnMut(AssocItem) -> ControlFlow<()>,
{
fn on_inherent_item(&mut self, item: AssocItem) -> ControlFlow<()> {
self(item)
}
fn on_trait_item(&mut self, item: AssocItem) -> ControlFlow<()> {
self(item)
}
}

View file

@ -2060,6 +2060,11 @@ impl SemanticsScope<'_> {
)
}
pub fn resolve_mod_path(&self, path: &ModPath) -> impl Iterator<Item = ItemInNs> {
let items = self.resolver.resolve_module_path_in_items(self.db.upcast(), path);
items.iter_items().map(|(item, _)| item.into())
}
/// Iterates over associated types that may be specified after the given path (using
/// `Ty::Assoc` syntax).
pub fn assoc_type_shorthand_candidates<R>(