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.rs | 898 |
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(), - } - } -} |