Merge #8390
8390: Support trait impls in unnamed consts r=jonas-schievink a=jonas-schievink Fixes https://github.com/rust-analyzer/rust-analyzer/issues/7550 bors r+ Co-authored-by: Jonas Schievink <jonasschievink@gmail.com>
This commit is contained in:
commit
cf41e1410a
@ -11,7 +11,7 @@ use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use stdx::format_to;
|
||||
|
||||
use crate::{
|
||||
db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ImplId,
|
||||
db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ConstId, ImplId,
|
||||
LocalModuleId, MacroDefId, ModuleDefId, ModuleId, TraitId,
|
||||
};
|
||||
|
||||
@ -37,6 +37,7 @@ pub struct ItemScope {
|
||||
|
||||
defs: Vec<ModuleDefId>,
|
||||
impls: Vec<ImplId>,
|
||||
unnamed_consts: Vec<ConstId>,
|
||||
/// Traits imported via `use Trait as _;`.
|
||||
unnamed_trait_imports: FxHashMap<TraitId, Visibility>,
|
||||
/// Macros visible in current module in legacy textual scope
|
||||
@ -106,6 +107,10 @@ impl ItemScope {
|
||||
.map(|(_, v)| v)
|
||||
}
|
||||
|
||||
pub fn unnamed_consts(&self) -> impl Iterator<Item = ConstId> + '_ {
|
||||
self.unnamed_consts.iter().copied()
|
||||
}
|
||||
|
||||
/// Iterate over all module scoped macros
|
||||
pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
|
||||
self.entries().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_)))
|
||||
@ -156,6 +161,10 @@ impl ItemScope {
|
||||
self.impls.push(imp)
|
||||
}
|
||||
|
||||
pub(crate) fn define_unnamed_const(&mut self, konst: ConstId) {
|
||||
self.unnamed_consts.push(konst);
|
||||
}
|
||||
|
||||
pub(crate) fn define_legacy_macro(&mut self, name: Name, mac: MacroDefId) {
|
||||
self.legacy_macros.insert(name, mac);
|
||||
}
|
||||
@ -295,6 +304,7 @@ impl ItemScope {
|
||||
unresolved,
|
||||
defs,
|
||||
impls,
|
||||
unnamed_consts,
|
||||
unnamed_trait_imports,
|
||||
legacy_macros,
|
||||
} = self;
|
||||
@ -304,6 +314,7 @@ impl ItemScope {
|
||||
unresolved.shrink_to_fit();
|
||||
defs.shrink_to_fit();
|
||||
impls.shrink_to_fit();
|
||||
unnamed_consts.shrink_to_fit();
|
||||
unnamed_trait_imports.shrink_to_fit();
|
||||
legacy_macros.shrink_to_fit();
|
||||
}
|
||||
|
@ -1163,19 +1163,27 @@ impl ModCollector<'_, '_> {
|
||||
}
|
||||
ModItem::Const(id) => {
|
||||
let it = &self.item_tree[id];
|
||||
let const_id = ConstLoc {
|
||||
container: module.into(),
|
||||
id: ItemTreeId::new(self.file_id, id),
|
||||
}
|
||||
.intern(self.def_collector.db);
|
||||
|
||||
if let Some(name) = &it.name {
|
||||
def = Some(DefData {
|
||||
id: ConstLoc {
|
||||
container: module.into(),
|
||||
id: ItemTreeId::new(self.file_id, id),
|
||||
}
|
||||
.intern(self.def_collector.db)
|
||||
.into(),
|
||||
name,
|
||||
visibility: &self.item_tree[it.visibility],
|
||||
has_constructor: false,
|
||||
});
|
||||
match &it.name {
|
||||
Some(name) => {
|
||||
def = Some(DefData {
|
||||
id: const_id.into(),
|
||||
name,
|
||||
visibility: &self.item_tree[it.visibility],
|
||||
has_constructor: false,
|
||||
});
|
||||
}
|
||||
None => {
|
||||
// const _: T = ...;
|
||||
self.def_collector.def_map.modules[self.module_id]
|
||||
.scope
|
||||
.define_unnamed_const(const_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
ModItem::Static(id) => {
|
||||
|
@ -8,8 +8,8 @@ use arrayvec::ArrayVec;
|
||||
use base_db::CrateId;
|
||||
use chalk_ir::{cast::Cast, Mutability, UniverseIndex};
|
||||
use hir_def::{
|
||||
lang_item::LangItemTarget, AssocContainerId, AssocItemId, FunctionId, GenericDefId, HasModule,
|
||||
ImplId, Lookup, ModuleId, TraitId,
|
||||
lang_item::LangItemTarget, nameres::DefMap, AssocContainerId, AssocItemId, FunctionId,
|
||||
GenericDefId, HasModule, ImplId, Lookup, ModuleId, TraitId,
|
||||
};
|
||||
use hir_expand::name::Name;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
@ -100,25 +100,38 @@ impl TraitImpls {
|
||||
let mut impls = Self { map: FxHashMap::default() };
|
||||
|
||||
let crate_def_map = db.crate_def_map(krate);
|
||||
for (_module_id, module_data) in crate_def_map.modules() {
|
||||
for impl_id in module_data.scope.impls() {
|
||||
let target_trait = match db.impl_trait(impl_id) {
|
||||
Some(tr) => tr.skip_binders().hir_trait_id(),
|
||||
None => continue,
|
||||
};
|
||||
let self_ty = db.impl_self_ty(impl_id);
|
||||
let self_ty_fp = TyFingerprint::for_impl(self_ty.skip_binders());
|
||||
impls
|
||||
.map
|
||||
.entry(target_trait)
|
||||
.or_default()
|
||||
.entry(self_ty_fp)
|
||||
.or_default()
|
||||
.push(impl_id);
|
||||
collect_def_map(db, &crate_def_map, &mut impls);
|
||||
|
||||
return Arc::new(impls);
|
||||
|
||||
fn collect_def_map(db: &dyn HirDatabase, def_map: &DefMap, impls: &mut TraitImpls) {
|
||||
for (_module_id, module_data) in def_map.modules() {
|
||||
for impl_id in module_data.scope.impls() {
|
||||
let target_trait = match db.impl_trait(impl_id) {
|
||||
Some(tr) => tr.skip_binders().hir_trait_id(),
|
||||
None => continue,
|
||||
};
|
||||
let self_ty = db.impl_self_ty(impl_id);
|
||||
let self_ty_fp = TyFingerprint::for_impl(self_ty.skip_binders());
|
||||
impls
|
||||
.map
|
||||
.entry(target_trait)
|
||||
.or_default()
|
||||
.entry(self_ty_fp)
|
||||
.or_default()
|
||||
.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.upcast()) {
|
||||
collect_def_map(db, &block_def_map, impls);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Arc::new(impls)
|
||||
}
|
||||
|
||||
pub(crate) fn trait_impls_in_deps_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
|
||||
@ -208,6 +221,9 @@ impl InherentImpls {
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: We're not collecting inherent impls from unnamed consts here, we intentionally only
|
||||
// support trait impls there.
|
||||
|
||||
Arc::new(Self { map })
|
||||
}
|
||||
|
||||
|
@ -1292,3 +1292,25 @@ mod b {
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn impl_in_unnamed_const() {
|
||||
check_types(
|
||||
r#"
|
||||
struct S;
|
||||
|
||||
trait Tr {
|
||||
fn method(&self) -> u16;
|
||||
}
|
||||
|
||||
const _: () = {
|
||||
impl Tr for S {}
|
||||
};
|
||||
|
||||
fn f() {
|
||||
S.method();
|
||||
//^^^^^^^^^^ u16
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user