Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir/src/lib.rs')
-rw-r--r--crates/hir/src/lib.rs139
1 files changed, 118 insertions, 21 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index f0d8d5a830..8289c9006c 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -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)
+ }
+}