10729: Fix: Lookup impls in local def maps r=jonas-schievink a=XFFXFF

fixes #10676 

Co-authored-by: zhoufan <1247714429@qq.com>
This commit is contained in:
bors[bot] 2021-11-10 16:47:35 +00:00 committed by GitHub
commit b2bce38bb4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 98 additions and 24 deletions

View File

@ -77,6 +77,9 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
#[salsa::invoke(InherentImpls::inherent_impls_in_crate_query)]
fn inherent_impls_in_crate(&self, krate: CrateId) -> Arc<InherentImpls>;
#[salsa::invoke(InherentImpls::inherent_impls_in_block_query)]
fn inherent_impls_in_block(&self, block: BlockId) -> Option<Arc<InherentImpls>>;
#[salsa::invoke(TraitImpls::trait_impls_in_crate_query)]
fn trait_impls_in_crate(&self, krate: CrateId) -> Arc<TraitImpls>;

View File

@ -261,33 +261,45 @@ impl InherentImpls {
let mut impls = Self { map: FxHashMap::default() };
let crate_def_map = db.crate_def_map(krate);
collect_def_map(db, &crate_def_map, &mut impls);
impls.collect_def_map(db, &crate_def_map);
return Arc::new(impls);
}
fn collect_def_map(db: &dyn HirDatabase, def_map: &DefMap, impls: &mut InherentImpls) {
for (_module_id, module_data) in def_map.modules() {
for impl_id in module_data.scope.impls() {
let data = db.impl_data(impl_id);
if data.target_trait.is_some() {
continue;
}
pub(crate) fn inherent_impls_in_block_query(
db: &dyn HirDatabase,
block: BlockId,
) -> Option<Arc<Self>> {
let mut impls = Self { map: FxHashMap::default() };
if let Some(block_def_map) = db.block_def_map(block) {
impls.collect_def_map(db, &block_def_map);
return Some(Arc::new(impls));
}
return None;
}
let self_ty = db.impl_self_ty(impl_id);
let fp = TyFingerprint::for_inherent_impl(self_ty.skip_binders());
if let Some(fp) = fp {
impls.map.entry(fp).or_default().push(impl_id);
}
// `fp` should only be `None` in error cases (either erroneous code or incomplete name resolution)
fn collect_def_map(&mut self, db: &dyn HirDatabase, def_map: &DefMap) {
for (_module_id, module_data) in def_map.modules() {
for impl_id in module_data.scope.impls() {
let data = db.impl_data(impl_id);
if data.target_trait.is_some() {
continue;
}
// 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.upcast()) {
collect_def_map(db, &block_def_map, impls);
}
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);
}
// `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.
// const _: () = { ... };
for konst in module_data.scope.unnamed_consts() {
let body = db.body(konst.into());
for (_, block_def_map) in body.blocks(db.upcast()) {
self.collect_def_map(db, &block_def_map);
}
}
}
@ -744,11 +756,49 @@ fn iterate_inherent_methods(
None => return ControlFlow::Continue(()),
};
if let Some(module_id) = visible_from_module {
if let Some(block_id) = module_id.containing_block() {
if let Some(impls) = db.inherent_impls_in_block(block_id) {
impls_for_self_ty(
&impls,
self_ty,
db,
env.clone(),
name,
receiver_ty,
visible_from_module,
callback,
)?;
}
}
}
for krate in def_crates {
let impls = db.inherent_impls_in_crate(krate);
impls_for_self_ty(
&impls,
self_ty,
db,
env.clone(),
name,
receiver_ty,
visible_from_module,
callback,
)?;
}
return ControlFlow::Continue(());
let impls_for_self_ty = filter_inherent_impls_for_self_ty(&impls, &self_ty.value);
fn impls_for_self_ty(
impls: &InherentImpls,
self_ty: &Canonical<Ty>,
db: &dyn HirDatabase,
env: Arc<TraitEnvironment>,
name: Option<&Name>,
receiver_ty: Option<&Canonical<Ty>>,
visible_from_module: Option<ModuleId>,
callback: &mut dyn FnMut(&Canonical<Ty>, AssocItemId) -> ControlFlow<()>,
) -> ControlFlow<()> {
let impls_for_self_ty = filter_inherent_impls_for_self_ty(impls, &self_ty.value);
for &impl_def in impls_for_self_ty {
for &item in db.impl_data(impl_def).items.iter() {
if !is_valid_candidate(
@ -776,8 +826,8 @@ fn iterate_inherent_methods(
callback(receiver_ty, item)?;
}
}
ControlFlow::Continue(())
}
ControlFlow::Continue(())
}
/// Returns the self type for the index trait call.

View File

@ -1386,3 +1386,24 @@ fn f<S: Sized, T, U: ?Sized>() {
"#]],
);
}
#[test]
fn local_impl() {
check_types(
r#"
fn main() {
struct SomeStruct(i32);
impl SomeStruct {
fn is_even(&self) -> bool {
self.0 % 2 == 0
}
}
let o = SomeStruct(3);
let is_even = o.is_even();
// ^^^^^^^ bool
}
"#,
);
}