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.rs | 178 |
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<()>; +} |