hir_ty/
method_resolution.rs

1//! This module is concerned with finding methods that a given type provides.
2//! For details about how this works in rustc, see the method lookup page in the
3//! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html)
4//! and the corresponding code mostly in rustc_hir_analysis/check/method/probe.rs.
5
6mod 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    /// Impl method ID, for inherent methods, or trait method ID, otherwise.
104    pub def_id: FunctionId,
105    pub args: GenericArgs<'db>,
106
107    /// Instantiated method signature, i.e., it has been
108    /// instantiated, normalized, and has had late-bound
109    /// lifetimes replaced with inference variables.
110    pub sig: FnSig<'db>,
111}
112
113#[derive(Debug)]
114pub enum MethodError<'db> {
115    /// Did not find an applicable method.
116    NoMatch,
117
118    /// Multiple methods might apply.
119    Ambiguity(Vec<CandidateSource>),
120
121    /// Found an applicable method, but it is not visible.
122    PrivateMatch(Pick<'db>),
123
124    /// Found a `Self: Sized` bound where `Self` is a trait object.
125    IllegalSizedBound { candidates: Vec<FunctionId>, needs_mut: bool },
126
127    /// Error has already been emitted, no need to emit another one.
128    ErrorReported,
129}
130
131// A pared down enum describing just the places from which a method
132// candidate can arise. Used for error reporting only.
133#[derive(Copy, Clone, Debug, Eq, PartialEq)]
134pub enum CandidateSource {
135    Impl(ImplId),
136    Trait(TraitId),
137}
138
139impl<'a, 'db> InferenceContext<'a, 'db> {
140    /// Performs method lookup. If lookup is successful, it will return the callee
141    /// and store an appropriate adjustment for the self-expr. In some cases it may
142    /// report an error (e.g., invoking the `drop` method).
143    #[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                // FIXME: Report error.
156                (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            // FIXME: Report an error.
166        }
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/// Used by [FnCtxt::lookup_method_for_operator] with `-Znext-solver`.
208///
209/// With `AsRigid` we error on `impl Opaque: NotInItemBounds` while
210/// `AsInfer` just treats it as ambiguous and succeeds. This is necessary
211/// as we want [FnCtxt::check_expr_call] to treat not-yet-defined opaque
212/// types as rigid to support `impl Deref<Target = impl FnOnce()>` and
213/// `Box<impl FnOnce()>`.
214///
215/// We only want to treat opaque types as rigid if we need to eagerly choose
216/// between multiple candidates. We otherwise treat them as ordinary inference
217/// variable to avoid rejecting otherwise correct code.
218#[derive(Debug)]
219#[expect(dead_code)]
220pub(super) enum TreatNotYetDefinedOpaques {
221    AsInfer,
222    AsRigid,
223}
224
225impl<'db> InferenceTable<'db> {
226    /// `lookup_method_in_trait` is used for overloaded operators.
227    /// It does a very narrow slice of what the normal probe/confirm path does.
228    /// In particular, it doesn't really do any probing: it simply constructs
229    /// an obligation for a particular trait with the given self type and checks
230    /// whether that trait is implemented.
231    #[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        // Construct a trait-reference `self_ty : Trait<input_tys>`
242        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                        // FIXME: We should stop passing `None` for the failure case
257                        // when probing for call exprs. I.e. `opt_rhs_ty` should always
258                        // be set when it needs to be.
259                        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        // Now we want to know if this can be matched
273        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            // Cannot be matched, no such method resolution is possible.
283            return None;
284        }
285
286        // Trait must have a method named `m_name` and it should not have
287        // type parameters or early-bound regions.
288        let interner = self.interner();
289        // We use `Ident::with_dummy_span` since no built-in operator methods have
290        // any macro-specific hygiene, so the span's context doesn't really matter.
291        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        // Instantiate late-bound regions and instantiate the trait
303        // parameters into the method type to get the actual method type.
304        //
305        // N.B., instantiate late-bound regions before normalizing the
306        // function signature so that normalization does not need to deal
307        // with bound regions.
308        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        // Register obligations for the parameters. This will include the
315        // `Self` parameter, which in turn has a bound of the main trait,
316        // so this also effectively registers `obligation` as well. (We
317        // used to register `obligation` explicitly, but that resulted in
318        // double error messages being reported.)
319        //
320        // Note that as the method comes from a trait, it should not have
321        // any late-bound regions appearing in its bounds.
322        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        // Also add an obligation for the method type being well-formed.
332        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
380/// Checks if the self parameter of `Trait` method is the `dyn Trait` and we should
381/// call the method using the vtable.
382pub 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        // rustc doesn't accept `impl Foo<2> for dyn Foo<5>`, so if the trait id is equal, no matter
403        // what the generics are, we are sure that the method is come from the vtable.
404        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
414/// Looks up the impl method that actually runs for the trait method `func`.
415///
416/// Returns `func` if it's not a method defined in a trait or the lookup failed.
417pub(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    // Currently, we use a fulfillment context to completely resolve
486    // all nested obligations. This is because they can inform the
487    // inference of the impl's type parameters.
488    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    // We assume that only sysroot crates contain `#[rustc_has_incoherent_inherent_impls]`
511    // impls, since this is an internal feature and only std uses it.
512    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                // To better support custom derives, collect impls in all unnamed const items.
609                // const _: () = { ... };
610                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                    // Reservation impls should be ignored during trait resolution, so we never need
711                    // them during type analysis. See rust-lang/rust#64631 for details.
712                    //
713                    // FIXME: Reservation impls should be considered during coherence checks. If we are
714                    // (ever) to implement coherence checks, this filtering should be done by the trait
715                    // solver.
716                    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                // To better support custom derives, collect impls in all unnamed const items.
737                // const _: () = { ... };
738                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    /// Queries whether `self_ty` has potentially applicable implementations of `trait_`.
753    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    /// Like [`Self::for_each_crate_and_block()`], but takes in account two blocks, one for a trait and one for a self type.
801    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        // We must not provide duplicate impls to the solver. Therefore we work with the following strategy:
812        // start from each block, and walk ancestors until you meet the other block. If they never meet,
813        // that means there can't be duplicate impls; if they meet, we stop the search of the deeper block.
814        // This breaks when they are equal (both will stop immediately), therefore we handle this case
815        // specifically.
816        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}