Skip to content

Commit 7e639ee

Browse files
authored
Merge pull request #18179 from ChayimFriedman2/omit-trait-completion
feat: Allow excluding specific traits from completion
2 parents e5950cd + 1adc805 commit 7e639ee

File tree

20 files changed

+1028
-100
lines changed

20 files changed

+1028
-100
lines changed

crates/hir-ty/src/method_resolution.rs

+58-11
Original file line numberDiff line numberDiff line change
@@ -913,7 +913,7 @@ pub fn iterate_path_candidates(
913913
traits_in_scope: &FxHashSet<TraitId>,
914914
visible_from_module: VisibleFromModule,
915915
name: Option<&Name>,
916-
callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
916+
callback: &mut dyn MethodCandidateCallback,
917917
) -> ControlFlow<()> {
918918
iterate_method_candidates_dyn(
919919
ty,
@@ -924,7 +924,7 @@ pub fn iterate_path_candidates(
924924
name,
925925
LookupMode::Path,
926926
// the adjustments are not relevant for path lookup
927-
&mut |_, id, _| callback(id),
927+
callback,
928928
)
929929
}
930930

@@ -936,7 +936,7 @@ pub fn iterate_method_candidates_dyn(
936936
visible_from_module: VisibleFromModule,
937937
name: Option<&Name>,
938938
mode: LookupMode,
939-
callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
939+
callback: &mut dyn MethodCandidateCallback,
940940
) -> ControlFlow<()> {
941941
let _p = tracing::info_span!(
942942
"iterate_method_candidates_dyn",
@@ -1006,7 +1006,7 @@ fn iterate_method_candidates_with_autoref(
10061006
traits_in_scope: &FxHashSet<TraitId>,
10071007
visible_from_module: VisibleFromModule,
10081008
name: Option<&Name>,
1009-
mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
1009+
callback: &mut dyn MethodCandidateCallback,
10101010
) -> ControlFlow<()> {
10111011
if receiver_ty.value.is_general_var(Interner, &receiver_ty.binders) {
10121012
// don't try to resolve methods on unknown types
@@ -1021,7 +1021,7 @@ fn iterate_method_candidates_with_autoref(
10211021
traits_in_scope,
10221022
visible_from_module,
10231023
name,
1024-
&mut callback,
1024+
callback,
10251025
)
10261026
};
10271027

@@ -1051,6 +1051,45 @@ fn iterate_method_candidates_with_autoref(
10511051
iterate_method_candidates_by_receiver(ref_muted, first_adjustment.with_autoref(Mutability::Mut))
10521052
}
10531053

1054+
pub trait MethodCandidateCallback {
1055+
fn on_inherent_method(
1056+
&mut self,
1057+
adjustments: ReceiverAdjustments,
1058+
item: AssocItemId,
1059+
is_visible: bool,
1060+
) -> ControlFlow<()>;
1061+
1062+
fn on_trait_method(
1063+
&mut self,
1064+
adjustments: ReceiverAdjustments,
1065+
item: AssocItemId,
1066+
is_visible: bool,
1067+
) -> ControlFlow<()>;
1068+
}
1069+
1070+
impl<F> MethodCandidateCallback for F
1071+
where
1072+
F: FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
1073+
{
1074+
fn on_inherent_method(
1075+
&mut self,
1076+
adjustments: ReceiverAdjustments,
1077+
item: AssocItemId,
1078+
is_visible: bool,
1079+
) -> ControlFlow<()> {
1080+
self(adjustments, item, is_visible)
1081+
}
1082+
1083+
fn on_trait_method(
1084+
&mut self,
1085+
adjustments: ReceiverAdjustments,
1086+
item: AssocItemId,
1087+
is_visible: bool,
1088+
) -> ControlFlow<()> {
1089+
self(adjustments, item, is_visible)
1090+
}
1091+
}
1092+
10541093
#[tracing::instrument(skip_all, fields(name = ?name))]
10551094
fn iterate_method_candidates_by_receiver(
10561095
table: &mut InferenceTable<'_>,
@@ -1059,7 +1098,7 @@ fn iterate_method_candidates_by_receiver(
10591098
traits_in_scope: &FxHashSet<TraitId>,
10601099
visible_from_module: VisibleFromModule,
10611100
name: Option<&Name>,
1062-
mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
1101+
callback: &mut dyn MethodCandidateCallback,
10631102
) -> ControlFlow<()> {
10641103
let receiver_ty = table.instantiate_canonical(receiver_ty);
10651104
// We're looking for methods with *receiver* type receiver_ty. These could
@@ -1075,7 +1114,9 @@ fn iterate_method_candidates_by_receiver(
10751114
Some(&receiver_ty),
10761115
Some(receiver_adjustments.clone()),
10771116
visible_from_module,
1078-
&mut callback,
1117+
&mut |adjustments, item, is_visible| {
1118+
callback.on_inherent_method(adjustments, item, is_visible)
1119+
},
10791120
)?
10801121
}
10811122
ControlFlow::Continue(())
@@ -1095,7 +1136,9 @@ fn iterate_method_candidates_by_receiver(
10951136
name,
10961137
Some(&receiver_ty),
10971138
Some(receiver_adjustments.clone()),
1098-
&mut callback,
1139+
&mut |adjustments, item, is_visible| {
1140+
callback.on_trait_method(adjustments, item, is_visible)
1141+
},
10991142
)?
11001143
}
11011144
ControlFlow::Continue(())
@@ -1110,7 +1153,7 @@ fn iterate_method_candidates_for_self_ty(
11101153
traits_in_scope: &FxHashSet<TraitId>,
11111154
visible_from_module: VisibleFromModule,
11121155
name: Option<&Name>,
1113-
mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
1156+
callback: &mut dyn MethodCandidateCallback,
11141157
) -> ControlFlow<()> {
11151158
let mut table = InferenceTable::new(db, env);
11161159
let self_ty = table.instantiate_canonical(self_ty.clone());
@@ -1121,7 +1164,9 @@ fn iterate_method_candidates_for_self_ty(
11211164
None,
11221165
None,
11231166
visible_from_module,
1124-
&mut callback,
1167+
&mut |adjustments, item, is_visible| {
1168+
callback.on_inherent_method(adjustments, item, is_visible)
1169+
},
11251170
)?;
11261171
iterate_trait_method_candidates(
11271172
&self_ty,
@@ -1130,7 +1175,9 @@ fn iterate_method_candidates_for_self_ty(
11301175
name,
11311176
None,
11321177
None,
1133-
callback,
1178+
&mut |adjustments, item, is_visible| {
1179+
callback.on_trait_method(adjustments, item, is_visible)
1180+
},
11341181
)
11351182
}
11361183

crates/hir/src/attrs.rs

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

crates/hir/src/lib.rs

+118-21
Original file line numberDiff line numberDiff line change
@@ -5223,21 +5223,18 @@ impl Type {
52235223
) -> Option<T> {
52245224
let _p = tracing::info_span!("iterate_method_candidates_with_traits").entered();
52255225
let mut slot = None;
5226-
5227-
self.iterate_method_candidates_dyn(
5226+
self.iterate_method_candidates_split_inherent(
52285227
db,
52295228
scope,
52305229
traits_in_scope,
52315230
with_local_impls,
52325231
name,
5233-
&mut |assoc_item_id| {
5234-
if let AssocItemId::FunctionId(func) = assoc_item_id {
5235-
if let Some(res) = callback(func.into()) {
5236-
slot = Some(res);
5237-
return ControlFlow::Break(());
5238-
}
5232+
|f| match callback(f) {
5233+
it @ Some(_) => {
5234+
slot = it;
5235+
ControlFlow::Break(())
52395236
}
5240-
ControlFlow::Continue(())
5237+
None => ControlFlow::Continue(()),
52415238
},
52425239
);
52435240
slot
@@ -5261,15 +5258,49 @@ impl Type {
52615258
)
52625259
}
52635260

5264-
fn iterate_method_candidates_dyn(
5261+
/// Allows you to treat inherent and non-inherent methods differently.
5262+
///
5263+
/// Note that inherent methods may actually be trait methods! For example, in `dyn Trait`, the trait's methods
5264+
/// are considered inherent methods.
5265+
pub fn iterate_method_candidates_split_inherent(
52655266
&self,
52665267
db: &dyn HirDatabase,
52675268
scope: &SemanticsScope<'_>,
52685269
traits_in_scope: &FxHashSet<TraitId>,
52695270
with_local_impls: Option<Module>,
52705271
name: Option<&Name>,
5271-
callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
5272+
callback: impl MethodCandidateCallback,
52725273
) {
5274+
struct Callback<T>(T);
5275+
5276+
impl<T: MethodCandidateCallback> method_resolution::MethodCandidateCallback for Callback<T> {
5277+
fn on_inherent_method(
5278+
&mut self,
5279+
_adjustments: method_resolution::ReceiverAdjustments,
5280+
item: AssocItemId,
5281+
_is_visible: bool,
5282+
) -> ControlFlow<()> {
5283+
if let AssocItemId::FunctionId(func) = item {
5284+
self.0.on_inherent_method(func.into())
5285+
} else {
5286+
ControlFlow::Continue(())
5287+
}
5288+
}
5289+
5290+
fn on_trait_method(
5291+
&mut self,
5292+
_adjustments: method_resolution::ReceiverAdjustments,
5293+
item: AssocItemId,
5294+
_is_visible: bool,
5295+
) -> ControlFlow<()> {
5296+
if let AssocItemId::FunctionId(func) = item {
5297+
self.0.on_trait_method(func.into())
5298+
} else {
5299+
ControlFlow::Continue(())
5300+
}
5301+
}
5302+
}
5303+
52735304
let _p = tracing::info_span!(
52745305
"iterate_method_candidates_dyn",
52755306
with_local_impls = traits_in_scope.len(),
@@ -5294,7 +5325,7 @@ impl Type {
52945325
with_local_impls.and_then(|b| b.id.containing_block()).into(),
52955326
name,
52965327
method_resolution::LookupMode::MethodCall,
5297-
&mut |_adj, id, _| callback(id),
5328+
&mut Callback(callback),
52985329
);
52995330
}
53005331

@@ -5310,33 +5341,61 @@ impl Type {
53105341
) -> Option<T> {
53115342
let _p = tracing::info_span!("iterate_path_candidates").entered();
53125343
let mut slot = None;
5313-
self.iterate_path_candidates_dyn(
5344+
5345+
self.iterate_path_candidates_split_inherent(
53145346
db,
53155347
scope,
53165348
traits_in_scope,
53175349
with_local_impls,
53185350
name,
5319-
&mut |assoc_item_id| {
5320-
if let Some(res) = callback(assoc_item_id.into()) {
5321-
slot = Some(res);
5322-
return ControlFlow::Break(());
5351+
|item| match callback(item) {
5352+
it @ Some(_) => {
5353+
slot = it;
5354+
ControlFlow::Break(())
53235355
}
5324-
ControlFlow::Continue(())
5356+
None => ControlFlow::Continue(()),
53255357
},
53265358
);
53275359
slot
53285360
}
53295361

5362+
/// Iterates over inherent methods.
5363+
///
5364+
/// In some circumstances, inherent methods methods may actually be trait methods!
5365+
/// For example, when `dyn Trait` is a receiver, _trait_'s methods would be considered
5366+
/// to be inherent methods.
53305367
#[tracing::instrument(skip_all, fields(name = ?name))]
5331-
fn iterate_path_candidates_dyn(
5368+
pub fn iterate_path_candidates_split_inherent(
53325369
&self,
53335370
db: &dyn HirDatabase,
53345371
scope: &SemanticsScope<'_>,
53355372
traits_in_scope: &FxHashSet<TraitId>,
53365373
with_local_impls: Option<Module>,
53375374
name: Option<&Name>,
5338-
callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
5375+
callback: impl PathCandidateCallback,
53395376
) {
5377+
struct Callback<T>(T);
5378+
5379+
impl<T: PathCandidateCallback> method_resolution::MethodCandidateCallback for Callback<T> {
5380+
fn on_inherent_method(
5381+
&mut self,
5382+
_adjustments: method_resolution::ReceiverAdjustments,
5383+
item: AssocItemId,
5384+
_is_visible: bool,
5385+
) -> ControlFlow<()> {
5386+
self.0.on_inherent_item(item.into())
5387+
}
5388+
5389+
fn on_trait_method(
5390+
&mut self,
5391+
_adjustments: method_resolution::ReceiverAdjustments,
5392+
item: AssocItemId,
5393+
_is_visible: bool,
5394+
) -> ControlFlow<()> {
5395+
self.0.on_trait_item(item.into())
5396+
}
5397+
}
5398+
53405399
let canonical = hir_ty::replace_errors_with_variables(&self.ty);
53415400

53425401
let krate = scope.krate();
@@ -5352,7 +5411,7 @@ impl Type {
53525411
traits_in_scope,
53535412
with_local_impls.and_then(|b| b.id.containing_block()).into(),
53545413
name,
5355-
callback,
5414+
&mut Callback(callback),
53565415
);
53575416
}
53585417

@@ -6060,3 +6119,41 @@ fn push_ty_diagnostics(
60606119
);
60616120
}
60626121
}
6122+
6123+
pub trait MethodCandidateCallback {
6124+
fn on_inherent_method(&mut self, f: Function) -> ControlFlow<()>;
6125+
6126+
fn on_trait_method(&mut self, f: Function) -> ControlFlow<()>;
6127+
}
6128+
6129+
impl<F> MethodCandidateCallback for F
6130+
where
6131+
F: FnMut(Function) -> ControlFlow<()>,
6132+
{
6133+
fn on_inherent_method(&mut self, f: Function) -> ControlFlow<()> {
6134+
self(f)
6135+
}
6136+
6137+
fn on_trait_method(&mut self, f: Function) -> ControlFlow<()> {
6138+
self(f)
6139+
}
6140+
}
6141+
6142+
pub trait PathCandidateCallback {
6143+
fn on_inherent_item(&mut self, item: AssocItem) -> ControlFlow<()>;
6144+
6145+
fn on_trait_item(&mut self, item: AssocItem) -> ControlFlow<()>;
6146+
}
6147+
6148+
impl<F> PathCandidateCallback for F
6149+
where
6150+
F: FnMut(AssocItem) -> ControlFlow<()>,
6151+
{
6152+
fn on_inherent_item(&mut self, item: AssocItem) -> ControlFlow<()> {
6153+
self(item)
6154+
}
6155+
6156+
fn on_trait_item(&mut self, item: AssocItem) -> ControlFlow<()> {
6157+
self(item)
6158+
}
6159+
}

crates/hir/src/semantics.rs

+5
Original file line numberDiff line numberDiff line change
@@ -2060,6 +2060,11 @@ impl SemanticsScope<'_> {
20602060
)
20612061
}
20622062

2063+
pub fn resolve_mod_path(&self, path: &ModPath) -> impl Iterator<Item = ItemInNs> {
2064+
let items = self.resolver.resolve_module_path_in_items(self.db.upcast(), path);
2065+
items.iter_items().map(|(item, _)| item.into())
2066+
}
2067+
20632068
/// Iterates over associated types that may be specified after the given path (using
20642069
/// `Ty::Assoc` syntax).
20652070
pub fn assoc_type_shorthand_candidates<R>(

0 commit comments

Comments
 (0)