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.rs178
1 files changed, 148 insertions, 30 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index f8af04302f..4c5f9d2a5a 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -5219,28 +5219,49 @@ impl Type {
traits_in_scope: &FxHashSet<TraitId>,
with_local_impls: Option<Module>,
name: Option<&Name>,
- mut callback: impl FnMut(Function) -> Option<T>,
+ callback: impl FnMut(Function) -> Option<T>,
) -> Option<T> {
+ struct Callback<T, F> {
+ f: F,
+ slot: Option<T>,
+ }
+ impl<T, F> MethodCandidateCallback for &'_ mut Callback<T, F>
+ where
+ F: FnMut(Function) -> Option<T>,
+ {
+ fn on_inherent_method(&mut self, f: Function) -> ControlFlow<()> {
+ match (self.f)(f) {
+ it @ Some(_) => {
+ self.slot = it;
+ ControlFlow::Break(())
+ }
+ None => ControlFlow::Continue(()),
+ }
+ }
+
+ fn on_trait_method(&mut self, f: Function) -> ControlFlow<()> {
+ match (self.f)(f) {
+ it @ Some(_) => {
+ self.slot = it;
+ ControlFlow::Break(())
+ }
+ None => ControlFlow::Continue(()),
+ }
+ }
+ }
+
let _p = tracing::info_span!("iterate_method_candidates_with_traits").entered();
- let mut slot = None;
+ let mut callback = Callback { slot: None, f: callback };
- 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(());
- }
- }
- ControlFlow::Continue(())
- },
+ &mut callback,
);
- slot
+ callback.slot
}
pub fn iterate_method_candidates<T>(
@@ -5261,15 +5282,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 +5349,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),
);
}
@@ -5306,37 +5361,88 @@ impl Type {
traits_in_scope: &FxHashSet<TraitId>,
with_local_impls: Option<Module>,
name: Option<&Name>,
- mut callback: impl FnMut(AssocItem) -> Option<T>,
+ callback: impl FnMut(AssocItem) -> Option<T>,
) -> Option<T> {
+ struct Callback<T, F> {
+ f: F,
+ slot: Option<T>,
+ }
+ impl<T, F> PathCandidateCallback for &'_ mut Callback<T, F>
+ where
+ F: FnMut(AssocItem) -> Option<T>,
+ {
+ fn on_inherent_item(&mut self, item: AssocItem) -> ControlFlow<()> {
+ match (self.f)(item) {
+ it @ Some(_) => {
+ self.slot = it;
+ ControlFlow::Break(())
+ }
+ None => ControlFlow::Continue(()),
+ }
+ }
+
+ fn on_trait_item(&mut self, item: AssocItem) -> ControlFlow<()> {
+ match (self.f)(item) {
+ it @ Some(_) => {
+ self.slot = it;
+ ControlFlow::Break(())
+ }
+ None => ControlFlow::Continue(()),
+ }
+ }
+ }
+
let _p = tracing::info_span!("iterate_path_candidates").entered();
- let mut slot = None;
- self.iterate_path_candidates_dyn(
+ let mut callback = Callback { slot: None, f: callback };
+
+ 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(());
- }
- ControlFlow::Continue(())
- },
+ &mut callback,
);
- slot
+ callback.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 +5458,7 @@ impl Type {
traits_in_scope,
with_local_impls.and_then(|b| b.id.containing_block()).into(),
name,
- callback,
+ &mut Callback(callback),
);
}
@@ -6054,3 +6160,15 @@ 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<()>;
+}
+
+pub trait PathCandidateCallback {
+ fn on_inherent_item(&mut self, item: AssocItem) -> ControlFlow<()>;
+
+ fn on_trait_item(&mut self, item: AssocItem) -> ControlFlow<()>;
+}