1mod confirm;
10mod probe;
11
12use either::Either;
13use hir_expand::name::Name;
14use salsa::Update;
15use span::Edition;
16use tracing::{debug, instrument};
17
18use base_db::{Crate, salsa::update_fallback_db};
19use hir_def::{
20 AssocItemId, BlockIdLt, BuiltinDeriveImplId, ConstId, FunctionId, GenericParamId, HasModule,
21 ImplId, ItemContainerId, ModuleId, TraitId,
22 attrs::AttrFlags,
23 builtin_derive::BuiltinDeriveImplMethod,
24 expr_store::{Body, path::GenericArgs as HirGenericArgs},
25 hir::{ExprId, generics::GenericParams},
26 lang_item::LangItems,
27 nameres::{DefMap, block_def_map, crate_def_map},
28 resolver::Resolver,
29 signatures::{ConstSignature, FunctionSignature},
30 unstable_features::UnstableFeatures,
31};
32use rustc_hash::{FxHashMap, FxHashSet};
33use rustc_type_ir::{
34 TypeVisitableExt,
35 fast_reject::{TreatParams, simplify_type},
36 inherent::{BoundExistentialPredicates, IntoKind},
37};
38use stdx::impl_from;
39use triomphe::Arc;
40
41use crate::{
42 InferenceDiagnostic, Span, all_super_traits,
43 db::HirDatabase,
44 infer::{InferenceContext, unify::InferenceTable},
45 lower::GenericPredicates,
46 next_solver::{
47 AnyImplId, Binder, ClauseKind, DbInterner, FnSig, GenericArgs, ParamEnv, PredicateKind,
48 SimplifiedType, SolverDefId, TraitRef, Ty, TyKind, TypingMode, Unnormalized,
49 infer::{
50 BoundRegionConversionTime, DbInternerInferExt, InferCtxt, InferOk,
51 select::ImplSource,
52 traits::{Obligation, ObligationCause, PredicateObligations},
53 },
54 obligation_ctxt::ObligationCtxt,
55 util::clauses_as_obligations,
56 },
57 traits::ParamEnvAndCrate,
58};
59
60pub use self::probe::{
61 Candidate, CandidateKind, CandidateStep, CandidateWithPrivate, Mode, Pick, PickKind,
62};
63
64pub struct MethodResolutionContext<'a, 'db> {
65 pub infcx: &'a InferCtxt<'db>,
66 pub resolver: &'a Resolver<'db>,
67 pub param_env: ParamEnv<'db>,
68 pub traits_in_scope: &'a FxHashSet<TraitId>,
69 pub edition: Edition,
70 pub features: &'a UnstableFeatures,
71 pub call_span: Span,
72 pub receiver_span: Span,
73}
74
75#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Update)]
76pub enum CandidateId {
77 FunctionId(FunctionId),
78 ConstId(ConstId),
79}
80impl_from!(FunctionId, ConstId for CandidateId);
81
82impl CandidateId {
83 fn container(self, db: &dyn HirDatabase) -> ItemContainerId {
84 match self {
85 CandidateId::FunctionId(id) => id.loc(db).container,
86 CandidateId::ConstId(id) => id.loc(db).container,
87 }
88 }
89}
90
91#[derive(Clone, Copy, Debug)]
92pub(crate) struct MethodCallee<'db> {
93 pub def_id: FunctionId,
95 pub args: GenericArgs<'db>,
96
97 pub sig: FnSig<'db>,
101}
102
103#[derive(Debug)]
104pub enum MethodError<'db> {
105 NoMatch,
107
108 Ambiguity(Vec<CandidateSource>),
110
111 PrivateMatch(Pick<'db>),
113
114 IllegalSizedBound { candidates: Vec<FunctionId>, needs_mut: bool },
116
117 ErrorReported,
119}
120
121#[derive(Copy, Clone, Debug, Eq, PartialEq)]
124pub enum CandidateSource {
125 Impl(AnyImplId),
126 Trait(TraitId),
127}
128
129impl<'db> InferenceContext<'db> {
130 #[instrument(level = "debug", skip(self))]
134 pub(crate) fn lookup_method_including_private(
135 &mut self,
136 self_ty: Ty<'db>,
137 name: Name,
138 generic_args: Option<&HirGenericArgs>,
139 receiver: ExprId,
140 call_expr: ExprId,
141 ) -> Result<(MethodCallee<'db>, bool), MethodError<'db>> {
142 let (pick, is_visible) = match self.lookup_probe(call_expr, receiver, name, self_ty) {
143 Ok(it) => (it, true),
144 Err(MethodError::PrivateMatch(it)) => {
145 (it, false)
147 }
148 Err(err) => return Err(err),
149 };
150
151 let result = self.confirm_method(&pick, self_ty, call_expr, generic_args);
152 debug!("result = {:?}", result);
153
154 if result.illegal_sized_bound {
155 self.push_diagnostic(InferenceDiagnostic::MethodCallIllegalSizedBound { call_expr });
156 }
157
158 self.write_expr_adj(receiver, result.adjustments);
159 self.write_method_resolution(call_expr, result.callee.def_id, result.callee.args);
160
161 Ok((result.callee, is_visible))
162 }
163
164 #[instrument(level = "debug", skip(self))]
165 pub(crate) fn lookup_probe(
166 &self,
167 call_expr: ExprId,
168 receiver: ExprId,
169 method_name: Name,
170 self_ty: Ty<'db>,
171 ) -> probe::PickResult<'db> {
172 self.with_method_resolution(call_expr.into(), receiver.into(), |ctx| {
173 let pick = ctx.probe_for_name(probe::Mode::MethodCall, method_name, self_ty)?;
174 Ok(pick)
175 })
176 }
177
178 pub(crate) fn with_method_resolution<R>(
179 &self,
180 call_span: Span,
181 receiver_span: Span,
182 f: impl FnOnce(&MethodResolutionContext<'_, 'db>) -> R,
183 ) -> R {
184 let traits_in_scope = self.get_traits_in_scope();
185 let traits_in_scope = match &traits_in_scope {
186 Either::Left(it) => it,
187 Either::Right(it) => *it,
188 };
189 let ctx = MethodResolutionContext {
190 infcx: &self.table.infer_ctxt,
191 resolver: &self.resolver,
192 param_env: self.table.param_env,
193 traits_in_scope,
194 edition: self.edition,
195 features: self.features,
196 call_span,
197 receiver_span,
198 };
199 f(&ctx)
200 }
201}
202
203#[derive(Debug)]
215pub(super) enum TreatNotYetDefinedOpaques {
216 AsInfer,
217 AsRigid,
218}
219
220impl<'db> InferenceTable<'db> {
221 #[instrument(level = "debug", skip(self))]
227 pub(super) fn lookup_method_for_operator(
228 &self,
229 cause: ObligationCause,
230 trait_def_id: TraitId,
231 method_item: FunctionId,
232 self_ty: Ty<'db>,
233 opt_rhs_ty: Option<Ty<'db>>,
234 treat_opaques: TreatNotYetDefinedOpaques,
235 ) -> Option<InferOk<'db, MethodCallee<'db>>> {
236 let args = GenericArgs::for_item(
238 self.interner(),
239 trait_def_id.into(),
240 |param_idx, param_id, _, _| match param_id {
241 GenericParamId::LifetimeParamId(_) | GenericParamId::ConstParamId(_) => {
242 unreachable!("did not expect operator trait to have lifetime/const")
243 }
244 GenericParamId::TypeParamId(_) => {
245 if param_idx == 0 {
246 self_ty.into()
247 } else if let Some(rhs_ty) = opt_rhs_ty {
248 assert_eq!(param_idx, 1, "did not expect >1 param on operator trait");
249 rhs_ty.into()
250 } else {
251 self.var_for_def(param_id, cause.span())
255 }
256 }
257 },
258 );
259
260 let obligation = Obligation::new(
261 self.interner(),
262 cause,
263 self.param_env,
264 TraitRef::new_from_args(self.interner(), trait_def_id.into(), args),
265 );
266
267 let matches_trait = match treat_opaques {
269 TreatNotYetDefinedOpaques::AsInfer => self.infer_ctxt.predicate_may_hold(&obligation),
270 TreatNotYetDefinedOpaques::AsRigid => {
271 self.infer_ctxt.predicate_may_hold_opaque_types_jank(&obligation)
272 }
273 };
274
275 if !matches_trait {
276 debug!("--> Cannot match obligation");
277 return None;
279 }
280
281 let interner = self.interner();
284
285 let def_id = method_item;
286
287 debug!("lookup_in_trait_adjusted: method_item={:?}", method_item);
288 let mut obligations = PredicateObligations::new();
289
290 let fn_sig = self
297 .db
298 .callable_item_signature(method_item.into())
299 .instantiate(interner, args)
300 .skip_norm_wip();
301 let fn_sig = self.infer_ctxt.instantiate_binder_with_fresh_vars(
302 cause.span(),
303 BoundRegionConversionTime::FnCall,
304 fn_sig,
305 );
306
307 let bounds = GenericPredicates::query_all(self.db, method_item.into());
316 let bounds = clauses_as_obligations(
317 bounds.iter_instantiated(interner, args.as_slice()).map(Unnormalized::skip_norm_wip),
318 cause,
319 self.param_env,
320 );
321
322 obligations.extend(bounds);
323
324 debug!(
326 "lookup_method_in_trait: matched method fn_sig={:?} obligation={:?}",
327 fn_sig, obligation
328 );
329 for ty in fn_sig.inputs_and_output {
330 obligations.push(Obligation::new(
331 interner,
332 obligation.cause,
333 self.param_env,
334 Binder::dummy(PredicateKind::Clause(ClauseKind::WellFormed(ty.into()))),
335 ));
336 }
337
338 let callee = MethodCallee { def_id, args, sig: fn_sig };
339 debug!("callee = {:?}", callee);
340
341 Some(InferOk { obligations, value: callee })
342 }
343}
344
345pub fn lookup_impl_const<'db>(
346 infcx: &InferCtxt<'db>,
347 env: ParamEnv<'db>,
348 const_id: ConstId,
349 subs: GenericArgs<'db>,
350) -> (ConstId, GenericArgs<'db>) {
351 let interner = infcx.interner;
352 let db = interner.db;
353
354 let trait_id = match const_id.loc(db).container {
355 ItemContainerId::TraitId(id) => id,
356 _ => return (const_id, subs),
357 };
358 let trait_ref = TraitRef::new_from_args(interner, trait_id.into(), subs);
359
360 let const_signature = ConstSignature::of(db, const_id);
361 let name = match const_signature.name.as_ref() {
362 Some(name) => name,
363 None => return (const_id, subs),
364 };
365
366 lookup_impl_assoc_item_for_trait_ref(infcx, trait_ref, env, name)
367 .and_then(|assoc| {
368 if let (Either::Left(AssocItemId::ConstId(id)), s) = assoc {
369 Some((id, s))
370 } else {
371 None
372 }
373 })
374 .unwrap_or((const_id, subs))
375}
376
377pub fn is_dyn_method<'db>(
380 interner: DbInterner<'db>,
381 _env: ParamEnv<'db>,
382 func: FunctionId,
383 fn_subst: GenericArgs<'db>,
384) -> Option<usize> {
385 let db = interner.db;
386
387 let ItemContainerId::TraitId(trait_id) = func.loc(db).container else {
388 return None;
389 };
390 let trait_params = GenericParams::of(db, trait_id.into()).len();
391 let fn_params = fn_subst.len() - trait_params;
392 let trait_ref = TraitRef::new_from_args(
393 interner,
394 trait_id.into(),
395 GenericArgs::new_from_slice(&fn_subst[..trait_params]),
396 );
397 let self_ty = trait_ref.self_ty();
398 if let TyKind::Dynamic(d, _) = self_ty.kind() {
399 let is_my_trait_in_bounds = d
402 .principal_def_id()
403 .is_some_and(|trait_| all_super_traits(db, trait_.0).contains(&trait_id));
404 if is_my_trait_in_bounds {
405 return Some(fn_params);
406 }
407 }
408 None
409}
410
411pub(crate) fn lookup_impl_method_query<'db>(
415 db: &'db dyn HirDatabase,
416 env: ParamEnvAndCrate<'db>,
417 func: FunctionId,
418 fn_subst: GenericArgs<'db>,
419) -> (Either<FunctionId, (BuiltinDeriveImplId, BuiltinDeriveImplMethod)>, GenericArgs<'db>) {
420 let interner = DbInterner::new_with(db, env.krate);
421 let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);
422
423 let ItemContainerId::TraitId(trait_id) = func.loc(db).container else {
424 return (Either::Left(func), fn_subst);
425 };
426 let trait_params = GenericParams::of(db, trait_id.into()).len();
427 let trait_ref = TraitRef::new_from_args(
428 interner,
429 trait_id.into(),
430 GenericArgs::new_from_slice(&fn_subst[..trait_params]),
431 );
432
433 let name = &FunctionSignature::of(db, func).name;
434 let Some((impl_fn, impl_subst)) =
435 lookup_impl_assoc_item_for_trait_ref(&infcx, trait_ref, env.param_env, name).and_then(
436 |(assoc, impl_args)| {
437 let assoc = match assoc {
438 Either::Left(AssocItemId::FunctionId(id)) => Either::Left(id),
439 Either::Right(it) => Either::Right(it),
440 _ => return None,
441 };
442 Some((assoc, impl_args))
443 },
444 )
445 else {
446 return (Either::Left(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<(Either<AssocItemId, (BuiltinDeriveImplId, BuiltinDeriveImplMethod)>, GenericArgs<'db>)>
464{
465 let (impl_id, impl_subst) = find_matching_impl(infcx, env, trait_ref)?;
466 let impl_id = match impl_id {
467 AnyImplId::ImplId(it) => it,
468 AnyImplId::BuiltinDeriveImplId(impl_) => {
469 return impl_
470 .loc(infcx.interner.db)
471 .trait_
472 .get_method(name.symbol())
473 .map(|method| (Either::Right((impl_, method)), impl_subst));
474 }
475 };
476 let item =
477 impl_id.impl_items(infcx.interner.db).items.iter().find_map(|(n, it)| match *it {
478 AssocItemId::FunctionId(f) => (n == name).then_some(AssocItemId::FunctionId(f)),
479 AssocItemId::ConstId(c) => (n == name).then_some(AssocItemId::ConstId(c)),
480 AssocItemId::TypeAliasId(_) => None,
481 })?;
482 Some((Either::Left(item), impl_subst))
483}
484
485pub(crate) fn find_matching_impl<'db>(
486 infcx: &InferCtxt<'db>,
487 env: ParamEnv<'db>,
488 trait_ref: TraitRef<'db>,
489) -> Option<(AnyImplId, GenericArgs<'db>)> {
490 let trait_ref = infcx.at(&ObligationCause::dummy(), env).deeply_normalize(trait_ref).ok()?;
491
492 let obligation = Obligation::new(infcx.interner, ObligationCause::dummy(), env, trait_ref);
493
494 let selection = infcx.select(&obligation).ok()??;
495
496 let mut ocx = ObligationCtxt::new(infcx);
500 let impl_source = selection.map(|obligation| ocx.register_obligation(obligation));
501
502 let errors = ocx.evaluate_obligations_error_on_ambiguity();
503 if !errors.is_empty() {
504 return None;
505 }
506
507 let impl_source = infcx.resolve_vars_if_possible(impl_source);
508 if impl_source.has_non_region_infer() {
509 return None;
510 }
511
512 match impl_source {
513 ImplSource::UserDefined(impl_source) => Some((impl_source.impl_def_id, impl_source.args)),
514 ImplSource::Param(_) | ImplSource::Builtin(..) => None,
515 }
516}
517
518#[salsa::tracked(returns(ref))]
519fn crates_containing_incoherent_inherent_impls(db: &dyn HirDatabase, krate: Crate) -> Box<[Crate]> {
520 let _p = tracing::info_span!("crates_containing_incoherent_inherent_impls").entered();
521 krate.transitive_deps(db).into_iter().filter(|krate| krate.data(db).origin.is_lang()).collect()
524}
525
526pub fn with_incoherent_inherent_impls<'db>(
527 db: &'db dyn HirDatabase,
528 krate: Crate,
529 self_ty: &SimplifiedType<'db>,
530 mut callback: impl FnMut(&[ImplId]),
531) {
532 let has_incoherent_impls = match self_ty.def() {
533 Some(def_id) => match def_id.try_into() {
534 Ok(def_id) => AttrFlags::query(db, def_id)
535 .contains(AttrFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS),
536 Err(()) => true,
537 },
538 _ => true,
539 };
540 if !has_incoherent_impls {
541 return;
542 }
543 let _p = tracing::info_span!("incoherent_inherent_impls").entered();
544 let crates = crates_containing_incoherent_inherent_impls(db, krate);
545 for &krate in crates {
546 let impls = InherentImpls::for_crate(db, krate);
547 callback(impls.for_self_ty(self_ty));
548 }
549}
550
551pub fn simplified_type_module(db: &dyn HirDatabase, ty: &SimplifiedType<'_>) -> Option<ModuleId> {
552 match ty.def()? {
553 SolverDefId::AdtId(id) => Some(id.module(db)),
554 SolverDefId::TypeAliasId(id) => Some(id.module(db)),
555 SolverDefId::TraitId(id) => Some(id.module(db)),
556 _ => None,
557 }
558}
559
560#[derive(Debug, PartialEq, Eq, Update)]
561pub struct InherentImpls<'db> {
562 #[update(bounds(SolverDefId<'db>: Update), unsafe(with(update_fallback_db::<'db, _>)))]
563 map: FxHashMap<SimplifiedType<'db>, Box<[ImplId]>>,
564}
565
566#[salsa::tracked]
567impl<'db> InherentImpls<'db> {
568 #[salsa::tracked(returns(ref))]
569 pub fn for_crate(db: &'db dyn HirDatabase, krate: Crate) -> InherentImpls<'db> {
570 let _p = tracing::info_span!("inherent_impls_in_crate_query", ?krate).entered();
571
572 let crate_def_map = crate_def_map(db, krate);
573
574 Self::collect_def_map(db, crate_def_map)
575 }
576
577 #[salsa::tracked(returns(ref))]
578 pub fn for_block(
579 db: &'db dyn HirDatabase,
580 block: BlockIdLt<'db>,
581 ) -> Option<Box<InherentImpls<'db>>> {
582 let _p = tracing::info_span!("inherent_impls_in_block_query").entered();
583
584 let block_def_map = block_def_map(db, block);
585 let result = Self::collect_def_map(db, block_def_map);
586 if result.map.is_empty() { None } else { Some(Box::new(result)) }
587 }
588}
589
590impl<'db> InherentImpls<'db> {
591 fn collect_def_map(db: &'db dyn HirDatabase, def_map: &'db DefMap) -> Self {
592 let mut map = FxHashMap::default();
593 collect(db, def_map, &mut map);
594 let mut map = map
595 .into_iter()
596 .map(|(self_ty, impls)| (self_ty, impls.into_boxed_slice()))
597 .collect::<FxHashMap<_, _>>();
598 map.shrink_to_fit();
599 return Self { map };
600
601 fn collect<'db>(
602 db: &'db dyn HirDatabase,
603 def_map: &DefMap,
604 map: &mut FxHashMap<SimplifiedType<'db>, Vec<ImplId>>,
605 ) {
606 for (_module_id, module_data) in def_map.modules() {
607 for impl_id in module_data.scope.inherent_impls() {
608 let interner = DbInterner::new_no_crate(db);
609 let self_ty = db.impl_self_ty(impl_id);
610 let self_ty = self_ty.instantiate_identity().skip_norm_wip();
611 if let Some(self_ty) =
612 simplify_type(interner, self_ty, TreatParams::InstantiateWithInfer)
613 {
614 map.entry(self_ty).or_default().push(impl_id);
615 }
616 }
617
618 for konst in module_data.scope.unnamed_consts() {
621 let body = Body::of(db, konst.into());
622 for (_, block_def_map) in body.blocks(db) {
623 collect(db, block_def_map, map);
624 }
625 }
626 }
627 }
628 }
629
630 pub fn for_self_ty(&self, self_ty: &SimplifiedType<'db>) -> &[ImplId] {
631 self.map.get(self_ty).map(|it| &**it).unwrap_or_default()
632 }
633
634 pub fn for_each_crate_and_block(
635 db: &'db dyn HirDatabase,
636 krate: Crate,
637 block: Option<BlockIdLt<'db>>,
638 for_each: &mut dyn FnMut(&InherentImpls<'db>),
639 ) {
640 let blocks = std::iter::successors(block, |block| block.module(db).block(db));
641 blocks.filter_map(|block| Self::for_block(db, block).as_deref()).for_each(&mut *for_each);
642 for_each(Self::for_crate(db, krate));
643 }
644}
645
646#[derive(Debug, PartialEq, Update)]
647struct OneTraitImpls<'db> {
648 #[update(bounds(SolverDefId<'db>: Update), unsafe(with(update_fallback_db::<'db, _>)))]
649 non_blanket_impls: FxHashMap<SimplifiedType<'db>, (Box<[ImplId]>, Box<[BuiltinDeriveImplId]>)>,
650 blanket_impls: Box<[ImplId]>,
651}
652
653#[derive(Default)]
654struct OneTraitImplsBuilder<'db> {
655 non_blanket_impls: FxHashMap<SimplifiedType<'db>, (Vec<ImplId>, Vec<BuiltinDeriveImplId>)>,
656 blanket_impls: Vec<ImplId>,
657}
658
659impl<'db> OneTraitImplsBuilder<'db> {
660 fn finish(self) -> OneTraitImpls<'db> {
661 let mut non_blanket_impls = self
662 .non_blanket_impls
663 .into_iter()
664 .map(|(self_ty, (impls, builtin_derive_impls))| {
665 (self_ty, (impls.into_boxed_slice(), builtin_derive_impls.into_boxed_slice()))
666 })
667 .collect::<FxHashMap<_, _>>();
668 non_blanket_impls.shrink_to_fit();
669 let blanket_impls = self.blanket_impls.into_boxed_slice();
670 OneTraitImpls { non_blanket_impls, blanket_impls }
671 }
672}
673
674#[derive(Debug, PartialEq, Update)]
675pub struct TraitImpls<'db> {
676 map: FxHashMap<TraitId, OneTraitImpls<'db>>,
677}
678
679#[salsa::tracked]
680impl<'db> TraitImpls<'db> {
681 #[salsa::tracked(returns(ref))]
682 pub fn for_crate(db: &'db dyn HirDatabase, krate: Crate) -> Arc<TraitImpls<'db>> {
683 let _p = tracing::info_span!("inherent_impls_in_crate_query", ?krate).entered();
684
685 let crate_def_map = crate_def_map(db, krate);
686 let result = Self::collect_def_map(db, crate_def_map);
687 Arc::new(result)
688 }
689
690 #[salsa::tracked(returns(as_deref))]
691 pub fn for_block(
692 db: &'db dyn HirDatabase,
693 block: BlockIdLt<'db>,
694 ) -> Option<Box<TraitImpls<'db>>> {
695 let _p = tracing::info_span!("inherent_impls_in_block_query").entered();
696
697 let block_def_map = block_def_map(db, block);
698 let result = Self::collect_def_map(db, block_def_map);
699 if result.map.is_empty() { None } else { Some(Box::new(result)) }
700 }
701
702 #[salsa::tracked(returns(deref))]
703 pub fn for_crate_and_deps(db: &'db dyn HirDatabase, krate: Crate) -> Box<[Arc<Self>]> {
704 krate.transitive_deps(db).iter().map(|&dep| Self::for_crate(db, dep).clone()).collect()
705 }
706}
707
708impl<'db> TraitImpls<'db> {
709 fn collect_def_map(db: &'db dyn HirDatabase, def_map: &DefMap) -> Self {
710 let lang_items = hir_def::lang_item::lang_items(db, def_map.krate());
711 let mut map = FxHashMap::default();
712 collect(db, def_map, lang_items, &mut map);
713 let mut map = map
714 .into_iter()
715 .map(|(trait_id, trait_map)| (trait_id, trait_map.finish()))
716 .collect::<FxHashMap<_, _>>();
717 map.shrink_to_fit();
718 return Self { map };
719
720 fn collect<'db>(
721 db: &'db dyn HirDatabase,
722 def_map: &DefMap,
723 lang_items: &LangItems,
724 map: &mut FxHashMap<TraitId, OneTraitImplsBuilder<'db>>,
725 ) {
726 for (_module_id, module_data) in def_map.modules() {
727 for impl_id in module_data.scope.trait_impls() {
728 let trait_ref = match db.impl_trait(impl_id) {
729 Some(tr) => tr.instantiate_identity().skip_norm_wip(),
730 None => continue,
731 };
732 if AttrFlags::query(db, impl_id.into())
739 .contains(AttrFlags::RUSTC_RESERVATION_IMPL)
740 {
741 continue;
742 }
743
744 let self_ty = trait_ref.self_ty();
745 if self_ty_has_error_constructor(self_ty) {
746 continue;
748 }
749
750 let interner = DbInterner::new_no_crate(db);
751 let entry = map.entry(trait_ref.def_id.0).or_default();
752 match simplify_type(interner, self_ty, TreatParams::InstantiateWithInfer) {
753 Some(self_ty) => {
754 entry.non_blanket_impls.entry(self_ty).or_default().0.push(impl_id)
755 }
756 None => entry.blanket_impls.push(impl_id),
757 }
758 }
759
760 for impl_id in module_data.scope.builtin_derive_impls() {
761 let loc = impl_id.loc(db);
762 let Some(trait_id) = loc.trait_.get_id(lang_items) else { continue };
763 let entry = map.entry(trait_id).or_default();
764 let entry = entry
765 .non_blanket_impls
766 .entry(SimplifiedType::Adt(loc.adt.into()))
767 .or_default();
768 entry.1.push(impl_id);
769 }
770
771 for konst in module_data.scope.unnamed_consts() {
774 let body = Body::of(db, konst.into());
775 for (_, block_def_map) in body.blocks(db) {
776 collect(db, block_def_map, lang_items, map);
777 }
778 }
779 }
780 }
781 }
782
783 pub fn blanket_impls(&self, for_trait: TraitId) -> &[ImplId] {
784 self.map.get(&for_trait).map(|it| &*it.blanket_impls).unwrap_or_default()
785 }
786
787 pub fn has_impls_for_trait_and_self_ty(
789 &self,
790 trait_: TraitId,
791 self_ty: &SimplifiedType<'db>,
792 ) -> bool {
793 self.map.get(&trait_).is_some_and(|trait_impls| {
794 trait_impls.non_blanket_impls.contains_key(self_ty)
795 || !trait_impls.blanket_impls.is_empty()
796 })
797 }
798
799 pub fn for_trait_and_self_ty(
800 &'db self,
801 trait_: TraitId,
802 self_ty: &SimplifiedType<'db>,
803 ) -> (&'db [ImplId], &'db [BuiltinDeriveImplId]) {
804 self.map
805 .get(&trait_)
806 .and_then(|map| map.non_blanket_impls.get(self_ty))
807 .map(|it| (&*it.0, &*it.1))
808 .unwrap_or_default()
809 }
810
811 pub fn for_trait(
812 &self,
813 trait_: TraitId,
814 mut callback: impl FnMut(Either<&[ImplId], &[BuiltinDeriveImplId]>),
815 ) {
816 if let Some(impls) = self.map.get(&trait_) {
817 callback(Either::Left(&impls.blanket_impls));
818 for impls in impls.non_blanket_impls.values() {
819 callback(Either::Left(&impls.0));
820 callback(Either::Right(&impls.1));
821 }
822 }
823 }
824
825 pub fn for_self_ty(
826 &self,
827 self_ty: &SimplifiedType<'db>,
828 mut callback: impl FnMut(Either<&[ImplId], &[BuiltinDeriveImplId]>),
829 ) {
830 for for_trait in self.map.values() {
831 if let Some(for_ty) = for_trait.non_blanket_impls.get(self_ty) {
832 callback(Either::Left(&for_ty.0));
833 callback(Either::Right(&for_ty.1));
834 }
835 }
836 }
837
838 pub fn for_each_crate_and_block(
839 db: &'db dyn HirDatabase,
840 krate: Crate,
841 block: Option<BlockIdLt<'db>>,
842 for_each: &mut dyn FnMut(&TraitImpls<'db>),
843 ) {
844 let blocks = std::iter::successors(block, |block| block.module(db).block(db));
845 blocks.filter_map(|block| Self::for_block(db, block)).for_each(&mut *for_each);
846 Self::for_crate_and_deps(db, krate).iter().map(|it| &**it).for_each(for_each);
847 }
848
849 pub fn for_each_crate_and_block_trait_and_type(
851 db: &'db dyn HirDatabase,
852 krate: Crate,
853 type_block: Option<BlockIdLt<'db>>,
854 trait_block: Option<BlockIdLt<'db>>,
855 for_each: &mut dyn FnMut(&TraitImpls<'db>),
856 ) {
857 let in_self_and_deps = TraitImpls::for_crate_and_deps(db, krate);
858 in_self_and_deps.iter().for_each(|impls| for_each(impls));
859
860 let blocks_iter = |block: Option<BlockIdLt<'db>>| {
866 std::iter::successors(block, |block| block.module(db).block(db))
867 };
868 let for_each_block = |current_block: Option<BlockIdLt<'db>>,
869 other_block: Option<BlockIdLt<'db>>| {
870 blocks_iter(current_block)
871 .take_while(move |&block| {
872 other_block.is_none_or(|other_block| other_block != block)
873 })
874 .filter_map(move |block| TraitImpls::for_block(db, block))
875 };
876 if trait_block == type_block {
877 blocks_iter(trait_block)
878 .filter_map(|block| TraitImpls::for_block(db, block))
879 .for_each(for_each);
880 } else {
881 for_each_block(trait_block, type_block).for_each(&mut *for_each);
882 for_each_block(type_block, trait_block).for_each(for_each);
883 }
884 }
885}
886
887fn self_ty_has_error_constructor<'db>(mut self_ty: Ty<'db>) -> bool {
888 if !self_ty.references_non_lt_error() {
889 return false;
890 }
891
892 loop {
893 self_ty = match self_ty.kind() {
894 TyKind::Error(_) => return true,
895 TyKind::Ref(_, inner, _)
896 | TyKind::RawPtr(inner, _)
897 | TyKind::Array(inner, _)
898 | TyKind::Slice(inner)
899 | TyKind::Pat(inner, _) => inner,
900 TyKind::UnsafeBinder(inner) => inner.skip_binder(),
901 _ => return false,
902 };
903 }
904}