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 | 92 |
1 files changed, 83 insertions, 9 deletions
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index 92a17fc3a9..f3a27632bf 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -19,13 +19,13 @@ use stdx::never; use crate::{ autoderef::{self, AutoderefKind}, db::HirDatabase, - from_foreign_def_id, + from_chalk_trait_id, from_foreign_def_id, infer::{unify::InferenceTable, Adjust, Adjustment, AutoBorrow, OverloadedDeref, PointerCast}, primitive::{FloatTy, IntTy, UintTy}, static_lifetime, to_chalk_trait_id, utils::all_super_traits, - AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, InEnvironment, Interner, - Scalar, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, + AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, InEnvironment, + Interner, Scalar, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, }; /// This is used as a key for indexing impls. @@ -266,11 +266,12 @@ impl TraitImpls { #[derive(Debug, Eq, PartialEq)] pub struct InherentImpls { map: FxHashMap<TyFingerprint, Vec<ImplId>>, + invalid_impls: Vec<ImplId>, } impl InherentImpls { pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> { - let mut impls = Self { map: FxHashMap::default() }; + let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() }; let crate_def_map = db.crate_def_map(krate); impls.collect_def_map(db, &crate_def_map); @@ -283,7 +284,7 @@ impl InherentImpls { db: &dyn HirDatabase, block: BlockId, ) -> Option<Arc<Self>> { - let mut impls = Self { map: FxHashMap::default() }; + let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() }; if let Some(block_def_map) = db.block_def_map(block) { impls.collect_def_map(db, &block_def_map); impls.shrink_to_fit(); @@ -306,11 +307,17 @@ impl InherentImpls { } let self_ty = db.impl_self_ty(impl_id); - let fp = TyFingerprint::for_inherent_impl(self_ty.skip_binders()); - if let Some(fp) = fp { - self.map.entry(fp).or_default().push(impl_id); + let self_ty = self_ty.skip_binders(); + + match is_inherent_impl_coherent(db, def_map, &data, self_ty) { + true => { + // `fp` should only be `None` in error cases (either erroneous code or incomplete name resolution) + if let Some(fp) = TyFingerprint::for_inherent_impl(self_ty) { + self.map.entry(fp).or_default().push(impl_id); + } + } + false => self.invalid_impls.push(impl_id), } - // `fp` should only be `None` in error cases (either erroneous code or incomplete name resolution) } // To better support custom derives, collect impls in all unnamed const items. @@ -334,6 +341,10 @@ impl InherentImpls { pub fn all_impls(&self) -> impl Iterator<Item = ImplId> + '_ { self.map.values().flat_map(|v| v.iter().copied()) } + + pub fn invalid_impls(&self) -> &[ImplId] { + &self.invalid_impls + } } pub(crate) fn incoherent_inherent_impl_crates( @@ -775,6 +786,69 @@ fn find_matching_impl( } } +fn is_inherent_impl_coherent( + db: &dyn HirDatabase, + def_map: &DefMap, + impl_data: &ImplData, + self_ty: &Ty, +) -> bool { + let self_ty = self_ty.kind(Interner); + let impl_allowed = match self_ty { + TyKind::Tuple(_, _) + | TyKind::FnDef(_, _) + | TyKind::Array(_, _) + | TyKind::Never + | TyKind::Raw(_, _) + | TyKind::Ref(_, _, _) + | TyKind::Slice(_) + | TyKind::Str + | TyKind::Scalar(_) => def_map.is_rustc_coherence_is_core(), + + &TyKind::Adt(AdtId(adt), _) => adt.module(db.upcast()).krate() == def_map.krate(), + TyKind::Dyn(it) => it.principal().map_or(false, |trait_ref| { + from_chalk_trait_id(trait_ref.trait_id).module(db.upcast()).krate() == def_map.krate() + }), + + _ => true, + }; + impl_allowed || { + let rustc_has_incoherent_inherent_impls = match self_ty { + TyKind::Tuple(_, _) + | TyKind::FnDef(_, _) + | TyKind::Array(_, _) + | TyKind::Never + | TyKind::Raw(_, _) + | TyKind::Ref(_, _, _) + | TyKind::Slice(_) + | TyKind::Str + | TyKind::Scalar(_) => true, + + &TyKind::Adt(AdtId(adt), _) => match adt { + hir_def::AdtId::StructId(it) => { + db.struct_data(it).rustc_has_incoherent_inherent_impls + } + hir_def::AdtId::UnionId(it) => { + db.union_data(it).rustc_has_incoherent_inherent_impls + } + hir_def::AdtId::EnumId(it) => db.enum_data(it).rustc_has_incoherent_inherent_impls, + }, + TyKind::Dyn(it) => it.principal().map_or(false, |trait_ref| { + db.trait_data(from_chalk_trait_id(trait_ref.trait_id)) + .rustc_has_incoherent_inherent_impls + }), + + _ => false, + }; + rustc_has_incoherent_inherent_impls + && !impl_data.items.is_empty() + && impl_data.items.iter().copied().all(|assoc| match assoc { + AssocItemId::FunctionId(it) => db.function_data(it).rustc_allow_incoherent_impl, + AssocItemId::ConstId(it) => db.const_data(it).rustc_allow_incoherent_impl, + AssocItemId::TypeAliasId(it) => db.type_alias_data(it).rustc_allow_incoherent_impl, + }) + } +} + pub fn iterate_path_candidates( ty: &Canonical<Ty>, db: &dyn HirDatabase, |