Skip to content

Commit

Permalink
fix: Fix attributes on generic parameters colliding in item tree
Browse files Browse the repository at this point in the history
  • Loading branch information
Veykril committed Apr 27, 2024
1 parent 2668912 commit bfe59bb
Show file tree
Hide file tree
Showing 11 changed files with 250 additions and 212 deletions.
14 changes: 6 additions & 8 deletions crates/hir-def/src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -698,24 +698,22 @@ impl<'a> AssocItemCollector<'a> {
match item {
AssocItem::Function(id) => {
let item = &item_tree[id];

let def =
FunctionLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db);
self.items.push((item.name.clone(), def.into()));
}
AssocItem::Const(id) => {
let item = &item_tree[id];
let Some(name) = item.name.clone() else { return };
let def = ConstLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db);
self.items.push((name, def.into()));
}
AssocItem::TypeAlias(id) => {
let item = &item_tree[id];

let def =
TypeAliasLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db);
self.items.push((item.name.clone(), def.into()));
}
AssocItem::Const(id) => {
let item = &item_tree[id];
let Some(name) = item.name.clone() else { return };
let def = ConstLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db);
self.items.push((name, def.into()));
}
AssocItem::MacroCall(call) => {
let file_id = self.expander.current_file_id();
let MacroCall { ast_id, expand_to, ctxt, ref path } = item_tree[call];
Expand Down
2 changes: 2 additions & 0 deletions crates/hir-def/src/find_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1177,6 +1177,8 @@ pub mod fmt {
//- /main.rs crate:main deps:alloc,std
#![no_std]
extern crate alloc;
$0
//- /std.rs crate:std deps:alloc
Expand Down
98 changes: 55 additions & 43 deletions crates/hir-def/src/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use triomphe::Arc;
use crate::{
db::DefDatabase,
expander::Expander,
item_tree::{GenericsItemTreeNode, ItemTree},
item_tree::{AttrOwner, FileItemTreeId, GenericModItem, GenericsItemTreeNode, ItemTree},
lower::LowerCtx,
nameres::{DefMap, MacroSubNs},
type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef},
Expand Down Expand Up @@ -456,56 +456,67 @@ impl GenericParams {
let cfg_options = &cfg_options[krate].cfg_options;

// Returns the generic parameters that are enabled under the current `#[cfg]` options
let enabled_params = |params: &Interned<GenericParams>, item_tree: &ItemTree| {
let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options);

// In the common case, no parameters will by disabled by `#[cfg]` attributes.
// Therefore, make a first pass to check if all parameters are enabled and, if so,
// clone the `Interned<GenericParams>` instead of recreating an identical copy.
let all_type_or_consts_enabled =
params.type_or_consts.iter().all(|(idx, _)| enabled(idx.into()));
let all_lifetimes_enabled = params.lifetimes.iter().all(|(idx, _)| enabled(idx.into()));

if all_type_or_consts_enabled && all_lifetimes_enabled {
params.clone()
} else {
Interned::new(GenericParams {
type_or_consts: all_type_or_consts_enabled
.then(|| params.type_or_consts.clone())
.unwrap_or_else(|| {
params
.type_or_consts
.iter()
.filter(|(idx, _)| enabled((*idx).into()))
.map(|(_, param)| param.clone())
.collect()
}),
lifetimes: all_lifetimes_enabled
.then(|| params.lifetimes.clone())
.unwrap_or_else(|| {
params
.lifetimes
.iter()
.filter(|(idx, _)| enabled((*idx).into()))
.map(|(_, param)| param.clone())
.collect()
}),
where_predicates: params.where_predicates.clone(),
})
}
};
let enabled_params =
|params: &Interned<GenericParams>, item_tree: &ItemTree, parent: GenericModItem| {
let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options);
let attr_owner_ct = |param| AttrOwner::TypeOrConstParamData(parent, param);
let attr_owner_lt = |param| AttrOwner::LifetimeParamData(parent, param);

// In the common case, no parameters will by disabled by `#[cfg]` attributes.
// Therefore, make a first pass to check if all parameters are enabled and, if so,
// clone the `Interned<GenericParams>` instead of recreating an identical copy.
let all_type_or_consts_enabled =
params.type_or_consts.iter().all(|(idx, _)| enabled(attr_owner_ct(idx)));
let all_lifetimes_enabled =
params.lifetimes.iter().all(|(idx, _)| enabled(attr_owner_lt(idx)));

if all_type_or_consts_enabled && all_lifetimes_enabled {
params.clone()
} else {
Interned::new(GenericParams {
type_or_consts: all_type_or_consts_enabled
.then(|| params.type_or_consts.clone())
.unwrap_or_else(|| {
params
.type_or_consts
.iter()
.filter(|&(idx, _)| enabled(attr_owner_ct(idx)))
.map(|(_, param)| param.clone())
.collect()
}),
lifetimes: all_lifetimes_enabled
.then(|| params.lifetimes.clone())
.unwrap_or_else(|| {
params
.lifetimes
.iter()
.filter(|&(idx, _)| enabled(attr_owner_lt(idx)))
.map(|(_, param)| param.clone())
.collect()
}),
where_predicates: params.where_predicates.clone(),
})
}
};
fn id_to_generics<Id: GenericsItemTreeNode>(
db: &dyn DefDatabase,
id: impl for<'db> Lookup<
Database<'db> = dyn DefDatabase + 'db,
Data = impl ItemTreeLoc<Id = Id>,
>,
enabled_params: impl Fn(&Interned<GenericParams>, &ItemTree) -> Interned<GenericParams>,
) -> Interned<GenericParams> {
enabled_params: impl Fn(
&Interned<GenericParams>,
&ItemTree,
GenericModItem,
) -> Interned<GenericParams>,
) -> Interned<GenericParams>
where
FileItemTreeId<Id>: Into<GenericModItem>,
{
let id = id.lookup(db).item_tree_id();
let tree = id.item_tree(db);
let item = &tree[id.value];
enabled_params(item.generic_params(), &tree)
enabled_params(item.generic_params(), &tree, id.value.into())
}

match def {
Expand All @@ -514,7 +525,8 @@ impl GenericParams {
let tree = loc.id.item_tree(db);
let item = &tree[loc.id.value];

let enabled_params = enabled_params(&item.explicit_generic_params, &tree);
let enabled_params =
enabled_params(&item.explicit_generic_params, &tree, loc.id.value.into());

let module = loc.container.module(db);
let func_data = db.function_data(id);
Expand Down
47 changes: 41 additions & 6 deletions crates/hir-def/src/item_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ use triomphe::Arc;
use crate::{
attr::Attrs,
db::DefDatabase,
generics::{GenericParams, LifetimeParamData, TypeOrConstParamData},
generics::GenericParams,
path::{GenericArgs, ImportAlias, ModPath, Path, PathKind},
type_ref::{Mutability, TraitRef, TypeBound, TypeRef},
visibility::{RawVisibility, VisibilityExplicitness},
BlockId, Lookup,
BlockId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup,
};

#[derive(Copy, Clone, Eq, PartialEq)]
Expand Down Expand Up @@ -293,8 +293,8 @@ pub enum AttrOwner {
Variant(FileItemTreeId<Variant>),
Field(Idx<Field>),
Param(Idx<Param>),
TypeOrConstParamData(Idx<TypeOrConstParamData>),
LifetimeParamData(Idx<LifetimeParamData>),
TypeOrConstParamData(GenericModItem, LocalTypeOrConstParamId),
LifetimeParamData(GenericModItem, LocalLifetimeParamId),
}

macro_rules! from_attrs {
Expand All @@ -314,8 +314,6 @@ from_attrs!(
Variant(FileItemTreeId<Variant>),
Field(Idx<Field>),
Param(Idx<Param>),
TypeOrConstParamData(Idx<TypeOrConstParamData>),
LifetimeParamData(Idx<LifetimeParamData>),
);

/// Trait implemented by all nodes in the item tree.
Expand Down Expand Up @@ -465,12 +463,49 @@ macro_rules! mod_items {
)+
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum GenericModItem {
$(
$(
#[cfg_attr(FALSE, $generic_params)]
$typ(FileItemTreeId<$typ>),
)?
)+
}

impl From<GenericModItem> for ModItem {
fn from(id: GenericModItem) -> ModItem {
match id {
$(
$(
#[cfg_attr(FALSE, $generic_params)]
GenericModItem::$typ(id) => ModItem::$typ(id),
)?
)+
}
}
}

impl From<GenericModItem> for AttrOwner {
fn from(t: GenericModItem) -> AttrOwner {
AttrOwner::ModItem(t.into())
}
}

$(
impl From<FileItemTreeId<$typ>> for ModItem {
fn from(id: FileItemTreeId<$typ>) -> ModItem {
ModItem::$typ(id)
}
}
$(
#[cfg_attr(FALSE, $generic_params)]
impl From<FileItemTreeId<$typ>> for GenericModItem {
fn from(id: FileItemTreeId<$typ>) -> GenericModItem {
GenericModItem::$typ(id)
}
}
)?
)+

$(
Expand Down
Loading

0 comments on commit bfe59bb

Please sign in to comment.