Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support trait impls in unnamed consts #8390

Merged
merged 2 commits into from
Apr 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion crates/hir_def/src/item_scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand All @@ -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
Expand Down Expand Up @@ -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_)))
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -295,6 +304,7 @@ impl ItemScope {
unresolved,
defs,
impls,
unnamed_consts,
unnamed_trait_imports,
legacy_macros,
} = self;
Expand All @@ -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();
}
Expand Down
34 changes: 21 additions & 13 deletions crates/hir_def/src/nameres/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1163,19 +1163,27 @@ impl ModCollector<'_, '_> {
}
ModItem::Const(id) => {
let it = &self.item_tree[id];

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,
});
let const_id = ConstLoc {
container: module.into(),
id: ItemTreeId::new(self.file_id, id),
}
.intern(self.def_collector.db);

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) => {
Expand Down
54 changes: 35 additions & 19 deletions crates/hir_ty/src/method_resolution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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> {
Expand Down Expand Up @@ -208,6 +221,9 @@ impl InherentImpls {
}
}

// NOTE: We're not collecting inherent impls from unnamed consts here, we intentionally only
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is that? Wouldn't implementation be the same?

// support trait impls there.

Arc::new(Self { map })
}

Expand Down
22 changes: 22 additions & 0 deletions crates/hir_ty/src/tests/method_resolution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
"#,
);
}