Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/item_tree.rs')
-rw-r--r--crates/hir-def/src/item_tree.rs898
1 files changed, 279 insertions, 619 deletions
diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs
index 1b97eb72b6..c633339857 100644
--- a/crates/hir-def/src/item_tree.rs
+++ b/crates/hir-def/src/item_tree.rs
@@ -29,7 +29,6 @@
//!
//! In general, any item in the `ItemTree` stores its `AstId`, which allows mapping it back to its
//! surface syntax.
-#![allow(unexpected_cfgs)]
mod lower;
mod pretty;
@@ -38,38 +37,40 @@ mod tests;
use std::{
fmt::{self, Debug},
- hash::{Hash, Hasher},
- ops::{Index, Range},
+ hash::Hash,
+ ops::Index,
sync::OnceLock,
};
use ast::{AstNode, StructKind};
use base_db::Crate;
use hir_expand::{
- ExpandTo, HirFileId, InFile,
+ ExpandTo, HirFileId,
attrs::RawAttrs,
mod_path::{ModPath, PathKind},
name::Name,
};
-use intern::{Interned, Symbol};
-use la_arena::{Arena, Idx, RawIdx};
+use intern::Interned;
+use la_arena::{Idx, RawIdx};
use rustc_hash::FxHashMap;
-use smallvec::SmallVec;
use span::{AstIdNode, Edition, FileAstId, SyntaxContext};
use stdx::never;
use syntax::{SyntaxKind, ast, match_ast};
+use thin_vec::ThinVec;
use triomphe::Arc;
use crate::{BlockId, Lookup, attr::Attrs, db::DefDatabase};
+pub(crate) use crate::item_tree::lower::{lower_use_tree, visibility_from_ast};
+
#[derive(Copy, Clone, Eq, PartialEq)]
-pub struct RawVisibilityId(u32);
+pub(crate) struct RawVisibilityId(u32);
impl RawVisibilityId {
- pub const PUB: Self = RawVisibilityId(u32::MAX);
- pub const PRIV_IMPLICIT: Self = RawVisibilityId(u32::MAX - 1);
- pub const PRIV_EXPLICIT: Self = RawVisibilityId(u32::MAX - 2);
- pub const PUB_CRATE: Self = RawVisibilityId(u32::MAX - 3);
+ const PUB: Self = RawVisibilityId(u32::MAX);
+ const PRIV_IMPLICIT: Self = RawVisibilityId(u32::MAX - 1);
+ const PRIV_EXPLICIT: Self = RawVisibilityId(u32::MAX - 2);
+ const PUB_CRATE: Self = RawVisibilityId(u32::MAX - 3);
}
impl fmt::Debug for RawVisibilityId {
@@ -85,112 +86,136 @@ impl fmt::Debug for RawVisibilityId {
}
}
-/// The item tree of a source file.
-#[derive(Debug, Default, Eq, PartialEq)]
-pub struct ItemTree {
- top_level: SmallVec<[ModItem; 1]>,
- attrs: FxHashMap<AttrOwner, RawAttrs>,
-
- data: Option<Box<ItemTreeData>>,
-}
-
-impl ItemTree {
- pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
- let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered();
- static EMPTY: OnceLock<Arc<ItemTree>> = OnceLock::new();
-
- let ctx = lower::Ctx::new(db, file_id);
- let syntax = db.parse_or_expand(file_id);
- let mut top_attrs = None;
- let mut item_tree = match_ast! {
- match syntax {
- ast::SourceFile(file) => {
- top_attrs = Some(RawAttrs::new(db, &file, ctx.span_map()));
- ctx.lower_module_items(&file)
- },
- ast::MacroItems(items) => {
- ctx.lower_module_items(&items)
- },
- ast::MacroStmts(stmts) => {
- // The produced statements can include items, which should be added as top-level
- // items.
- ctx.lower_macro_stmts(stmts)
- },
- _ => {
- if never!(syntax.kind() == SyntaxKind::ERROR, "{:?} from {:?} {}", file_id, syntax, syntax) {
- return Default::default();
- }
- panic!("cannot create item tree for file {file_id:?} from {syntax:?} {syntax}");
- },
- }
- };
+#[salsa_macros::tracked(returns(deref))]
+pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
+ let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered();
+ static EMPTY: OnceLock<Arc<ItemTree>> = OnceLock::new();
- if let Some(attrs) = top_attrs {
- item_tree.attrs.insert(AttrOwner::TopLevel, attrs);
+ let ctx = lower::Ctx::new(db, file_id);
+ let syntax = db.parse_or_expand(file_id);
+ let mut item_tree = match_ast! {
+ match syntax {
+ ast::SourceFile(file) => {
+ let top_attrs = RawAttrs::new(db, &file, ctx.span_map());
+ let mut item_tree = ctx.lower_module_items(&file);
+ item_tree.top_attrs = top_attrs;
+ item_tree
+ },
+ ast::MacroItems(items) => {
+ ctx.lower_module_items(&items)
+ },
+ ast::MacroStmts(stmts) => {
+ // The produced statements can include items, which should be added as top-level
+ // items.
+ ctx.lower_macro_stmts(stmts)
+ },
+ _ => {
+ if never!(syntax.kind() == SyntaxKind::ERROR, "{:?} from {:?} {}", file_id, syntax, syntax) {
+ return Default::default();
+ }
+ panic!("cannot create item tree for file {file_id:?} from {syntax:?} {syntax}");
+ },
}
- if item_tree.data.is_none() && item_tree.top_level.is_empty() && item_tree.attrs.is_empty()
- {
- EMPTY
- .get_or_init(|| {
- Arc::new(ItemTree {
- top_level: SmallVec::new_const(),
- attrs: FxHashMap::default(),
- data: None,
- })
+ };
+ let ItemTree { top_level, top_attrs, attrs, vis, big_data, small_data } = &item_tree;
+ if small_data.is_empty()
+ && big_data.is_empty()
+ && top_level.is_empty()
+ && attrs.is_empty()
+ && top_attrs.is_empty()
+ && vis.arena.is_empty()
+ {
+ EMPTY
+ .get_or_init(|| {
+ Arc::new(ItemTree {
+ top_level: Box::new([]),
+ attrs: FxHashMap::default(),
+ small_data: FxHashMap::default(),
+ big_data: FxHashMap::default(),
+ top_attrs: RawAttrs::EMPTY,
+ vis: ItemVisibilities { arena: ThinVec::new() },
})
- .clone()
- } else {
- item_tree.shrink_to_fit();
- Arc::new(item_tree)
- }
- }
-
- pub(crate) fn block_item_tree_query(db: &dyn DefDatabase, block: BlockId) -> Arc<ItemTree> {
- let _p = tracing::info_span!("block_item_tree_query", ?block).entered();
- static EMPTY: OnceLock<Arc<ItemTree>> = OnceLock::new();
-
- let loc = block.lookup(db);
- let block = loc.ast_id.to_node(db);
-
- let ctx = lower::Ctx::new(db, loc.ast_id.file_id);
- let mut item_tree = ctx.lower_block(&block);
- if item_tree.data.is_none() && item_tree.top_level.is_empty() && item_tree.attrs.is_empty()
- {
- EMPTY
- .get_or_init(|| {
- Arc::new(ItemTree {
- top_level: SmallVec::new_const(),
- attrs: FxHashMap::default(),
- data: None,
- })
+ })
+ .clone()
+ } else {
+ item_tree.shrink_to_fit();
+ Arc::new(item_tree)
+ }
+}
+
+#[salsa_macros::tracked(returns(deref))]
+pub(crate) fn block_item_tree_query(db: &dyn DefDatabase, block: BlockId) -> Arc<ItemTree> {
+ let _p = tracing::info_span!("block_item_tree_query", ?block).entered();
+ static EMPTY: OnceLock<Arc<ItemTree>> = OnceLock::new();
+
+ let loc = block.lookup(db);
+ let block = loc.ast_id.to_node(db);
+
+ let ctx = lower::Ctx::new(db, loc.ast_id.file_id);
+ let mut item_tree = ctx.lower_block(&block);
+ let ItemTree { top_level, top_attrs, attrs, vis, big_data, small_data } = &item_tree;
+ if small_data.is_empty()
+ && big_data.is_empty()
+ && top_level.is_empty()
+ && attrs.is_empty()
+ && top_attrs.is_empty()
+ && vis.arena.is_empty()
+ {
+ EMPTY
+ .get_or_init(|| {
+ Arc::new(ItemTree {
+ top_level: Box::new([]),
+ attrs: FxHashMap::default(),
+ small_data: FxHashMap::default(),
+ big_data: FxHashMap::default(),
+ top_attrs: RawAttrs::EMPTY,
+ vis: ItemVisibilities { arena: ThinVec::new() },
})
- .clone()
- } else {
- item_tree.shrink_to_fit();
- Arc::new(item_tree)
- }
+ })
+ .clone()
+ } else {
+ item_tree.shrink_to_fit();
+ Arc::new(item_tree)
}
+}
+/// The item tree of a source file.
+#[derive(Debug, Default, Eq, PartialEq)]
+pub struct ItemTree {
+ top_level: Box<[ModItemId]>,
+ top_attrs: RawAttrs,
+ attrs: FxHashMap<FileAstId<ast::Item>, RawAttrs>,
+ vis: ItemVisibilities,
+ big_data: FxHashMap<FileAstId<ast::Item>, BigModItem>,
+ small_data: FxHashMap<FileAstId<ast::Item>, SmallModItem>,
+}
+impl ItemTree {
/// Returns an iterator over all items located at the top level of the `HirFileId` this
/// `ItemTree` was created from.
- pub fn top_level_items(&self) -> &[ModItem] {
+ pub(crate) fn top_level_items(&self) -> &[ModItemId] {
&self.top_level
}
/// Returns the inner attributes of the source file.
- pub fn top_level_attrs(&self, db: &dyn DefDatabase, krate: Crate) -> Attrs {
- Attrs::expand_cfg_attr(
- db,
- krate,
- self.attrs.get(&AttrOwner::TopLevel).unwrap_or(&RawAttrs::EMPTY).clone(),
- )
+ pub(crate) fn top_level_raw_attrs(&self) -> &RawAttrs {
+ &self.top_attrs
+ }
+
+ /// Returns the inner attributes of the source file.
+ pub(crate) fn top_level_attrs(&self, db: &dyn DefDatabase, krate: Crate) -> Attrs {
+ Attrs::expand_cfg_attr(db, krate, self.top_attrs.clone())
}
- pub(crate) fn raw_attrs(&self, of: AttrOwner) -> &RawAttrs {
+ pub(crate) fn raw_attrs(&self, of: FileAstId<ast::Item>) -> &RawAttrs {
self.attrs.get(&of).unwrap_or(&RawAttrs::EMPTY)
}
- pub(crate) fn attrs(&self, db: &dyn DefDatabase, krate: Crate, of: AttrOwner) -> Attrs {
+ pub(crate) fn attrs(
+ &self,
+ db: &dyn DefDatabase,
+ krate: Crate,
+ of: FileAstId<ast::Item>,
+ ) -> Attrs {
Attrs::expand_cfg_attr(db, krate, self.raw_attrs(of).clone())
}
@@ -198,131 +223,79 @@ impl ItemTree {
///
/// For more detail, see [`ItemTreeDataStats`].
pub fn item_tree_stats(&self) -> ItemTreeDataStats {
- match self.data {
- Some(ref data) => ItemTreeDataStats {
- traits: data.traits.len(),
- impls: data.impls.len(),
- mods: data.mods.len(),
- macro_calls: data.macro_calls.len(),
- macro_rules: data.macro_rules.len(),
- },
- None => ItemTreeDataStats::default(),
+ let mut traits = 0;
+ let mut impls = 0;
+ let mut mods = 0;
+ let mut macro_calls = 0;
+ let mut macro_rules = 0;
+ for item in self.small_data.values() {
+ match item {
+ SmallModItem::Trait(_) => traits += 1,
+ SmallModItem::Impl(_) => impls += 1,
+ SmallModItem::MacroRules(_) => macro_rules += 1,
+ SmallModItem::MacroCall(_) => macro_calls += 1,
+ _ => {}
+ }
+ }
+ for item in self.big_data.values() {
+ match item {
+ BigModItem::Mod(_) => mods += 1,
+ _ => {}
+ }
}
+ ItemTreeDataStats { traits, impls, mods, macro_calls, macro_rules }
}
pub fn pretty_print(&self, db: &dyn DefDatabase, edition: Edition) -> String {
pretty::print_item_tree(db, self, edition)
}
- fn data(&self) -> &ItemTreeData {
- self.data.as_ref().expect("attempted to access data of empty ItemTree")
- }
-
- fn data_mut(&mut self) -> &mut ItemTreeData {
- self.data.get_or_insert_with(Box::default)
- }
-
fn shrink_to_fit(&mut self) {
- let ItemTree { top_level, attrs, data } = self;
- top_level.shrink_to_fit();
+ let ItemTree { top_level: _, attrs, big_data, small_data, vis: _, top_attrs: _ } = self;
attrs.shrink_to_fit();
- if let Some(data) = data {
- let ItemTreeData {
- uses,
- extern_crates,
- extern_blocks,
- functions,
- structs,
- unions,
- enums,
- variants,
- consts,
- statics,
- traits,
- trait_aliases,
- impls,
- type_aliases,
- mods,
- macro_calls,
- macro_rules,
- macro_defs,
- vis,
- } = &mut **data;
-
- uses.shrink_to_fit();
- extern_crates.shrink_to_fit();
- extern_blocks.shrink_to_fit();
- functions.shrink_to_fit();
- structs.shrink_to_fit();
- unions.shrink_to_fit();
- enums.shrink_to_fit();
- variants.shrink_to_fit();
- consts.shrink_to_fit();
- statics.shrink_to_fit();
- traits.shrink_to_fit();
- trait_aliases.shrink_to_fit();
- impls.shrink_to_fit();
- type_aliases.shrink_to_fit();
- mods.shrink_to_fit();
- macro_calls.shrink_to_fit();
- macro_rules.shrink_to_fit();
- macro_defs.shrink_to_fit();
-
- vis.arena.shrink_to_fit();
- }
+ big_data.shrink_to_fit();
+ small_data.shrink_to_fit();
}
}
#[derive(Default, Debug, Eq, PartialEq)]
struct ItemVisibilities {
- arena: Arena<RawVisibility>,
+ arena: ThinVec<RawVisibility>,
}
-impl ItemVisibilities {
- fn alloc(&mut self, vis: RawVisibility) -> RawVisibilityId {
- match &vis {
- RawVisibility::Public => RawVisibilityId::PUB,
- RawVisibility::Module(path, explicitiy) if path.segments().is_empty() => {
- match (path.kind, explicitiy) {
- (PathKind::SELF, VisibilityExplicitness::Explicit) => {
- RawVisibilityId::PRIV_EXPLICIT
- }
- (PathKind::SELF, VisibilityExplicitness::Implicit) => {
- RawVisibilityId::PRIV_IMPLICIT
- }
- (PathKind::Crate, _) => RawVisibilityId::PUB_CRATE,
- _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()),
- }
- }
- _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()),
- }
- }
+#[derive(Debug, Clone, Eq, PartialEq)]
+enum SmallModItem {
+ Const(Const),
+ Enum(Enum),
+ ExternBlock(ExternBlock),
+ Function(Function),
+ Impl(Impl),
+ Macro2(Macro2),
+ MacroCall(MacroCall),
+ MacroRules(MacroRules),
+ Static(Static),
+ Struct(Struct),
+ Trait(Trait),
+ TraitAlias(TraitAlias),
+ TypeAlias(TypeAlias),
+ Union(Union),
}
-#[derive(Default, Debug, Eq, PartialEq)]
-struct ItemTreeData {
- uses: Arena<Use>,
- extern_crates: Arena<ExternCrate>,
- extern_blocks: Arena<ExternBlock>,
- functions: Arena<Function>,
- structs: Arena<Struct>,
- unions: Arena<Union>,
- enums: Arena<Enum>,
- variants: Arena<Variant>,
- consts: Arena<Const>,
- statics: Arena<Static>,
- traits: Arena<Trait>,
- trait_aliases: Arena<TraitAlias>,
- impls: Arena<Impl>,
- type_aliases: Arena<TypeAlias>,
- mods: Arena<Mod>,
- macro_calls: Arena<MacroCall>,
- macro_rules: Arena<MacroRules>,
- macro_defs: Arena<Macro2>,
-
- vis: ItemVisibilities,
+#[derive(Debug, Clone, Eq, PartialEq)]
+enum BigModItem {
+ ExternCrate(ExternCrate),
+ Mod(Mod),
+ Use(Use),
}
+// `ModItem` is stored a bunch in `ItemTree`'s so we pay the max for each item. It should stay as
+// small as possible which is why we split them in two, most common ones are 3 usize but some rarer
+// ones are 5.
+#[cfg(target_pointer_width = "64")]
+const _: [(); std::mem::size_of::<BigModItem>()] = [(); std::mem::size_of::<[usize; 5]>()];
+#[cfg(target_pointer_width = "64")]
+const _: [(); std::mem::size_of::<SmallModItem>()] = [(); std::mem::size_of::<[usize; 3]>()];
+
#[derive(Default, Debug, Eq, PartialEq)]
pub struct ItemTreeDataStats {
pub traits: usize,
@@ -332,100 +305,13 @@ pub struct ItemTreeDataStats {
pub macro_rules: usize,
}
-#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
-pub enum AttrOwner {
- /// Attributes on an item.
- ModItem(ModItem),
- /// Inner attributes of the source file.
- TopLevel,
-
- Variant(FileItemTreeId<Variant>),
- // while not relevant to early name resolution, fields can contain visibility
- Field(FieldParent, ItemTreeFieldId),
-}
-
-impl AttrOwner {
- pub fn make_field_indexed(parent: FieldParent, idx: usize) -> Self {
- AttrOwner::Field(parent, ItemTreeFieldId::from_raw(RawIdx::from_u32(idx as u32)))
- }
-}
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-pub enum FieldParent {
- Struct(FileItemTreeId<Struct>),
- Union(FileItemTreeId<Union>),
- EnumVariant(FileItemTreeId<Variant>),
-}
-
-pub type ItemTreeFieldId = Idx<Field>;
-
-macro_rules! from_attrs {
- ( $( $var:ident($t:ty) ),+ $(,)? ) => {
- $(
- impl From<$t> for AttrOwner {
- fn from(t: $t) -> AttrOwner {
- AttrOwner::$var(t)
- }
- }
- )+
- };
-}
-
-from_attrs!(ModItem(ModItem), Variant(FileItemTreeId<Variant>));
-
/// Trait implemented by all nodes in the item tree.
-pub trait ItemTreeNode: Clone {
+pub(crate) trait ItemTreeNode: Clone {
type Source: AstIdNode;
-
- fn ast_id(&self) -> FileAstId<Self::Source>;
-
- /// Looks up an instance of `Self` in an item tree.
- fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self;
- fn attr_owner(id: FileItemTreeId<Self>) -> AttrOwner;
-}
-
-pub struct FileItemTreeId<N>(Idx<N>);
-
-impl<N> FileItemTreeId<N> {
- pub fn range_iter(range: Range<Self>) -> impl Iterator<Item = Self> + Clone {
- (range.start.index().into_raw().into_u32()..range.end.index().into_raw().into_u32())
- .map(RawIdx::from_u32)
- .map(Idx::from_raw)
- .map(Self)
- }
-}
-
-impl<N> FileItemTreeId<N> {
- pub fn index(&self) -> Idx<N> {
- self.0
- }
-}
-
-impl<N> Clone for FileItemTreeId<N> {
- fn clone(&self) -> Self {
- *self
- }
-}
-impl<N> Copy for FileItemTreeId<N> {}
-
-impl<N> PartialEq for FileItemTreeId<N> {
- fn eq(&self, other: &FileItemTreeId<N>) -> bool {
- self.0 == other.0
- }
-}
-impl<N> Eq for FileItemTreeId<N> {}
-
-impl<N> Hash for FileItemTreeId<N> {
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.0.hash(state)
- }
}
-impl<N> fmt::Debug for FileItemTreeId<N> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.0.fmt(f)
- }
-}
+#[allow(type_alias_bounds)]
+pub(crate) type ItemTreeAstId<T: ItemTreeNode> = FileAstId<T::Source>;
/// Identifies a particular [`ItemTree`].
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
@@ -435,100 +321,48 @@ pub struct TreeId {
}
impl TreeId {
- pub fn new(file: HirFileId, block: Option<BlockId>) -> Self {
+ pub(crate) fn new(file: HirFileId, block: Option<BlockId>) -> Self {
Self { file, block }
}
- pub fn item_tree(&self, db: &dyn DefDatabase) -> Arc<ItemTree> {
+ pub(crate) fn item_tree<'db>(&self, db: &'db dyn DefDatabase) -> &'db ItemTree {
match self.block {
- Some(block) => db.block_item_tree(block),
- None => db.file_item_tree(self.file),
+ Some(block) => block_item_tree_query(db, block),
+ None => file_item_tree_query(db, self.file),
}
}
+ #[inline]
pub fn file_id(self) -> HirFileId {
self.file
}
- pub fn is_block(self) -> bool {
+ pub(crate) fn is_block(self) -> bool {
self.block.is_some()
}
}
-#[derive(Debug)]
-pub struct ItemTreeId<N> {
- tree: TreeId,
- pub value: FileItemTreeId<N>,
-}
-
-impl<N> ItemTreeId<N> {
- pub fn new(tree: TreeId, idx: FileItemTreeId<N>) -> Self {
- Self { tree, value: idx }
- }
-
- pub fn file_id(self) -> HirFileId {
- self.tree.file
- }
-
- pub fn tree_id(self) -> TreeId {
- self.tree
- }
-
- pub fn item_tree(self, db: &dyn DefDatabase) -> Arc<ItemTree> {
- self.tree.item_tree(db)
- }
-
- pub fn resolved<R>(self, db: &dyn DefDatabase, cb: impl FnOnce(&N) -> R) -> R
- where
- ItemTree: Index<FileItemTreeId<N>, Output = N>,
- {
- cb(&self.tree.item_tree(db)[self.value])
- }
-}
-
-impl<N> Copy for ItemTreeId<N> {}
-impl<N> Clone for ItemTreeId<N> {
- fn clone(&self) -> Self {
- *self
- }
-}
-
-impl<N> PartialEq for ItemTreeId<N> {
- fn eq(&self, other: &Self) -> bool {
- self.tree == other.tree && self.value == other.value
- }
-}
-
-impl<N> Eq for ItemTreeId<N> {}
-
-impl<N> Hash for ItemTreeId<N> {
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.tree.hash(state);
- self.value.hash(state);
- }
-}
-
macro_rules! mod_items {
- ( $( $typ:ident in $fld:ident -> $ast:ty ),+ $(,)? ) => {
+ ($mod_item:ident -> $( $typ:ident in $fld:ident -> $ast:ty ),+ $(,)? ) => {
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
- pub enum ModItem {
+ pub(crate) enum $mod_item {
$(
- $typ(FileItemTreeId<$typ>),
+ $typ(FileAstId<$ast>),
)+
}
- impl ModItem {
- pub fn ast_id(&self, tree: &ItemTree) -> FileAstId<ast::Item> {
+ impl $mod_item {
+ pub(crate) fn ast_id(self) -> FileAstId<ast::Item> {
match self {
- $(ModItem::$typ(it) => tree[it.index()].ast_id().upcast()),+
+ $($mod_item::$typ(it) => it.upcast()),+
}
}
}
$(
- impl From<FileItemTreeId<$typ>> for ModItem {
- fn from(id: FileItemTreeId<$typ>) -> ModItem {
- ModItem::$typ(id)
+ impl From<FileAstId<$ast>> for $mod_item {
+ fn from(id: FileAstId<$ast>) -> $mod_item {
+ ModItemId::$typ(id)
}
}
)+
@@ -536,25 +370,19 @@ macro_rules! mod_items {
$(
impl ItemTreeNode for $typ {
type Source = $ast;
-
- fn ast_id(&self) -> FileAstId<Self::Source> {
- self.ast_id
- }
-
- fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self {
- &tree.data().$fld[index]
- }
-
- fn attr_owner(id: FileItemTreeId<Self>) -> AttrOwner {
- AttrOwner::ModItem(ModItem::$typ(id))
- }
}
- impl Index<Idx<$typ>> for ItemTree {
+ impl Index<FileAstId<$ast>> for ItemTree {
type Output = $typ;
- fn index(&self, index: Idx<$typ>) -> &Self::Output {
- &self.data().$fld[index]
+ #[allow(unused_imports)]
+ fn index(&self, index: FileAstId<$ast>) -> &Self::Output {
+ use BigModItem::*;
+ use SmallModItem::*;
+ match &self.$fld[&index.upcast()] {
+ $typ(item) => item,
+ _ => panic!("expected item of type `{}` at index `{:?}`", stringify!($typ), index),
+ }
}
}
)+
@@ -562,94 +390,59 @@ macro_rules! mod_items {
}
mod_items! {
- Use in uses -> ast::Use,
- ExternCrate in extern_crates -> ast::ExternCrate,
- ExternBlock in extern_blocks -> ast::ExternBlock,
- Function in functions -> ast::Fn,
- Struct in structs -> ast::Struct,
- Union in unions -> ast::Union,
- Enum in enums -> ast::Enum,
- Const in consts -> ast::Const,
- Static in statics -> ast::Static,
- Trait in traits -> ast::Trait,
- TraitAlias in trait_aliases -> ast::TraitAlias,
- Impl in impls -> ast::Impl,
- TypeAlias in type_aliases -> ast::TypeAlias,
- Mod in mods -> ast::Module,
- MacroCall in macro_calls -> ast::MacroCall,
- MacroRules in macro_rules -> ast::MacroRules,
- Macro2 in macro_defs -> ast::MacroDef,
+ModItemId ->
+ Const in small_data -> ast::Const,
+ Enum in small_data -> ast::Enum,
+ ExternBlock in small_data -> ast::ExternBlock,
+ ExternCrate in big_data -> ast::ExternCrate,
+ Function in small_data -> ast::Fn,
+ Impl in small_data -> ast::Impl,
+ Macro2 in small_data -> ast::MacroDef,
+ MacroCall in small_data -> ast::MacroCall,
+ MacroRules in small_data -> ast::MacroRules,
+ Mod in big_data -> ast::Module,
+ Static in small_data -> ast::Static,
+ Struct in small_data -> ast::Struct,
+ Trait in small_data -> ast::Trait,
+ TraitAlias in small_data -> ast::TraitAlias,
+ TypeAlias in small_data -> ast::TypeAlias,
+ Union in small_data -> ast::Union,
+ Use in big_data -> ast::Use,
}
impl Index<RawVisibilityId> for ItemTree {
type Output = RawVisibility;
fn index(&self, index: RawVisibilityId) -> &Self::Output {
static VIS_PUB: RawVisibility = RawVisibility::Public;
- static VIS_PRIV_IMPLICIT: OnceLock<RawVisibility> = OnceLock::new();
- static VIS_PRIV_EXPLICIT: OnceLock<RawVisibility> = OnceLock::new();
- static VIS_PUB_CRATE: OnceLock<RawVisibility> = OnceLock::new();
+ static VIS_PRIV_IMPLICIT: RawVisibility =
+ RawVisibility::PubSelf(VisibilityExplicitness::Implicit);
+ static VIS_PRIV_EXPLICIT: RawVisibility =
+ RawVisibility::PubSelf(VisibilityExplicitness::Explicit);
+ static VIS_PUB_CRATE: RawVisibility = RawVisibility::PubCrate;
match index {
- RawVisibilityId::PRIV_IMPLICIT => VIS_PRIV_IMPLICIT.get_or_init(|| {
- RawVisibility::Module(
- Interned::new(ModPath::from_kind(PathKind::SELF)),
- VisibilityExplicitness::Implicit,
- )
- }),
- RawVisibilityId::PRIV_EXPLICIT => VIS_PRIV_EXPLICIT.get_or_init(|| {
- RawVisibility::Module(
- Interned::new(ModPath::from_kind(PathKind::SELF)),
- VisibilityExplicitness::Explicit,
- )
- }),
+ RawVisibilityId::PRIV_IMPLICIT => &VIS_PRIV_IMPLICIT,
+ RawVisibilityId::PRIV_EXPLICIT => &VIS_PRIV_EXPLICIT,
RawVisibilityId::PUB => &VIS_PUB,
- RawVisibilityId::PUB_CRATE => VIS_PUB_CRATE.get_or_init(|| {
- RawVisibility::Module(
- Interned::new(ModPath::from_kind(PathKind::Crate)),
- VisibilityExplicitness::Explicit,
- )
- }),
- _ => &self.data().vis.arena[Idx::from_raw(index.0.into())],
+ RawVisibilityId::PUB_CRATE => &VIS_PUB_CRATE,
+ _ => &self.vis.arena[index.0 as usize],
}
}
}
-impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree {
- type Output = N;
- fn index(&self, id: FileItemTreeId<N>) -> &N {
- N::lookup(self, id.index())
- }
-}
-
-impl ItemTreeNode for Variant {
- type Source = ast::Variant;
-
- fn ast_id(&self) -> FileAstId<Self::Source> {
- self.ast_id
- }
-
- fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self {
- &tree.data().variants[index]
- }
-
- fn attr_owner(id: FileItemTreeId<Self>) -> AttrOwner {
- AttrOwner::Variant(id)
- }
-}
-
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Use {
- pub visibility: RawVisibilityId,
- pub ast_id: FileAstId<ast::Use>,
- pub use_tree: UseTree,
+ pub(crate) visibility: RawVisibilityId,
+ pub(crate) use_tree: UseTree,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct UseTree {
- pub index: Idx<ast::UseTree>,
kind: UseTreeKind,
}
+// FIXME: Would be nice to encode `None` into this
+// We could just use a `Name` where `_` well means `_` ..
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ImportAlias {
/// Unnamed alias, as in `use Foo as _;`
@@ -703,55 +496,37 @@ pub enum UseTreeKind {
pub struct ExternCrate {
pub name: Name,
pub alias: Option<ImportAlias>,
- pub visibility: RawVisibilityId,
- pub ast_id: FileAstId<ast::ExternCrate>,
+ pub(crate) visibility: RawVisibilityId,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct ExternBlock {
- pub abi: Option<Symbol>,
- pub ast_id: FileAstId<ast::ExternBlock>,
- pub children: Box<[ModItem]>,
+ pub(crate) children: Box<[ModItemId]>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Function {
pub name: Name,
- pub visibility: RawVisibilityId,
- pub ast_id: FileAstId<ast::Fn>,
+ pub(crate) visibility: RawVisibilityId,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Struct {
pub name: Name,
- pub visibility: RawVisibilityId,
- pub fields: Box<[Field]>,
+ pub(crate) visibility: RawVisibilityId,
pub shape: FieldsShape,
- pub ast_id: FileAstId<ast::Struct>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Union {
pub name: Name,
- pub visibility: RawVisibilityId,
- pub fields: Box<[Field]>,
- pub ast_id: FileAstId<ast::Union>,
+ pub(crate) visibility: RawVisibilityId,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Enum {
pub name: Name,
- pub visibility: RawVisibilityId,
- pub variants: Range<FileItemTreeId<Variant>>,
- pub ast_id: FileAstId<ast::Enum>,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct Variant {
- pub name: Name,
- pub fields: Box<[Field]>,
- pub shape: FieldsShape,
- pub ast_id: FileAstId<ast::Variant>,
+ pub(crate) visibility: RawVisibilityId,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -762,11 +537,15 @@ pub enum FieldsShape {
}
/// Visibility of an item, not yet resolved.
-#[derive(Debug, Clone, PartialEq, Eq)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum RawVisibility {
/// `pub(in module)`, `pub(crate)` or `pub(super)`. Also private, which is
/// equivalent to `pub(self)`.
Module(Interned<ModPath>, VisibilityExplicitness),
+ /// `pub(self)`.
+ PubSelf(VisibilityExplicitness),
+ /// `pub(crate)`.
+ PubCrate,
/// `pub`.
Public,
}
@@ -785,71 +564,51 @@ impl VisibilityExplicitness {
}
}
-// FIXME: Remove this from item tree?
-/// A single field of an enum variant or struct
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct Field {
- pub name: Name,
- pub visibility: RawVisibilityId,
- // FIXME: Not an item tree property
- pub is_unsafe: bool,
-}
-
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Const {
/// `None` for `const _: () = ();`
pub name: Option<Name>,
- pub visibility: RawVisibilityId,
- pub ast_id: FileAstId<ast::Const>,
+ pub(crate) visibility: RawVisibilityId,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Static {
pub name: Name,
- pub visibility: RawVisibilityId,
- pub ast_id: FileAstId<ast::Static>,
+ pub(crate) visibility: RawVisibilityId,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Trait {
pub name: Name,
- pub visibility: RawVisibilityId,
- pub items: Box<[AssocItem]>,
- pub ast_id: FileAstId<ast::Trait>,
+ pub(crate) visibility: RawVisibilityId,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct TraitAlias {
pub name: Name,
- pub visibility: RawVisibilityId,
- pub ast_id: FileAstId<ast::TraitAlias>,
+ pub(crate) visibility: RawVisibilityId,
}
#[derive(Debug, Clone, Eq, PartialEq)]
-pub struct Impl {
- pub items: Box<[AssocItem]>,
- pub ast_id: FileAstId<ast::Impl>,
-}
+pub struct Impl {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TypeAlias {
pub name: Name,
- pub visibility: RawVisibilityId,
- pub ast_id: FileAstId<ast::TypeAlias>,
+ pub(crate) visibility: RawVisibilityId,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Mod {
pub name: Name,
- pub visibility: RawVisibilityId,
- pub kind: ModKind,
- pub ast_id: FileAstId<ast::Module>,
+ pub(crate) visibility: RawVisibilityId,
+ pub(crate) kind: ModKind,
}
#[derive(Debug, Clone, Eq, PartialEq)]
-pub enum ModKind {
+pub(crate) enum ModKind {
/// `mod m { ... }`
- Inline { items: Box<[ModItem]> },
+ Inline { items: Box<[ModItemId]> },
/// `mod m;`
Outline,
}
@@ -858,7 +617,6 @@ pub enum ModKind {
pub struct MacroCall {
/// Path to the called macro.
pub path: Interned<ModPath>,
- pub ast_id: FileAstId<ast::MacroCall>,
pub expand_to: ExpandTo,
pub ctxt: SyntaxContext,
}
@@ -867,52 +625,13 @@ pub struct MacroCall {
pub struct MacroRules {
/// The name of the declared macro.
pub name: Name,
- pub ast_id: FileAstId<ast::MacroRules>,
}
/// "Macros 2.0" macro definition.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Macro2 {
pub name: Name,
- pub visibility: RawVisibilityId,
- pub ast_id: FileAstId<ast::MacroDef>,
-}
-
-impl Use {
- /// Maps a `UseTree` contained in this import back to its AST node.
- pub fn use_tree_to_ast(
- &self,
- db: &dyn DefDatabase,
- file_id: HirFileId,
- index: Idx<ast::UseTree>,
- ) -> ast::UseTree {
- // Re-lower the AST item and get the source map.
- // Note: The AST unwraps are fine, since if they fail we should have never obtained `index`.
- let ast = InFile::new(file_id, self.ast_id).to_node(db);
- let ast_use_tree = ast.use_tree().expect("missing `use_tree`");
- let (_, source_map) = lower::lower_use_tree(db, ast_use_tree, &mut |range| {
- db.span_map(file_id).span_for_range(range).ctx
- })
- .expect("failed to lower use tree");
- source_map[index].clone()
- }
-
- /// Maps a `UseTree` contained in this import back to its AST node.
- pub fn use_tree_source_map(
- &self,
- db: &dyn DefDatabase,
- file_id: HirFileId,
- ) -> Arena<ast::UseTree> {
- // Re-lower the AST item and get the source map.
- // Note: The AST unwraps are fine, since if they fail we should have never obtained `index`.
- let ast = InFile::new(file_id, self.ast_id).to_node(db);
- let ast_use_tree = ast.use_tree().expect("missing `use_tree`");
- lower::lower_use_tree(db, ast_use_tree, &mut |range| {
- db.span_map(file_id).span_for_range(range).ctx
- })
- .expect("failed to lower use tree")
- .1
- }
+ pub(crate) visibility: RawVisibilityId,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
@@ -925,15 +644,17 @@ pub enum ImportKind {
TypeOnly,
}
-impl UseTree {
+impl Use {
/// Expands the `UseTree` into individually imported `ModPath`s.
pub fn expand(
&self,
mut cb: impl FnMut(Idx<ast::UseTree>, ModPath, ImportKind, Option<ImportAlias>),
) {
- self.expand_impl(None, &mut cb)
+ self.use_tree.expand_impl(None, &mut 0, &mut cb)
}
+}
+impl UseTree {
/// The [`UseTreeKind`] of this `UseTree`.
pub fn kind(&self) -> &UseTreeKind {
&self.kind
@@ -942,6 +663,7 @@ impl UseTree {
fn expand_impl(
&self,
prefix: Option<ModPath>,
+ counting_index: &mut u32,
cb: &mut impl FnMut(Idx<ast::UseTree>, ModPath, ImportKind, Option<ImportAlias>),
) {
fn concat_mod_paths(
@@ -977,17 +699,27 @@ impl UseTree {
match &self.kind {
UseTreeKind::Single { path, alias } => {
if let Some((path, kind)) = concat_mod_paths(prefix, path) {
- cb(self.index, path, kind, alias.clone());
+ cb(Idx::from_raw(RawIdx::from_u32(*counting_index)), path, kind, alias.clone());
}
}
UseTreeKind::Glob { path: Some(path) } => {
if let Some((path, _)) = concat_mod_paths(prefix, path) {
- cb(self.index, path, ImportKind::Glob, None);
+ cb(
+ Idx::from_raw(RawIdx::from_u32(*counting_index)),
+ path,
+ ImportKind::Glob,
+ None,
+ );
}
}
UseTreeKind::Glob { path: None } => {
if let Some(prefix) = prefix {
- cb(self.index, prefix, ImportKind::Glob, None);
+ cb(
+ Idx::from_raw(RawIdx::from_u32(*counting_index)),
+ prefix,
+ ImportKind::Glob,
+ None,
+ );
}
}
UseTreeKind::Prefixed { prefix: additional_prefix, list } => {
@@ -999,82 +731,10 @@ impl UseTree {
None => prefix,
};
for tree in &**list {
- tree.expand_impl(prefix.clone(), cb);
+ *counting_index += 1;
+ tree.expand_impl(prefix.clone(), counting_index, cb);
}
}
}
}
}
-
-macro_rules! impl_froms {
- ($e:ident { $($v:ident ($t:ty)),* $(,)? }) => {
- $(
- impl From<$t> for $e {
- fn from(it: $t) -> $e {
- $e::$v(it)
- }
- }
- )*
- }
-}
-
-impl ModItem {
- pub fn as_assoc_item(&self) -> Option<AssocItem> {
- match self {
- ModItem::Use(_)
- | ModItem::ExternCrate(_)
- | ModItem::ExternBlock(_)
- | ModItem::Struct(_)
- | ModItem::Union(_)
- | ModItem::Enum(_)
- | ModItem::Static(_)
- | ModItem::Trait(_)
- | ModItem::TraitAlias(_)
- | ModItem::Impl(_)
- | ModItem::Mod(_)
- | ModItem::MacroRules(_)
- | ModItem::Macro2(_) => None,
- &ModItem::MacroCall(call) => Some(AssocItem::MacroCall(call)),
- &ModItem::Const(konst) => Some(AssocItem::Const(konst)),
- &ModItem::TypeAlias(alias) => Some(AssocItem::TypeAlias(alias)),
- &ModItem::Function(func) => Some(AssocItem::Function(func)),
- }
- }
-}
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-pub enum AssocItem {
- Function(FileItemTreeId<Function>),
- TypeAlias(FileItemTreeId<TypeAlias>),
- Const(FileItemTreeId<Const>),
- MacroCall(FileItemTreeId<MacroCall>),
-}
-
-impl_froms!(AssocItem {
- Function(FileItemTreeId<Function>),
- TypeAlias(FileItemTreeId<TypeAlias>),
- Const(FileItemTreeId<Const>),
- MacroCall(FileItemTreeId<MacroCall>),
-});
-
-impl From<AssocItem> for ModItem {
- fn from(item: AssocItem) -> Self {
- match item {
- AssocItem::Function(it) => it.into(),
- AssocItem::TypeAlias(it) => it.into(),
- AssocItem::Const(it) => it.into(),
- AssocItem::MacroCall(it) => it.into(),
- }
- }
-}
-
-impl AssocItem {
- pub fn ast_id(self, tree: &ItemTree) -> FileAstId<ast::AssocItem> {
- match self {
- AssocItem::Function(id) => tree[id].ast_id.upcast(),
- AssocItem::TypeAlias(id) => tree[id].ast_id.upcast(),
- AssocItem::Const(id) => tree[id].ast_id.upcast(),
- AssocItem::MacroCall(id) => tree[id].ast_id.upcast(),
- }
- }
-}