Skip to content

Commit

Permalink
Allow excluding specific traits from completion
Browse files Browse the repository at this point in the history
To be accurate, only their methods are excluded, the trait themselves are still available.

I also excluded a bunch of std traits by default. Some less opinionated, like `AsRef`, which should never be used directly except in generic scenarios (and won't be excluded there), some more opinionated, like the ops traits, which I know some users sometimes want to use directly. Either way it's configurable.

It should be pretty easy to extend support to excluding only specific methods, but I didn't do that currently.

Traits configured to be excluded are resolved in each completion request from scratch. If this proves too expensive, it is easy enough to cache them in the DB.
  • Loading branch information
ChayimFriedman2 committed Sep 29, 2024
1 parent 2f55a91 commit 39d3441
Show file tree
Hide file tree
Showing 18 changed files with 1,012 additions and 81 deletions.
7 changes: 7 additions & 0 deletions crates/hir-def/src/item_scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,13 @@ impl ItemScope {
.chain(self.unnamed_trait_imports.keys().copied())
}

pub fn trait_by_name(&self, name: &Name) -> Option<TraitId> {
self.types.get(name).and_then(|(def, _, _)| match def {
ModuleDefId::TraitId(it) => Some(*it),
_ => None,
})
}

pub(crate) fn resolutions(&self) -> impl Iterator<Item = (Option<Name>, PerNs)> + '_ {
self.entries().map(|(name, res)| (Some(name.clone()), res)).chain(
self.unnamed_trait_imports.iter().map(|(tr, (vis, i))| {
Expand Down
69 changes: 58 additions & 11 deletions crates/hir-ty/src/method_resolution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -914,7 +914,7 @@ pub fn iterate_path_candidates(
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule,
name: Option<&Name>,
callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
callback: &mut dyn MethodCandidateCallback,
) -> ControlFlow<()> {
iterate_method_candidates_dyn(
ty,
Expand All @@ -925,7 +925,7 @@ pub fn iterate_path_candidates(
name,
LookupMode::Path,
// the adjustments are not relevant for path lookup
&mut |_, id, _| callback(id),
callback,
)
}

Expand All @@ -937,7 +937,7 @@ pub fn iterate_method_candidates_dyn(
visible_from_module: VisibleFromModule,
name: Option<&Name>,
mode: LookupMode,
callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
callback: &mut dyn MethodCandidateCallback,
) -> ControlFlow<()> {
let _p = tracing::info_span!(
"iterate_method_candidates_dyn",
Expand Down Expand Up @@ -1007,7 +1007,7 @@ fn iterate_method_candidates_with_autoref(
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule,
name: Option<&Name>,
mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
callback: &mut dyn MethodCandidateCallback,
) -> ControlFlow<()> {
if receiver_ty.value.is_general_var(Interner, &receiver_ty.binders) {
// don't try to resolve methods on unknown types
Expand All @@ -1022,7 +1022,7 @@ fn iterate_method_candidates_with_autoref(
traits_in_scope,
visible_from_module,
name,
&mut callback,
callback,
)
};

Expand Down Expand Up @@ -1052,6 +1052,45 @@ fn iterate_method_candidates_with_autoref(
iterate_method_candidates_by_receiver(ref_muted, first_adjustment.with_autoref(Mutability::Mut))
}

pub trait MethodCandidateCallback {
fn on_inherent_method(
&mut self,
adjustments: ReceiverAdjustments,
item: AssocItemId,
is_visible: bool,
) -> ControlFlow<()>;

fn on_trait_method(
&mut self,
adjustments: ReceiverAdjustments,
item: AssocItemId,
is_visible: bool,
) -> ControlFlow<()>;
}

impl<F> MethodCandidateCallback for F
where
F: FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
{
fn on_inherent_method(
&mut self,
adjustments: ReceiverAdjustments,
item: AssocItemId,
is_visible: bool,
) -> ControlFlow<()> {
self(adjustments, item, is_visible)
}

fn on_trait_method(
&mut self,
adjustments: ReceiverAdjustments,
item: AssocItemId,
is_visible: bool,
) -> ControlFlow<()> {
self(adjustments, item, is_visible)
}
}

#[tracing::instrument(skip_all, fields(name = ?name))]
fn iterate_method_candidates_by_receiver(
table: &mut InferenceTable<'_>,
Expand All @@ -1060,7 +1099,7 @@ fn iterate_method_candidates_by_receiver(
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule,
name: Option<&Name>,
mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
callback: &mut dyn MethodCandidateCallback,
) -> ControlFlow<()> {
let receiver_ty = table.instantiate_canonical(receiver_ty);
// We're looking for methods with *receiver* type receiver_ty. These could
Expand All @@ -1076,7 +1115,9 @@ fn iterate_method_candidates_by_receiver(
Some(&receiver_ty),
Some(receiver_adjustments.clone()),
visible_from_module,
&mut callback,
&mut |adjustments, item, is_visible| {
callback.on_inherent_method(adjustments, item, is_visible)
},
)?
}
ControlFlow::Continue(())
Expand All @@ -1096,7 +1137,9 @@ fn iterate_method_candidates_by_receiver(
name,
Some(&receiver_ty),
Some(receiver_adjustments.clone()),
&mut callback,
&mut |adjustments, item, is_visible| {
callback.on_trait_method(adjustments, item, is_visible)
},
)?
}
ControlFlow::Continue(())
Expand All @@ -1111,7 +1154,7 @@ fn iterate_method_candidates_for_self_ty(
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule,
name: Option<&Name>,
mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
callback: &mut dyn MethodCandidateCallback,
) -> ControlFlow<()> {
let mut table = InferenceTable::new(db, env);
let self_ty = table.instantiate_canonical(self_ty.clone());
Expand All @@ -1122,7 +1165,9 @@ fn iterate_method_candidates_for_self_ty(
None,
None,
visible_from_module,
&mut callback,
&mut |adjustments, item, is_visible| {
callback.on_inherent_method(adjustments, item, is_visible)
},
)?;
iterate_trait_method_candidates(
&self_ty,
Expand All @@ -1131,7 +1176,9 @@ fn iterate_method_candidates_for_self_ty(
name,
None,
None,
callback,
&mut |adjustments, item, is_visible| {
callback.on_trait_method(adjustments, item, is_visible)
},
)
}

Expand Down
2 changes: 1 addition & 1 deletion crates/hir/src/attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Loading

0 comments on commit 39d3441

Please sign in to comment.