Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/method_resolution.rs')
| -rw-r--r-- | crates/hir-ty/src/method_resolution.rs | 136 |
1 files changed, 90 insertions, 46 deletions
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index c370330a87..e4681b464f 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -13,11 +13,13 @@ use tracing::{debug, instrument}; use base_db::Crate; use hir_def::{ - AssocItemId, BlockId, ConstId, FunctionId, GenericParamId, HasModule, ImplId, ItemContainerId, - ModuleId, TraitId, + AssocItemId, BlockId, BuiltinDeriveImplId, ConstId, FunctionId, GenericParamId, HasModule, + ImplId, ItemContainerId, ModuleId, TraitId, attrs::AttrFlags, + builtin_derive::BuiltinDeriveImplMethod, expr_store::path::GenericArgs as HirGenericArgs, hir::ExprId, + lang_item::LangItems, nameres::{DefMap, block_def_map, crate_def_map}, resolver::Resolver, }; @@ -37,7 +39,7 @@ use crate::{ infer::{InferenceContext, unify::InferenceTable}, lower::GenericPredicates, next_solver::{ - Binder, ClauseKind, DbInterner, FnSig, GenericArgs, ParamEnv, PredicateKind, + AnyImplId, Binder, ClauseKind, DbInterner, FnSig, GenericArgs, ParamEnv, PredicateKind, SimplifiedType, SolverDefId, TraitRef, Ty, TyKind, TypingMode, infer::{ BoundRegionConversionTime, DbInternerInferExt, InferCtxt, InferOk, @@ -132,7 +134,7 @@ pub enum MethodError<'db> { // candidate can arise. Used for error reporting only. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum CandidateSource { - Impl(ImplId), + Impl(AnyImplId), Trait(TraitId), } @@ -371,9 +373,13 @@ pub fn lookup_impl_const<'db>( }; lookup_impl_assoc_item_for_trait_ref(infcx, trait_ref, env, name) - .and_then( - |assoc| if let (AssocItemId::ConstId(id), s) = assoc { Some((id, s)) } else { None }, - ) + .and_then(|assoc| { + if let (Either::Left(AssocItemId::ConstId(id)), s) = assoc { + Some((id, s)) + } else { + None + } + }) .unwrap_or((const_id, subs)) } @@ -419,12 +425,12 @@ pub(crate) fn lookup_impl_method_query<'db>( env: ParamEnvAndCrate<'db>, func: FunctionId, fn_subst: GenericArgs<'db>, -) -> (FunctionId, GenericArgs<'db>) { +) -> (Either<FunctionId, (BuiltinDeriveImplId, BuiltinDeriveImplMethod)>, GenericArgs<'db>) { let interner = DbInterner::new_with(db, env.krate); let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); let ItemContainerId::TraitId(trait_id) = func.loc(db).container else { - return (func, fn_subst); + return (Either::Left(func), fn_subst); }; let trait_params = db.generic_params(trait_id.into()).len(); let trait_ref = TraitRef::new_from_args( @@ -434,16 +440,19 @@ pub(crate) fn lookup_impl_method_query<'db>( ); let name = &db.function_signature(func).name; - let Some((impl_fn, impl_subst)) = lookup_impl_assoc_item_for_trait_ref( - &infcx, - trait_ref, - env.param_env, - name, - ) - .and_then(|assoc| { - if let (AssocItemId::FunctionId(id), subst) = assoc { Some((id, subst)) } else { None } - }) else { - return (func, fn_subst); + let Some((impl_fn, impl_subst)) = + lookup_impl_assoc_item_for_trait_ref(&infcx, trait_ref, env.param_env, name).and_then( + |(assoc, impl_args)| { + let assoc = match assoc { + Either::Left(AssocItemId::FunctionId(id)) => Either::Left(id), + Either::Right(it) => Either::Right(it), + _ => return None, + }; + Some((assoc, impl_args)) + }, + ) + else { + return (Either::Left(func), fn_subst); }; ( @@ -460,22 +469,33 @@ fn lookup_impl_assoc_item_for_trait_ref<'db>( trait_ref: TraitRef<'db>, env: ParamEnv<'db>, name: &Name, -) -> Option<(AssocItemId, GenericArgs<'db>)> { +) -> Option<(Either<AssocItemId, (BuiltinDeriveImplId, BuiltinDeriveImplMethod)>, GenericArgs<'db>)> +{ let (impl_id, impl_subst) = find_matching_impl(infcx, env, trait_ref)?; + let impl_id = match impl_id { + AnyImplId::ImplId(it) => it, + AnyImplId::BuiltinDeriveImplId(impl_) => { + return impl_ + .loc(infcx.interner.db) + .trait_ + .get_method(name.symbol()) + .map(|method| (Either::Right((impl_, method)), impl_subst)); + } + }; let item = impl_id.impl_items(infcx.interner.db).items.iter().find_map(|(n, it)| match *it { AssocItemId::FunctionId(f) => (n == name).then_some(AssocItemId::FunctionId(f)), AssocItemId::ConstId(c) => (n == name).then_some(AssocItemId::ConstId(c)), AssocItemId::TypeAliasId(_) => None, })?; - Some((item, impl_subst)) + Some((Either::Left(item), impl_subst)) } pub(crate) fn find_matching_impl<'db>( infcx: &InferCtxt<'db>, env: ParamEnv<'db>, trait_ref: TraitRef<'db>, -) -> Option<(ImplId, GenericArgs<'db>)> { +) -> Option<(AnyImplId, GenericArgs<'db>)> { let trait_ref = infcx.at(&ObligationCause::dummy(), env).deeply_normalize(trait_ref).ok()?; let obligation = Obligation::new(infcx.interner, ObligationCause::dummy(), env, trait_ref); @@ -589,12 +609,7 @@ impl InherentImpls { map: &mut FxHashMap<SimplifiedType, Vec<ImplId>>, ) { for (_module_id, module_data) in def_map.modules() { - for impl_id in module_data.scope.impls() { - let data = db.impl_signature(impl_id); - if data.target_trait.is_some() { - continue; - } - + for impl_id in module_data.scope.inherent_impls() { let interner = DbInterner::new_no_crate(db); let self_ty = db.impl_self_ty(impl_id); let self_ty = self_ty.instantiate_identity(); @@ -635,13 +650,13 @@ impl InherentImpls { #[derive(Debug, PartialEq)] struct OneTraitImpls { - non_blanket_impls: FxHashMap<SimplifiedType, Box<[ImplId]>>, + non_blanket_impls: FxHashMap<SimplifiedType, (Box<[ImplId]>, Box<[BuiltinDeriveImplId]>)>, blanket_impls: Box<[ImplId]>, } #[derive(Default)] struct OneTraitImplsBuilder { - non_blanket_impls: FxHashMap<SimplifiedType, Vec<ImplId>>, + non_blanket_impls: FxHashMap<SimplifiedType, (Vec<ImplId>, Vec<BuiltinDeriveImplId>)>, blanket_impls: Vec<ImplId>, } @@ -650,7 +665,9 @@ impl OneTraitImplsBuilder { let mut non_blanket_impls = self .non_blanket_impls .into_iter() - .map(|(self_ty, impls)| (self_ty, impls.into_boxed_slice())) + .map(|(self_ty, (impls, builtin_derive_impls))| { + (self_ty, (impls.into_boxed_slice(), builtin_derive_impls.into_boxed_slice())) + }) .collect::<FxHashMap<_, _>>(); non_blanket_impls.shrink_to_fit(); let blanket_impls = self.blanket_impls.into_boxed_slice(); @@ -691,8 +708,9 @@ impl TraitImpls { impl TraitImpls { fn collect_def_map(db: &dyn HirDatabase, def_map: &DefMap) -> Self { + let lang_items = hir_def::lang_item::lang_items(db, def_map.krate()); let mut map = FxHashMap::default(); - collect(db, def_map, &mut map); + collect(db, def_map, lang_items, &mut map); let mut map = map .into_iter() .map(|(trait_id, trait_map)| (trait_id, trait_map.finish())) @@ -703,10 +721,15 @@ impl TraitImpls { fn collect( db: &dyn HirDatabase, def_map: &DefMap, + lang_items: &LangItems, map: &mut FxHashMap<TraitId, OneTraitImplsBuilder>, ) { for (_module_id, module_data) in def_map.modules() { - for impl_id in module_data.scope.impls() { + for impl_id in module_data.scope.trait_impls() { + let trait_ref = match db.impl_trait(impl_id) { + Some(tr) => tr.instantiate_identity(), + None => continue, + }; // Reservation impls should be ignored during trait resolution, so we never need // them during type analysis. See rust-lang/rust#64631 for details. // @@ -718,27 +741,34 @@ impl TraitImpls { { continue; } - let trait_ref = match db.impl_trait(impl_id) { - Some(tr) => tr.instantiate_identity(), - None => continue, - }; let self_ty = trait_ref.self_ty(); let interner = DbInterner::new_no_crate(db); let entry = map.entry(trait_ref.def_id.0).or_default(); match simplify_type(interner, self_ty, TreatParams::InstantiateWithInfer) { Some(self_ty) => { - entry.non_blanket_impls.entry(self_ty).or_default().push(impl_id) + entry.non_blanket_impls.entry(self_ty).or_default().0.push(impl_id) } None => entry.blanket_impls.push(impl_id), } } + for impl_id in module_data.scope.builtin_derive_impls() { + let loc = impl_id.loc(db); + let Some(trait_id) = loc.trait_.get_id(lang_items) else { continue }; + let entry = map.entry(trait_id).or_default(); + let entry = entry + .non_blanket_impls + .entry(SimplifiedType::Adt(loc.adt.into())) + .or_default(); + entry.1.push(impl_id); + } + // To better support custom derives, collect impls in all unnamed const items. // const _: () = { ... }; for konst in module_data.scope.unnamed_consts() { let body = db.body(konst.into()); for (_, block_def_map) in body.blocks(db) { - collect(db, block_def_map, map); + collect(db, block_def_map, lang_items, map); } } } @@ -761,27 +791,41 @@ impl TraitImpls { }) } - pub fn for_trait_and_self_ty(&self, trait_: TraitId, self_ty: &SimplifiedType) -> &[ImplId] { + pub fn for_trait_and_self_ty( + &self, + trait_: TraitId, + self_ty: &SimplifiedType, + ) -> (&[ImplId], &[BuiltinDeriveImplId]) { self.map .get(&trait_) .and_then(|map| map.non_blanket_impls.get(self_ty)) - .map(|it| &**it) + .map(|it| (&*it.0, &*it.1)) .unwrap_or_default() } - pub fn for_trait(&self, trait_: TraitId, mut callback: impl FnMut(&[ImplId])) { + pub fn for_trait( + &self, + trait_: TraitId, + mut callback: impl FnMut(Either<&[ImplId], &[BuiltinDeriveImplId]>), + ) { if let Some(impls) = self.map.get(&trait_) { - callback(&impls.blanket_impls); + callback(Either::Left(&impls.blanket_impls)); for impls in impls.non_blanket_impls.values() { - callback(impls); + callback(Either::Left(&impls.0)); + callback(Either::Right(&impls.1)); } } } - pub fn for_self_ty(&self, self_ty: &SimplifiedType, mut callback: impl FnMut(&[ImplId])) { + pub fn for_self_ty( + &self, + self_ty: &SimplifiedType, + mut callback: impl FnMut(Either<&[ImplId], &[BuiltinDeriveImplId]>), + ) { for for_trait in self.map.values() { if let Some(for_ty) = for_trait.non_blanket_impls.get(self_ty) { - callback(for_ty); + callback(Either::Left(&for_ty.0)); + callback(Either::Right(&for_ty.1)); } } } |