1mod confirm;
7mod probe;
8
9use either::Either;
10use hir_expand::name::Name;
11use span::Edition;
12use tracing::{debug, instrument};
13
14use base_db::Crate;
15use hir_def::{
16 AssocItemId, BlockId, ConstId, FunctionId, GenericParamId, HasModule, ImplId, ItemContainerId,
17 ModuleId, TraitId,
18 attrs::AttrFlags,
19 expr_store::path::GenericArgs as HirGenericArgs,
20 hir::ExprId,
21 nameres::{DefMap, block_def_map, crate_def_map},
22 resolver::Resolver,
23};
24use intern::{Symbol, sym};
25use rustc_hash::{FxHashMap, FxHashSet};
26use rustc_type_ir::{
27 TypeVisitableExt,
28 fast_reject::{TreatParams, simplify_type},
29 inherent::{BoundExistentialPredicates, IntoKind, SliceLike},
30};
31use stdx::impl_from;
32use triomphe::Arc;
33
34use crate::{
35 all_super_traits,
36 db::HirDatabase,
37 infer::{InferenceContext, unify::InferenceTable},
38 lower::GenericPredicates,
39 next_solver::{
40 Binder, ClauseKind, DbInterner, FnSig, GenericArgs, ParamEnv, PredicateKind,
41 SimplifiedType, SolverDefId, TraitRef, Ty, TyKind, TypingMode,
42 infer::{
43 BoundRegionConversionTime, DbInternerInferExt, InferCtxt, InferOk,
44 select::ImplSource,
45 traits::{Obligation, ObligationCause, PredicateObligations},
46 },
47 obligation_ctxt::ObligationCtxt,
48 util::clauses_as_obligations,
49 },
50 traits::ParamEnvAndCrate,
51};
52
53pub use self::probe::{
54 Candidate, CandidateKind, CandidateStep, CandidateWithPrivate, Mode, Pick, PickKind,
55};
56
57#[derive(Debug, Clone)]
58pub struct MethodResolutionUnstableFeatures {
59 arbitrary_self_types: bool,
60 arbitrary_self_types_pointers: bool,
61 supertrait_item_shadowing: bool,
62}
63
64impl MethodResolutionUnstableFeatures {
65 pub fn from_def_map(def_map: &DefMap) -> Self {
66 Self {
67 arbitrary_self_types: def_map.is_unstable_feature_enabled(&sym::arbitrary_self_types),
68 arbitrary_self_types_pointers: def_map
69 .is_unstable_feature_enabled(&sym::arbitrary_self_types_pointers),
70 supertrait_item_shadowing: def_map
71 .is_unstable_feature_enabled(&sym::supertrait_item_shadowing),
72 }
73 }
74}
75
76pub struct MethodResolutionContext<'a, 'db> {
77 pub infcx: &'a InferCtxt<'db>,
78 pub resolver: &'a Resolver<'db>,
79 pub param_env: ParamEnv<'db>,
80 pub traits_in_scope: &'a FxHashSet<TraitId>,
81 pub edition: Edition,
82 pub unstable_features: &'a MethodResolutionUnstableFeatures,
83}
84
85#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Update)]
86pub enum CandidateId {
87 FunctionId(FunctionId),
88 ConstId(ConstId),
89}
90impl_from!(FunctionId, ConstId for CandidateId);
91
92impl CandidateId {
93 fn container(self, db: &dyn HirDatabase) -> ItemContainerId {
94 match self {
95 CandidateId::FunctionId(id) => id.loc(db).container,
96 CandidateId::ConstId(id) => id.loc(db).container,
97 }
98 }
99}
100
101#[derive(Clone, Copy, Debug)]
102pub(crate) struct MethodCallee<'db> {
103 pub def_id: FunctionId,
105 pub args: GenericArgs<'db>,
106
107 pub sig: FnSig<'db>,
111}
112
113#[derive(Debug)]
114pub enum MethodError<'db> {
115 NoMatch,
117
118 Ambiguity(Vec<CandidateSource>),
120
121 PrivateMatch(Pick<'db>),
123
124 IllegalSizedBound { candidates: Vec<FunctionId>, needs_mut: bool },
126
127 ErrorReported,
129}
130
131#[derive(Copy, Clone, Debug, Eq, PartialEq)]
134pub enum CandidateSource {
135 Impl(ImplId),
136 Trait(TraitId),
137}
138
139impl<'a, 'db> InferenceContext<'a, 'db> {
140 #[instrument(level = "debug", skip(self))]
144 pub(crate) fn lookup_method_including_private(
145 &mut self,
146 self_ty: Ty<'db>,
147 name: Name,
148 generic_args: Option<&HirGenericArgs>,
149 receiver: ExprId,
150 call_expr: ExprId,
151 ) -> Result<(MethodCallee<'db>, bool), MethodError<'db>> {
152 let (pick, is_visible) = match self.lookup_probe(name, self_ty) {
153 Ok(it) => (it, true),
154 Err(MethodError::PrivateMatch(it)) => {
155 (it, false)
157 }
158 Err(err) => return Err(err),
159 };
160
161 let result = self.confirm_method(&pick, self_ty, call_expr, generic_args);
162 debug!("result = {:?}", result);
163
164 if result.illegal_sized_bound {
165 }
167
168 self.write_expr_adj(receiver, result.adjustments);
169 self.write_method_resolution(call_expr, result.callee.def_id, result.callee.args);
170
171 Ok((result.callee, is_visible))
172 }
173
174 #[instrument(level = "debug", skip(self))]
175 pub(crate) fn lookup_probe(
176 &self,
177 method_name: Name,
178 self_ty: Ty<'db>,
179 ) -> probe::PickResult<'db> {
180 self.with_method_resolution(|ctx| {
181 let pick = ctx.probe_for_name(probe::Mode::MethodCall, method_name, self_ty)?;
182 Ok(pick)
183 })
184 }
185
186 pub(crate) fn with_method_resolution<R>(
187 &self,
188 f: impl FnOnce(&MethodResolutionContext<'_, 'db>) -> R,
189 ) -> R {
190 let traits_in_scope = self.get_traits_in_scope();
191 let traits_in_scope = match &traits_in_scope {
192 Either::Left(it) => it,
193 Either::Right(it) => *it,
194 };
195 let ctx = MethodResolutionContext {
196 infcx: &self.table.infer_ctxt,
197 resolver: &self.resolver,
198 param_env: self.table.param_env,
199 traits_in_scope,
200 edition: self.edition,
201 unstable_features: &self.unstable_features,
202 };
203 f(&ctx)
204 }
205}
206
207#[derive(Debug)]
219#[expect(dead_code)]
220pub(super) enum TreatNotYetDefinedOpaques {
221 AsInfer,
222 AsRigid,
223}
224
225impl<'db> InferenceTable<'db> {
226 #[instrument(level = "debug", skip(self))]
232 pub(super) fn lookup_method_for_operator(
233 &self,
234 cause: ObligationCause,
235 method_name: Symbol,
236 trait_def_id: TraitId,
237 self_ty: Ty<'db>,
238 opt_rhs_ty: Option<Ty<'db>>,
239 treat_opaques: TreatNotYetDefinedOpaques,
240 ) -> Option<InferOk<'db, MethodCallee<'db>>> {
241 let args = GenericArgs::for_item(
243 self.interner(),
244 trait_def_id.into(),
245 |param_idx, param_id, _| match param_id {
246 GenericParamId::LifetimeParamId(_) | GenericParamId::ConstParamId(_) => {
247 unreachable!("did not expect operator trait to have lifetime/const")
248 }
249 GenericParamId::TypeParamId(_) => {
250 if param_idx == 0 {
251 self_ty.into()
252 } else if let Some(rhs_ty) = opt_rhs_ty {
253 assert_eq!(param_idx, 1, "did not expect >1 param on operator trait");
254 rhs_ty.into()
255 } else {
256 self.next_var_for_param(param_id)
260 }
261 }
262 },
263 );
264
265 let obligation = Obligation::new(
266 self.interner(),
267 cause,
268 self.param_env,
269 TraitRef::new_from_args(self.interner(), trait_def_id.into(), args),
270 );
271
272 let matches_trait = match treat_opaques {
274 TreatNotYetDefinedOpaques::AsInfer => self.infer_ctxt.predicate_may_hold(&obligation),
275 TreatNotYetDefinedOpaques::AsRigid => {
276 self.infer_ctxt.predicate_may_hold_opaque_types_jank(&obligation)
277 }
278 };
279
280 if !matches_trait {
281 debug!("--> Cannot match obligation");
282 return None;
284 }
285
286 let interner = self.interner();
289 let Some(method_item) =
292 trait_def_id.trait_items(self.db).method_by_name(&Name::new_symbol_root(method_name))
293 else {
294 panic!("expected associated item for operator trait")
295 };
296
297 let def_id = method_item;
298
299 debug!("lookup_in_trait_adjusted: method_item={:?}", method_item);
300 let mut obligations = PredicateObligations::new();
301
302 let fn_sig =
309 self.db.callable_item_signature(method_item.into()).instantiate(interner, args);
310 let fn_sig = self
311 .infer_ctxt
312 .instantiate_binder_with_fresh_vars(BoundRegionConversionTime::FnCall, fn_sig);
313
314 let bounds = GenericPredicates::query_all(self.db, method_item.into());
323 let bounds = clauses_as_obligations(
324 bounds.iter_instantiated_copied(interner, args.as_slice()),
325 ObligationCause::new(),
326 self.param_env,
327 );
328
329 obligations.extend(bounds);
330
331 debug!(
333 "lookup_method_in_trait: matched method fn_sig={:?} obligation={:?}",
334 fn_sig, obligation
335 );
336 for ty in fn_sig.inputs_and_output {
337 obligations.push(Obligation::new(
338 interner,
339 obligation.cause.clone(),
340 self.param_env,
341 Binder::dummy(PredicateKind::Clause(ClauseKind::WellFormed(ty.into()))),
342 ));
343 }
344
345 let callee = MethodCallee { def_id, args, sig: fn_sig };
346 debug!("callee = {:?}", callee);
347
348 Some(InferOk { obligations, value: callee })
349 }
350}
351
352pub fn lookup_impl_const<'db>(
353 infcx: &InferCtxt<'db>,
354 env: ParamEnv<'db>,
355 const_id: ConstId,
356 subs: GenericArgs<'db>,
357) -> (ConstId, GenericArgs<'db>) {
358 let interner = infcx.interner;
359 let db = interner.db;
360
361 let trait_id = match const_id.loc(db).container {
362 ItemContainerId::TraitId(id) => id,
363 _ => return (const_id, subs),
364 };
365 let trait_ref = TraitRef::new(interner, trait_id.into(), subs);
366
367 let const_signature = db.const_signature(const_id);
368 let name = match const_signature.name.as_ref() {
369 Some(name) => name,
370 None => return (const_id, subs),
371 };
372
373 lookup_impl_assoc_item_for_trait_ref(infcx, trait_ref, env, name)
374 .and_then(
375 |assoc| if let (AssocItemId::ConstId(id), s) = assoc { Some((id, s)) } else { None },
376 )
377 .unwrap_or((const_id, subs))
378}
379
380pub fn is_dyn_method<'db>(
383 interner: DbInterner<'db>,
384 _env: ParamEnv<'db>,
385 func: FunctionId,
386 fn_subst: GenericArgs<'db>,
387) -> Option<usize> {
388 let db = interner.db;
389
390 let ItemContainerId::TraitId(trait_id) = func.loc(db).container else {
391 return None;
392 };
393 let trait_params = db.generic_params(trait_id.into()).len();
394 let fn_params = fn_subst.len() - trait_params;
395 let trait_ref = TraitRef::new(
396 interner,
397 trait_id.into(),
398 GenericArgs::new_from_iter(interner, fn_subst.iter().take(trait_params)),
399 );
400 let self_ty = trait_ref.self_ty();
401 if let TyKind::Dynamic(d, _) = self_ty.kind() {
402 let is_my_trait_in_bounds = d
405 .principal_def_id()
406 .is_some_and(|trait_| all_super_traits(db, trait_.0).contains(&trait_id));
407 if is_my_trait_in_bounds {
408 return Some(fn_params);
409 }
410 }
411 None
412}
413
414pub(crate) fn lookup_impl_method_query<'db>(
418 db: &'db dyn HirDatabase,
419 env: ParamEnvAndCrate<'db>,
420 func: FunctionId,
421 fn_subst: GenericArgs<'db>,
422) -> (FunctionId, GenericArgs<'db>) {
423 let interner = DbInterner::new_with(db, env.krate);
424 let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);
425
426 let ItemContainerId::TraitId(trait_id) = func.loc(db).container else {
427 return (func, fn_subst);
428 };
429 let trait_params = db.generic_params(trait_id.into()).len();
430 let trait_ref = TraitRef::new(
431 interner,
432 trait_id.into(),
433 GenericArgs::new_from_iter(interner, fn_subst.iter().take(trait_params)),
434 );
435
436 let name = &db.function_signature(func).name;
437 let Some((impl_fn, impl_subst)) = lookup_impl_assoc_item_for_trait_ref(
438 &infcx,
439 trait_ref,
440 env.param_env,
441 name,
442 )
443 .and_then(|assoc| {
444 if let (AssocItemId::FunctionId(id), subst) = assoc { Some((id, subst)) } else { None }
445 }) else {
446 return (func, fn_subst);
447 };
448
449 (
450 impl_fn,
451 GenericArgs::new_from_iter(
452 interner,
453 impl_subst.iter().chain(fn_subst.iter().skip(trait_params)),
454 ),
455 )
456}
457
458fn lookup_impl_assoc_item_for_trait_ref<'db>(
459 infcx: &InferCtxt<'db>,
460 trait_ref: TraitRef<'db>,
461 env: ParamEnv<'db>,
462 name: &Name,
463) -> Option<(AssocItemId, GenericArgs<'db>)> {
464 let (impl_id, impl_subst) = find_matching_impl(infcx, env, trait_ref)?;
465 let item =
466 impl_id.impl_items(infcx.interner.db).items.iter().find_map(|(n, it)| match *it {
467 AssocItemId::FunctionId(f) => (n == name).then_some(AssocItemId::FunctionId(f)),
468 AssocItemId::ConstId(c) => (n == name).then_some(AssocItemId::ConstId(c)),
469 AssocItemId::TypeAliasId(_) => None,
470 })?;
471 Some((item, impl_subst))
472}
473
474pub(crate) fn find_matching_impl<'db>(
475 infcx: &InferCtxt<'db>,
476 env: ParamEnv<'db>,
477 trait_ref: TraitRef<'db>,
478) -> Option<(ImplId, GenericArgs<'db>)> {
479 let trait_ref = infcx.at(&ObligationCause::dummy(), env).deeply_normalize(trait_ref).ok()?;
480
481 let obligation = Obligation::new(infcx.interner, ObligationCause::dummy(), env, trait_ref);
482
483 let selection = infcx.select(&obligation).ok()??;
484
485 let mut ocx = ObligationCtxt::new(infcx);
489 let impl_source = selection.map(|obligation| ocx.register_obligation(obligation));
490
491 let errors = ocx.evaluate_obligations_error_on_ambiguity();
492 if !errors.is_empty() {
493 return None;
494 }
495
496 let impl_source = infcx.resolve_vars_if_possible(impl_source);
497 if impl_source.has_non_region_infer() {
498 return None;
499 }
500
501 match impl_source {
502 ImplSource::UserDefined(impl_source) => Some((impl_source.impl_def_id, impl_source.args)),
503 ImplSource::Param(_) | ImplSource::Builtin(..) => None,
504 }
505}
506
507#[salsa::tracked(returns(ref))]
508fn crates_containing_incoherent_inherent_impls(db: &dyn HirDatabase, krate: Crate) -> Box<[Crate]> {
509 let _p = tracing::info_span!("crates_containing_incoherent_inherent_impls").entered();
510 krate.transitive_deps(db).into_iter().filter(|krate| krate.data(db).origin.is_lang()).collect()
513}
514
515pub fn with_incoherent_inherent_impls(
516 db: &dyn HirDatabase,
517 krate: Crate,
518 self_ty: &SimplifiedType,
519 mut callback: impl FnMut(&[ImplId]),
520) {
521 let has_incoherent_impls = match self_ty.def() {
522 Some(def_id) => match def_id.try_into() {
523 Ok(def_id) => AttrFlags::query(db, def_id)
524 .contains(AttrFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS),
525 Err(()) => true,
526 },
527 _ => true,
528 };
529 if !has_incoherent_impls {
530 return;
531 }
532 let _p = tracing::info_span!("incoherent_inherent_impls").entered();
533 let crates = crates_containing_incoherent_inherent_impls(db, krate);
534 for &krate in crates {
535 let impls = InherentImpls::for_crate(db, krate);
536 callback(impls.for_self_ty(self_ty));
537 }
538}
539
540pub fn simplified_type_module(db: &dyn HirDatabase, ty: &SimplifiedType) -> Option<ModuleId> {
541 match ty.def()? {
542 SolverDefId::AdtId(id) => Some(id.module(db)),
543 SolverDefId::TypeAliasId(id) => Some(id.module(db)),
544 SolverDefId::TraitId(id) => Some(id.module(db)),
545 _ => None,
546 }
547}
548
549#[derive(Debug, PartialEq, Eq)]
550pub struct InherentImpls {
551 map: FxHashMap<SimplifiedType, Box<[ImplId]>>,
552}
553
554#[salsa::tracked]
555impl InherentImpls {
556 #[salsa::tracked(returns(ref))]
557 pub fn for_crate(db: &dyn HirDatabase, krate: Crate) -> Self {
558 let _p = tracing::info_span!("inherent_impls_in_crate_query", ?krate).entered();
559
560 let crate_def_map = crate_def_map(db, krate);
561
562 Self::collect_def_map(db, crate_def_map)
563 }
564
565 #[salsa::tracked(returns(ref))]
566 pub fn for_block(db: &dyn HirDatabase, block: BlockId) -> Option<Box<Self>> {
567 let _p = tracing::info_span!("inherent_impls_in_block_query").entered();
568
569 let block_def_map = block_def_map(db, block);
570 let result = Self::collect_def_map(db, block_def_map);
571 if result.map.is_empty() { None } else { Some(Box::new(result)) }
572 }
573}
574
575impl InherentImpls {
576 fn collect_def_map(db: &dyn HirDatabase, def_map: &DefMap) -> Self {
577 let mut map = FxHashMap::default();
578 collect(db, def_map, &mut map);
579 let mut map = map
580 .into_iter()
581 .map(|(self_ty, impls)| (self_ty, impls.into_boxed_slice()))
582 .collect::<FxHashMap<_, _>>();
583 map.shrink_to_fit();
584 return Self { map };
585
586 fn collect(
587 db: &dyn HirDatabase,
588 def_map: &DefMap,
589 map: &mut FxHashMap<SimplifiedType, Vec<ImplId>>,
590 ) {
591 for (_module_id, module_data) in def_map.modules() {
592 for impl_id in module_data.scope.impls() {
593 let data = db.impl_signature(impl_id);
594 if data.target_trait.is_some() {
595 continue;
596 }
597
598 let interner = DbInterner::new_no_crate(db);
599 let self_ty = db.impl_self_ty(impl_id);
600 let self_ty = self_ty.instantiate_identity();
601 if let Some(self_ty) =
602 simplify_type(interner, self_ty, TreatParams::InstantiateWithInfer)
603 {
604 map.entry(self_ty).or_default().push(impl_id);
605 }
606 }
607
608 for konst in module_data.scope.unnamed_consts() {
611 let body = db.body(konst.into());
612 for (_, block_def_map) in body.blocks(db) {
613 collect(db, block_def_map, map);
614 }
615 }
616 }
617 }
618 }
619
620 pub fn for_self_ty(&self, self_ty: &SimplifiedType) -> &[ImplId] {
621 self.map.get(self_ty).map(|it| &**it).unwrap_or_default()
622 }
623
624 pub fn for_each_crate_and_block(
625 db: &dyn HirDatabase,
626 krate: Crate,
627 block: Option<BlockId>,
628 for_each: &mut dyn FnMut(&InherentImpls),
629 ) {
630 let blocks = std::iter::successors(block, |block| block.loc(db).module.block(db));
631 blocks.filter_map(|block| Self::for_block(db, block).as_deref()).for_each(&mut *for_each);
632 for_each(Self::for_crate(db, krate));
633 }
634}
635
636#[derive(Debug, PartialEq)]
637struct OneTraitImpls {
638 non_blanket_impls: FxHashMap<SimplifiedType, Box<[ImplId]>>,
639 blanket_impls: Box<[ImplId]>,
640}
641
642#[derive(Default)]
643struct OneTraitImplsBuilder {
644 non_blanket_impls: FxHashMap<SimplifiedType, Vec<ImplId>>,
645 blanket_impls: Vec<ImplId>,
646}
647
648impl OneTraitImplsBuilder {
649 fn finish(self) -> OneTraitImpls {
650 let mut non_blanket_impls = self
651 .non_blanket_impls
652 .into_iter()
653 .map(|(self_ty, impls)| (self_ty, impls.into_boxed_slice()))
654 .collect::<FxHashMap<_, _>>();
655 non_blanket_impls.shrink_to_fit();
656 let blanket_impls = self.blanket_impls.into_boxed_slice();
657 OneTraitImpls { non_blanket_impls, blanket_impls }
658 }
659}
660
661#[derive(Debug, PartialEq)]
662pub struct TraitImpls {
663 map: FxHashMap<TraitId, OneTraitImpls>,
664}
665
666#[salsa::tracked]
667impl TraitImpls {
668 #[salsa::tracked(returns(ref))]
669 pub fn for_crate(db: &dyn HirDatabase, krate: Crate) -> Arc<Self> {
670 let _p = tracing::info_span!("inherent_impls_in_crate_query", ?krate).entered();
671
672 let crate_def_map = crate_def_map(db, krate);
673 let result = Self::collect_def_map(db, crate_def_map);
674 Arc::new(result)
675 }
676
677 #[salsa::tracked(returns(ref))]
678 pub fn for_block(db: &dyn HirDatabase, block: BlockId) -> Option<Box<Self>> {
679 let _p = tracing::info_span!("inherent_impls_in_block_query").entered();
680
681 let block_def_map = block_def_map(db, block);
682 let result = Self::collect_def_map(db, block_def_map);
683 if result.map.is_empty() { None } else { Some(Box::new(result)) }
684 }
685
686 #[salsa::tracked(returns(ref))]
687 pub fn for_crate_and_deps(db: &dyn HirDatabase, krate: Crate) -> Box<[Arc<Self>]> {
688 krate.transitive_deps(db).iter().map(|&dep| Self::for_crate(db, dep).clone()).collect()
689 }
690}
691
692impl TraitImpls {
693 fn collect_def_map(db: &dyn HirDatabase, def_map: &DefMap) -> Self {
694 let mut map = FxHashMap::default();
695 collect(db, def_map, &mut map);
696 let mut map = map
697 .into_iter()
698 .map(|(trait_id, trait_map)| (trait_id, trait_map.finish()))
699 .collect::<FxHashMap<_, _>>();
700 map.shrink_to_fit();
701 return Self { map };
702
703 fn collect(
704 db: &dyn HirDatabase,
705 def_map: &DefMap,
706 map: &mut FxHashMap<TraitId, OneTraitImplsBuilder>,
707 ) {
708 for (_module_id, module_data) in def_map.modules() {
709 for impl_id in module_data.scope.impls() {
710 if AttrFlags::query(db, impl_id.into())
717 .contains(AttrFlags::RUSTC_RESERVATION_IMPL)
718 {
719 continue;
720 }
721 let trait_ref = match db.impl_trait(impl_id) {
722 Some(tr) => tr.instantiate_identity(),
723 None => continue,
724 };
725 let self_ty = trait_ref.self_ty();
726 let interner = DbInterner::new_no_crate(db);
727 let entry = map.entry(trait_ref.def_id.0).or_default();
728 match simplify_type(interner, self_ty, TreatParams::InstantiateWithInfer) {
729 Some(self_ty) => {
730 entry.non_blanket_impls.entry(self_ty).or_default().push(impl_id)
731 }
732 None => entry.blanket_impls.push(impl_id),
733 }
734 }
735
736 for konst in module_data.scope.unnamed_consts() {
739 let body = db.body(konst.into());
740 for (_, block_def_map) in body.blocks(db) {
741 collect(db, block_def_map, map);
742 }
743 }
744 }
745 }
746 }
747
748 pub fn blanket_impls(&self, for_trait: TraitId) -> &[ImplId] {
749 self.map.get(&for_trait).map(|it| &*it.blanket_impls).unwrap_or_default()
750 }
751
752 pub fn has_impls_for_trait_and_self_ty(
754 &self,
755 trait_: TraitId,
756 self_ty: &SimplifiedType,
757 ) -> bool {
758 self.map.get(&trait_).is_some_and(|trait_impls| {
759 trait_impls.non_blanket_impls.contains_key(self_ty)
760 || !trait_impls.blanket_impls.is_empty()
761 })
762 }
763
764 pub fn for_trait_and_self_ty(&self, trait_: TraitId, self_ty: &SimplifiedType) -> &[ImplId] {
765 self.map
766 .get(&trait_)
767 .and_then(|map| map.non_blanket_impls.get(self_ty))
768 .map(|it| &**it)
769 .unwrap_or_default()
770 }
771
772 pub fn for_trait(&self, trait_: TraitId, mut callback: impl FnMut(&[ImplId])) {
773 if let Some(impls) = self.map.get(&trait_) {
774 callback(&impls.blanket_impls);
775 for impls in impls.non_blanket_impls.values() {
776 callback(impls);
777 }
778 }
779 }
780
781 pub fn for_self_ty(&self, self_ty: &SimplifiedType, mut callback: impl FnMut(&[ImplId])) {
782 for for_trait in self.map.values() {
783 if let Some(for_ty) = for_trait.non_blanket_impls.get(self_ty) {
784 callback(for_ty);
785 }
786 }
787 }
788
789 pub fn for_each_crate_and_block(
790 db: &dyn HirDatabase,
791 krate: Crate,
792 block: Option<BlockId>,
793 for_each: &mut dyn FnMut(&TraitImpls),
794 ) {
795 let blocks = std::iter::successors(block, |block| block.loc(db).module.block(db));
796 blocks.filter_map(|block| Self::for_block(db, block).as_deref()).for_each(&mut *for_each);
797 Self::for_crate_and_deps(db, krate).iter().map(|it| &**it).for_each(for_each);
798 }
799
800 pub fn for_each_crate_and_block_trait_and_type(
802 db: &dyn HirDatabase,
803 krate: Crate,
804 type_block: Option<BlockId>,
805 trait_block: Option<BlockId>,
806 for_each: &mut dyn FnMut(&TraitImpls),
807 ) {
808 let in_self_and_deps = TraitImpls::for_crate_and_deps(db, krate);
809 in_self_and_deps.iter().for_each(|impls| for_each(impls));
810
811 let blocks_iter = |block: Option<BlockId>| {
817 std::iter::successors(block, |block| block.loc(db).module.block(db))
818 };
819 let for_each_block = |current_block: Option<BlockId>, other_block: Option<BlockId>| {
820 blocks_iter(current_block)
821 .take_while(move |&block| {
822 other_block.is_none_or(|other_block| other_block != block)
823 })
824 .filter_map(move |block| TraitImpls::for_block(db, block).as_deref())
825 };
826 if trait_block == type_block {
827 blocks_iter(trait_block)
828 .filter_map(|block| TraitImpls::for_block(db, block).as_deref())
829 .for_each(for_each);
830 } else {
831 for_each_block(trait_block, type_block).for_each(&mut *for_each);
832 for_each_block(type_block, trait_block).for_each(for_each);
833 }
834 }
835}