Merge pull request #19982 from Veykril/push-uptnmqtlylsx

Simplify and optimize `ItemTree`
This commit is contained in:
Lukas Wirth 2025-06-13 11:16:24 +00:00 committed by GitHub
commit bd002fe65c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 561 additions and 758 deletions

View file

@ -26,7 +26,7 @@ use crate::{
AdtId, AstIdLoc, AttrDefId, GenericParamId, HasModule, LocalFieldId, Lookup, MacroId,
VariantId,
db::DefDatabase,
item_tree::AttrOwner,
item_tree::block_item_tree_query,
lang_item::LangItem,
nameres::{ModuleOrigin, ModuleSource},
src::{HasChildSource, HasSource},
@ -523,26 +523,25 @@ impl AttrsWithOwner {
let mod_data = &def_map[module.local_id];
let raw_attrs = match mod_data.origin {
ModuleOrigin::File { definition, declaration_tree_id, .. } => {
ModuleOrigin::File { definition, declaration_tree_id, declaration, .. } => {
let decl_attrs = declaration_tree_id
.item_tree(db)
.raw_attrs(AttrOwner::ModItem(declaration_tree_id.value.into()))
.raw_attrs(declaration.upcast())
.clone();
let tree = db.file_item_tree(definition.into());
let def_attrs = tree.raw_attrs(AttrOwner::TopLevel).clone();
let def_attrs = tree.top_level_raw_attrs().clone();
decl_attrs.merge(def_attrs)
}
ModuleOrigin::CrateRoot { definition } => {
let tree = db.file_item_tree(definition.into());
tree.raw_attrs(AttrOwner::TopLevel).clone()
tree.top_level_raw_attrs().clone()
}
ModuleOrigin::Inline { definition_tree_id, definition } => {
definition_tree_id.item_tree(db).raw_attrs(definition.upcast()).clone()
}
ModuleOrigin::Inline { definition_tree_id, .. } => definition_tree_id
.item_tree(db)
.raw_attrs(AttrOwner::ModItem(definition_tree_id.value.into()))
.clone(),
ModuleOrigin::BlockExpr { id, .. } => {
let tree = db.block_item_tree(id);
tree.raw_attrs(AttrOwner::TopLevel).clone()
let tree = block_item_tree_query(db, id);
tree.top_level_raw_attrs().clone()
}
};
Attrs::expand_cfg_attr(db, module.krate, raw_attrs)

View file

@ -24,7 +24,7 @@ use crate::{
},
hir::generics::GenericParams,
import_map::ImportMap,
item_tree::{AttrOwner, ItemTree},
item_tree::{ItemTree, file_item_tree_query},
lang_item::{self, LangItem},
nameres::{
assoc::{ImplItems, TraitItems},
@ -108,11 +108,9 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase {
fn expand_proc_attr_macros(&self) -> bool;
/// Computes an [`ItemTree`] for the given file or macro expansion.
#[salsa::invoke(ItemTree::file_item_tree_query)]
fn file_item_tree(&self, file_id: HirFileId) -> Arc<ItemTree>;
#[salsa::invoke(ItemTree::block_item_tree_query)]
fn block_item_tree(&self, block_id: BlockId) -> Arc<ItemTree>;
#[salsa::invoke(file_item_tree_query)]
#[salsa::transparent]
fn file_item_tree(&self, file_id: HirFileId) -> &ItemTree;
/// Turns a MacroId into a MacroDefId, describing the macro's definition post name resolution.
#[salsa::invoke(macro_def)]
@ -376,7 +374,7 @@ fn include_macro_invoc(
fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: Crate) -> bool {
let file = crate_id.data(db).root_file_id(db);
let item_tree = db.file_item_tree(file.into());
let attrs = item_tree.raw_attrs(AttrOwner::TopLevel);
let attrs = item_tree.top_level_raw_attrs();
for attr in &**attrs {
match attr.path().as_ident() {
Some(ident) if *ident == sym::no_std => return true,

View file

@ -37,8 +37,8 @@ mod tests;
use std::{
fmt::{self, Debug},
hash::{Hash, Hasher},
ops::{Index, Range},
hash::Hash,
ops::Index,
sync::OnceLock,
};
@ -51,12 +51,12 @@ use hir_expand::{
name::Name,
};
use intern::Interned;
use la_arena::{Arena, Idx, RawIdx};
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};
@ -64,13 +64,13 @@ 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 {
@ -86,112 +86,115 @@ impl fmt::Debug for RawVisibilityId {
}
}
#[salsa_macros::tracked(returns(ref))]
pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> ItemTree {
let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered();
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}");
},
}
};
item_tree.shrink_to_fit();
item_tree
}
#[salsa_macros::tracked(returns(ref))]
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();
// Blocks have a tendency to be empty due to macro calls that do not expand to items,
// so deduplicate this case via `Arc` to reduce the size of the query storage here.
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.small_data.is_empty()
&& item_tree.big_data.is_empty()
&& item_tree.top_level.is_empty()
&& item_tree.attrs.is_empty()
&& item_tree.top_attrs.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)
}
}
/// 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>>,
top_level: Box<[ModItemId]>,
top_attrs: RawAttrs,
attrs: FxHashMap<FileAstId<ast::Item>, RawAttrs>,
vis: ItemVisibilities,
// FIXME: They values store the key, turn this into a FxHashSet<ModItem> instead?
big_data: FxHashMap<FileAstId<ast::Item>, BigModItem>,
small_data: FxHashMap<FileAstId<ast::Item>, SmallModItem>,
}
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}");
},
}
};
if let Some(attrs) = top_attrs {
item_tree.attrs.insert(AttrOwner::TopLevel, attrs);
}
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)
}
}
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)
}
}
/// 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
}
pub(crate) fn raw_attrs(&self, of: AttrOwner) -> &RawAttrs {
/// 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: 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())
}
@ -199,105 +202,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,
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();
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();
}
big_data.shrink_to_fit();
small_data.shrink_to_fit();
}
}
#[derive(Default, Debug, Eq, PartialEq)]
struct ItemVisibilities {
arena: Box<[RawVisibility]>,
arena: ThinVec<RawVisibility>,
}
#[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>,
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 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(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,
@ -307,73 +284,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,
}
impl From<ModItem> for AttrOwner {
#[inline]
fn from(value: ModItem) -> Self {
AttrOwner::ModItem(value)
}
}
/// 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;
}
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)]
@ -383,14 +300,14 @@ 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),
}
}
@ -399,85 +316,32 @@ impl TreeId {
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)
}
}
)+
@ -485,21 +349,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]
}
}
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),
}
}
}
)+
@ -507,23 +369,24 @@ 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 {
@ -554,31 +417,24 @@ impl Index<RawVisibilityId> for ItemTree {
VisibilityExplicitness::Explicit,
)
}),
_ => &self.data().vis.arena[index.0 as usize],
_ => &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())
}
}
#[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 _;`
@ -632,43 +488,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 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(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 ast_id: FileAstId<ast::Union>,
pub(crate) visibility: RawVisibilityId,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Enum {
pub name: Name,
pub visibility: RawVisibilityId,
pub ast_id: FileAstId<ast::Enum>,
pub(crate) visibility: RawVisibilityId,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
@ -706,55 +556,47 @@ impl VisibilityExplicitness {
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 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 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,
}
@ -763,7 +605,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,
}
@ -772,15 +613,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>,
pub(crate) visibility: RawVisibilityId,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
@ -793,15 +632,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
@ -810,6 +651,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(
@ -845,17 +687,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 } => {
@ -867,7 +719,8 @@ 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);
}
}
}

View file

@ -10,7 +10,7 @@ use hir_expand::{
span_map::{SpanMap, SpanMapRef},
};
use la_arena::Arena;
use span::{AstIdMap, SyntaxContext};
use span::{AstIdMap, FileAstId, SyntaxContext};
use syntax::{
AstNode,
ast::{self, HasModuleItem, HasName},
@ -20,24 +20,21 @@ use triomphe::Arc;
use crate::{
db::DefDatabase,
item_tree::{
AttrOwner, Const, Enum, ExternBlock, ExternCrate, FieldsShape, FileItemTreeId, Function,
Idx, Impl, ImportAlias, Interned, ItemTree, ItemTreeData, Macro2, MacroCall, MacroRules,
Mod, ModItem, ModKind, ModPath, RawAttrs, RawVisibility, RawVisibilityId, Static, Struct,
StructKind, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind,
BigModItem, Const, Enum, ExternBlock, ExternCrate, FieldsShape, Function, Impl,
ImportAlias, Interned, ItemTree, ItemTreeAstId, Macro2, MacroCall, MacroRules, Mod,
ModItemId, ModKind, ModPath, RawAttrs, RawVisibility, RawVisibilityId, SmallModItem,
Static, Struct, StructKind, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind,
VisibilityExplicitness,
},
};
fn id<N>(index: Idx<N>) -> FileItemTreeId<N> {
FileItemTreeId(index)
}
pub(super) struct Ctx<'a> {
db: &'a dyn DefDatabase,
tree: ItemTree,
source_ast_id_map: Arc<AstIdMap>,
span_map: OnceCell<SpanMap>,
file: HirFileId,
top_level: Vec<ModItemId>,
visibilities: FxIndexSet<RawVisibility>,
}
@ -50,6 +47,7 @@ impl<'a> Ctx<'a> {
file,
span_map: OnceCell::new(),
visibilities: FxIndexSet::default(),
top_level: Vec::new(),
}
}
@ -58,16 +56,14 @@ impl<'a> Ctx<'a> {
}
pub(super) fn lower_module_items(mut self, item_owner: &dyn HasModuleItem) -> ItemTree {
self.tree.top_level =
item_owner.items().flat_map(|item| self.lower_mod_item(&item)).collect();
if let Some(data) = &mut self.tree.data {
data.vis.arena = self.visibilities.into_iter().collect();
}
self.top_level = item_owner.items().flat_map(|item| self.lower_mod_item(&item)).collect();
self.tree.vis.arena = self.visibilities.into_iter().collect();
self.tree.top_level = self.top_level.into_boxed_slice();
self.tree
}
pub(super) fn lower_macro_stmts(mut self, stmts: ast::MacroStmts) -> ItemTree {
self.tree.top_level = stmts
self.top_level = stmts
.statements()
.filter_map(|stmt| {
match stmt {
@ -91,20 +87,19 @@ impl<'a> Ctx<'a> {
if let Some(call) = tail_macro.macro_call() {
cov_mark::hit!(macro_stmt_with_trailing_macro_expr);
if let Some(mod_item) = self.lower_mod_item(&call.into()) {
self.tree.top_level.push(mod_item);
self.top_level.push(mod_item);
}
}
}
if let Some(data) = &mut self.tree.data {
data.vis.arena = self.visibilities.into_iter().collect();
}
self.tree.vis.arena = self.visibilities.into_iter().collect();
self.tree.top_level = self.top_level.into_boxed_slice();
self.tree
}
pub(super) fn lower_block(mut self, block: &ast::BlockExpr) -> ItemTree {
self.tree.attrs.insert(AttrOwner::TopLevel, RawAttrs::new(self.db, block, self.span_map()));
self.tree.top_level = block
self.tree.top_attrs = RawAttrs::new(self.db, block, self.span_map());
self.top_level = block
.statements()
.filter_map(|stmt| match stmt {
ast::Stmt::Item(item) => self.lower_mod_item(&item),
@ -120,22 +115,17 @@ impl<'a> Ctx<'a> {
if let Some(ast::Expr::MacroExpr(expr)) = block.tail_expr() {
if let Some(call) = expr.macro_call() {
if let Some(mod_item) = self.lower_mod_item(&call.into()) {
self.tree.top_level.push(mod_item);
self.top_level.push(mod_item);
}
}
}
if let Some(data) = &mut self.tree.data {
data.vis.arena = self.visibilities.into_iter().collect();
}
self.tree.vis.arena = self.visibilities.into_iter().collect();
self.tree.top_level = self.top_level.into_boxed_slice();
self.tree
}
fn data(&mut self) -> &mut ItemTreeData {
self.tree.data_mut()
}
fn lower_mod_item(&mut self, item: &ast::Item) -> Option<ModItem> {
let mod_item: ModItem = match item {
fn lower_mod_item(&mut self, item: &ast::Item) -> Option<ModItemId> {
let mod_item: ModItemId = match item {
ast::Item::Struct(ast) => self.lower_struct(ast)?.into(),
ast::Item::Union(ast) => self.lower_union(ast)?.into(),
ast::Item::Enum(ast) => self.lower_enum(ast)?.into(),
@ -155,12 +145,12 @@ impl<'a> Ctx<'a> {
ast::Item::ExternBlock(ast) => self.lower_extern_block(ast).into(),
};
let attrs = RawAttrs::new(self.db, item, self.span_map());
self.add_attrs(mod_item.into(), attrs);
self.add_attrs(mod_item.ast_id(), attrs);
Some(mod_item)
}
fn add_attrs(&mut self, item: AttrOwner, attrs: RawAttrs) {
fn add_attrs(&mut self, item: FileAstId<ast::Item>, attrs: RawAttrs) {
if !attrs.is_empty() {
match self.tree.attrs.entry(item) {
Entry::Occupied(mut entry) => {
@ -173,76 +163,78 @@ impl<'a> Ctx<'a> {
}
}
fn lower_struct(&mut self, strukt: &ast::Struct) -> Option<FileItemTreeId<Struct>> {
fn lower_struct(&mut self, strukt: &ast::Struct) -> Option<ItemTreeAstId<Struct>> {
let visibility = self.lower_visibility(strukt);
let name = strukt.name()?.as_name();
let ast_id = self.source_ast_id_map.ast_id(strukt);
let shape = adt_shape(strukt.kind());
let res = Struct { name, visibility, shape, ast_id };
let id = id(self.data().structs.alloc(res));
let res = Struct { name, visibility, shape };
self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Struct(res));
Some(id)
Some(ast_id)
}
fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> {
fn lower_union(&mut self, union: &ast::Union) -> Option<ItemTreeAstId<Union>> {
let visibility = self.lower_visibility(union);
let name = union.name()?.as_name();
let ast_id = self.source_ast_id_map.ast_id(union);
let res = Union { name, visibility, ast_id };
let id = id(self.data().unions.alloc(res));
Some(id)
let res = Union { name, visibility };
self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Union(res));
Some(ast_id)
}
fn lower_enum(&mut self, enum_: &ast::Enum) -> Option<FileItemTreeId<Enum>> {
fn lower_enum(&mut self, enum_: &ast::Enum) -> Option<ItemTreeAstId<Enum>> {
let visibility = self.lower_visibility(enum_);
let name = enum_.name()?.as_name();
let ast_id = self.source_ast_id_map.ast_id(enum_);
let res = Enum { name, visibility, ast_id };
let id = id(self.data().enums.alloc(res));
Some(id)
let res = Enum { name, visibility };
self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Enum(res));
Some(ast_id)
}
fn lower_function(&mut self, func: &ast::Fn) -> Option<FileItemTreeId<Function>> {
fn lower_function(&mut self, func: &ast::Fn) -> Option<ItemTreeAstId<Function>> {
let visibility = self.lower_visibility(func);
let name = func.name()?.as_name();
let ast_id = self.source_ast_id_map.ast_id(func);
let res = Function { name, visibility, ast_id };
let res = Function { name, visibility };
let id = id(self.data().functions.alloc(res));
Some(id)
self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Function(res));
Some(ast_id)
}
fn lower_type_alias(
&mut self,
type_alias: &ast::TypeAlias,
) -> Option<FileItemTreeId<TypeAlias>> {
) -> Option<ItemTreeAstId<TypeAlias>> {
let name = type_alias.name()?.as_name();
let visibility = self.lower_visibility(type_alias);
let ast_id = self.source_ast_id_map.ast_id(type_alias);
let res = TypeAlias { name, visibility, ast_id };
let id = id(self.data().type_aliases.alloc(res));
Some(id)
let res = TypeAlias { name, visibility };
self.tree.small_data.insert(ast_id.upcast(), SmallModItem::TypeAlias(res));
Some(ast_id)
}
fn lower_static(&mut self, static_: &ast::Static) -> Option<FileItemTreeId<Static>> {
fn lower_static(&mut self, static_: &ast::Static) -> Option<ItemTreeAstId<Static>> {
let name = static_.name()?.as_name();
let visibility = self.lower_visibility(static_);
let ast_id = self.source_ast_id_map.ast_id(static_);
let res = Static { name, visibility, ast_id };
Some(id(self.data().statics.alloc(res)))
let res = Static { name, visibility };
self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Static(res));
Some(ast_id)
}
fn lower_const(&mut self, konst: &ast::Const) -> FileItemTreeId<Const> {
fn lower_const(&mut self, konst: &ast::Const) -> ItemTreeAstId<Const> {
let name = konst.name().map(|it| it.as_name());
let visibility = self.lower_visibility(konst);
let ast_id = self.source_ast_id_map.ast_id(konst);
let res = Const { name, visibility, ast_id };
id(self.data().consts.alloc(res))
let res = Const { name, visibility };
self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Const(res));
ast_id
}
fn lower_module(&mut self, module: &ast::Module) -> Option<FileItemTreeId<Mod>> {
fn lower_module(&mut self, module: &ast::Module) -> Option<ItemTreeAstId<Mod>> {
let name = module.name()?.as_name();
let visibility = self.lower_visibility(module);
let kind = if module.semicolon_token().is_some() {
@ -259,56 +251,59 @@ impl<'a> Ctx<'a> {
}
};
let ast_id = self.source_ast_id_map.ast_id(module);
let res = Mod { name, visibility, kind, ast_id };
Some(id(self.data().mods.alloc(res)))
let res = Mod { name, visibility, kind };
self.tree.big_data.insert(ast_id.upcast(), BigModItem::Mod(res));
Some(ast_id)
}
fn lower_trait(&mut self, trait_def: &ast::Trait) -> Option<FileItemTreeId<Trait>> {
fn lower_trait(&mut self, trait_def: &ast::Trait) -> Option<ItemTreeAstId<Trait>> {
let name = trait_def.name()?.as_name();
let visibility = self.lower_visibility(trait_def);
let ast_id = self.source_ast_id_map.ast_id(trait_def);
let def = Trait { name, visibility, ast_id };
let id = id(self.data().traits.alloc(def));
Some(id)
let def = Trait { name, visibility };
self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Trait(def));
Some(ast_id)
}
fn lower_trait_alias(
&mut self,
trait_alias_def: &ast::TraitAlias,
) -> Option<FileItemTreeId<TraitAlias>> {
) -> Option<ItemTreeAstId<TraitAlias>> {
let name = trait_alias_def.name()?.as_name();
let visibility = self.lower_visibility(trait_alias_def);
let ast_id = self.source_ast_id_map.ast_id(trait_alias_def);
let alias = TraitAlias { name, visibility, ast_id };
let id = id(self.data().trait_aliases.alloc(alias));
Some(id)
let alias = TraitAlias { name, visibility };
self.tree.small_data.insert(ast_id.upcast(), SmallModItem::TraitAlias(alias));
Some(ast_id)
}
fn lower_impl(&mut self, impl_def: &ast::Impl) -> FileItemTreeId<Impl> {
fn lower_impl(&mut self, impl_def: &ast::Impl) -> ItemTreeAstId<Impl> {
let ast_id = self.source_ast_id_map.ast_id(impl_def);
// Note that trait impls don't get implicit `Self` unlike traits, because here they are a
// type alias rather than a type parameter, so this is handled by the resolver.
let res = Impl { ast_id };
id(self.data().impls.alloc(res))
let res = Impl {};
self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Impl(res));
ast_id
}
fn lower_use(&mut self, use_item: &ast::Use) -> Option<FileItemTreeId<Use>> {
fn lower_use(&mut self, use_item: &ast::Use) -> Option<ItemTreeAstId<Use>> {
let visibility = self.lower_visibility(use_item);
let ast_id = self.source_ast_id_map.ast_id(use_item);
let (use_tree, _) = lower_use_tree(self.db, use_item.use_tree()?, &mut |range| {
self.span_map().span_for_range(range).ctx
})?;
let res = Use { visibility, ast_id, use_tree };
Some(id(self.data().uses.alloc(res)))
let res = Use { visibility, use_tree };
self.tree.big_data.insert(ast_id.upcast(), BigModItem::Use(res));
Some(ast_id)
}
fn lower_extern_crate(
&mut self,
extern_crate: &ast::ExternCrate,
) -> Option<FileItemTreeId<ExternCrate>> {
) -> Option<ItemTreeAstId<ExternCrate>> {
let name = extern_crate.name_ref()?.as_name();
let alias = extern_crate.rename().map(|a| {
a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias)
@ -316,11 +311,12 @@ impl<'a> Ctx<'a> {
let visibility = self.lower_visibility(extern_crate);
let ast_id = self.source_ast_id_map.ast_id(extern_crate);
let res = ExternCrate { name, alias, visibility, ast_id };
Some(id(self.data().extern_crates.alloc(res)))
let res = ExternCrate { name, alias, visibility };
self.tree.big_data.insert(ast_id.upcast(), BigModItem::ExternCrate(res));
Some(ast_id)
}
fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> {
fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<ItemTreeAstId<MacroCall>> {
let span_map = self.span_map();
let path = m.path()?;
let range = path.syntax().text_range();
@ -329,29 +325,32 @@ impl<'a> Ctx<'a> {
})?);
let ast_id = self.source_ast_id_map.ast_id(m);
let expand_to = hir_expand::ExpandTo::from_call_site(m);
let res = MacroCall { path, ast_id, expand_to, ctxt: span_map.span_for_range(range).ctx };
Some(id(self.data().macro_calls.alloc(res)))
let res = MacroCall { path, expand_to, ctxt: span_map.span_for_range(range).ctx };
self.tree.small_data.insert(ast_id.upcast(), SmallModItem::MacroCall(res));
Some(ast_id)
}
fn lower_macro_rules(&mut self, m: &ast::MacroRules) -> Option<FileItemTreeId<MacroRules>> {
fn lower_macro_rules(&mut self, m: &ast::MacroRules) -> Option<ItemTreeAstId<MacroRules>> {
let name = m.name()?;
let ast_id = self.source_ast_id_map.ast_id(m);
let res = MacroRules { name: name.as_name(), ast_id };
Some(id(self.data().macro_rules.alloc(res)))
let res = MacroRules { name: name.as_name() };
self.tree.small_data.insert(ast_id.upcast(), SmallModItem::MacroRules(res));
Some(ast_id)
}
fn lower_macro_def(&mut self, m: &ast::MacroDef) -> Option<FileItemTreeId<Macro2>> {
fn lower_macro_def(&mut self, m: &ast::MacroDef) -> Option<ItemTreeAstId<Macro2>> {
let name = m.name()?;
let ast_id = self.source_ast_id_map.ast_id(m);
let visibility = self.lower_visibility(m);
let res = Macro2 { name: name.as_name(), ast_id, visibility };
Some(id(self.data().macro_defs.alloc(res)))
let res = Macro2 { name: name.as_name(), visibility };
self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Macro2(res));
Some(ast_id)
}
fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> FileItemTreeId<ExternBlock> {
fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> ItemTreeAstId<ExternBlock> {
let ast_id = self.source_ast_id_map.ast_id(block);
let children: Box<[_]> = block.extern_item_list().map_or(Box::new([]), |list| {
list.extern_items()
@ -360,21 +359,22 @@ impl<'a> Ctx<'a> {
// (in other words, the knowledge that they're in an extern block must not be used).
// This is because an extern block can contain macros whose ItemTree's top-level items
// should be considered to be in an extern block too.
let mod_item: ModItem = match &item {
let mod_item: ModItemId = match &item {
ast::ExternItem::Fn(ast) => self.lower_function(ast)?.into(),
ast::ExternItem::Static(ast) => self.lower_static(ast)?.into(),
ast::ExternItem::TypeAlias(ty) => self.lower_type_alias(ty)?.into(),
ast::ExternItem::MacroCall(call) => self.lower_macro_call(call)?.into(),
};
let attrs = RawAttrs::new(self.db, &item, self.span_map());
self.add_attrs(mod_item.into(), attrs);
self.add_attrs(mod_item.ast_id(), attrs);
Some(mod_item)
})
.collect()
});
let res = ExternBlock { ast_id, children };
id(self.data().extern_blocks.alloc(res))
let res = ExternBlock { children };
self.tree.small_data.insert(ast_id.upcast(), SmallModItem::ExternBlock(res));
ast_id
}
fn lower_visibility(&mut self, item: &dyn ast::HasVisibility) -> RawVisibilityId {
@ -425,17 +425,15 @@ impl UseTreeLowering<'_> {
}
};
self.mapping.alloc(tree.clone());
let list = use_tree_list
.use_trees()
.filter_map(|tree| self.lower_use_tree(tree, span_for_range))
.collect();
Some(
self.use_tree(
UseTreeKind::Prefixed { prefix: prefix.map(Interned::new), list },
tree,
),
)
Some(UseTree {
kind: UseTreeKind::Prefixed { prefix: prefix.map(Interned::new), list },
})
} else {
let is_glob = tree.star_token().is_some();
let path = match tree.path() {
@ -454,23 +452,20 @@ impl UseTreeLowering<'_> {
if path.is_none() {
cov_mark::hit!(glob_enum_group);
}
Some(self.use_tree(UseTreeKind::Glob { path: path.map(Interned::new) }, tree))
self.mapping.alloc(tree.clone());
Some(UseTree { kind: UseTreeKind::Glob { path: path.map(Interned::new) } })
}
// Globs can't be renamed
(_, Some(_), true) | (None, None, false) => None,
// `bla::{ as Name}` is invalid
(None, Some(_), false) => None,
(Some(path), alias, false) => Some(
self.use_tree(UseTreeKind::Single { path: Interned::new(path), alias }, tree),
),
(Some(path), alias, false) => {
self.mapping.alloc(tree.clone());
Some(UseTree { kind: UseTreeKind::Single { path: Interned::new(path), alias } })
}
}
}
}
fn use_tree(&mut self, kind: UseTreeKind, ast: ast::UseTree) -> UseTree {
let index = self.mapping.alloc(ast);
UseTree { index, kind }
}
}
pub(crate) fn lower_use_tree(

View file

@ -6,9 +6,9 @@ use span::{Edition, ErasedFileAstId};
use crate::{
item_tree::{
AttrOwner, Const, DefDatabase, Enum, ExternBlock, ExternCrate, FieldsShape, Function, Impl,
ItemTree, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, RawAttrs, RawVisibilityId,
Static, Struct, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind,
Const, DefDatabase, Enum, ExternBlock, ExternCrate, FieldsShape, Function, Impl, ItemTree,
Macro2, MacroCall, MacroRules, Mod, ModItemId, ModKind, RawAttrs, RawVisibilityId, Static,
Struct, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind,
},
visibility::RawVisibility,
};
@ -17,9 +17,7 @@ pub(super) fn print_item_tree(db: &dyn DefDatabase, tree: &ItemTree, edition: Ed
let mut p =
Printer { db, tree, buf: String::new(), indent_level: 0, needs_indent: true, edition };
if let Some(attrs) = tree.attrs.get(&AttrOwner::TopLevel) {
p.print_attrs(attrs, true, "\n");
}
p.print_attrs(&tree.top_attrs, true, "\n");
p.blank();
for item in tree.top_level_items() {
@ -101,8 +99,8 @@ impl Printer<'_> {
}
}
fn print_attrs_of(&mut self, of: impl Into<AttrOwner>, separated_by: &str) {
if let Some(attrs) = self.tree.attrs.get(&of.into()) {
fn print_attrs_of(&mut self, of: ModItemId, separated_by: &str) {
if let Some(attrs) = self.tree.attrs.get(&of.ast_id()) {
self.print_attrs(attrs, false, separated_by);
}
}
@ -159,20 +157,20 @@ impl Printer<'_> {
}
}
fn print_mod_item(&mut self, item: ModItem) {
fn print_mod_item(&mut self, item: ModItemId) {
self.print_attrs_of(item, "\n");
match item {
ModItem::Use(it) => {
let Use { visibility, use_tree, ast_id } = &self.tree[it];
ModItemId::Use(ast_id) => {
let Use { visibility, use_tree } = &self.tree[ast_id];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
w!(self, "use ");
self.print_use_tree(use_tree);
wln!(self, ";");
}
ModItem::ExternCrate(it) => {
let ExternCrate { name, alias, visibility, ast_id } = &self.tree[it];
ModItemId::ExternCrate(ast_id) => {
let ExternCrate { name, alias, visibility } = &self.tree[ast_id];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
w!(self, "extern crate {}", name.display(self.db, self.edition));
@ -181,8 +179,8 @@ impl Printer<'_> {
}
wln!(self, ";");
}
ModItem::ExternBlock(it) => {
let ExternBlock { ast_id, children } = &self.tree[it];
ModItemId::ExternBlock(ast_id) => {
let ExternBlock { children } = &self.tree[ast_id];
self.print_ast_id(ast_id.erase());
w!(self, "extern {{");
self.indented(|this| {
@ -192,14 +190,14 @@ impl Printer<'_> {
});
wln!(self, "}}");
}
ModItem::Function(it) => {
let Function { name, visibility, ast_id } = &self.tree[it];
ModItemId::Function(ast_id) => {
let Function { name, visibility } = &self.tree[ast_id];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
wln!(self, "fn {};", name.display(self.db, self.edition));
}
ModItem::Struct(it) => {
let Struct { visibility, name, shape: kind, ast_id } = &self.tree[it];
ModItemId::Struct(ast_id) => {
let Struct { visibility, name, shape: kind } = &self.tree[ast_id];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
w!(self, "struct {}", name.display(self.db, self.edition));
@ -210,22 +208,22 @@ impl Printer<'_> {
wln!(self, ";");
}
}
ModItem::Union(it) => {
let Union { name, visibility, ast_id } = &self.tree[it];
ModItemId::Union(ast_id) => {
let Union { name, visibility } = &self.tree[ast_id];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
w!(self, "union {}", name.display(self.db, self.edition));
self.print_fields(FieldsShape::Record);
wln!(self);
}
ModItem::Enum(it) => {
let Enum { name, visibility, ast_id } = &self.tree[it];
ModItemId::Enum(ast_id) => {
let Enum { name, visibility } = &self.tree[ast_id];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
w!(self, "enum {} {{ ... }}", name.display(self.db, self.edition));
}
ModItem::Const(it) => {
let Const { name, visibility, ast_id } = &self.tree[it];
ModItemId::Const(ast_id) => {
let Const { name, visibility } = &self.tree[ast_id];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
w!(self, "const ");
@ -235,8 +233,8 @@ impl Printer<'_> {
}
wln!(self, " = _;");
}
ModItem::Static(it) => {
let Static { name, visibility, ast_id } = &self.tree[it];
ModItemId::Static(ast_id) => {
let Static { name, visibility } = &self.tree[ast_id];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
w!(self, "static ");
@ -244,33 +242,33 @@ impl Printer<'_> {
w!(self, " = _;");
wln!(self);
}
ModItem::Trait(it) => {
let Trait { name, visibility, ast_id } = &self.tree[it];
ModItemId::Trait(ast_id) => {
let Trait { name, visibility } = &self.tree[ast_id];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
w!(self, "trait {} {{ ... }}", name.display(self.db, self.edition));
}
ModItem::TraitAlias(it) => {
let TraitAlias { name, visibility, ast_id } = &self.tree[it];
ModItemId::TraitAlias(ast_id) => {
let TraitAlias { name, visibility } = &self.tree[ast_id];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
wln!(self, "trait {} = ..;", name.display(self.db, self.edition));
}
ModItem::Impl(it) => {
let Impl { ast_id } = &self.tree[it];
ModItemId::Impl(ast_id) => {
let Impl {} = &self.tree[ast_id];
self.print_ast_id(ast_id.erase());
w!(self, "impl {{ ... }}");
}
ModItem::TypeAlias(it) => {
let TypeAlias { name, visibility, ast_id } = &self.tree[it];
ModItemId::TypeAlias(ast_id) => {
let TypeAlias { name, visibility } = &self.tree[ast_id];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
w!(self, "type {}", name.display(self.db, self.edition));
w!(self, ";");
wln!(self);
}
ModItem::Mod(it) => {
let Mod { name, visibility, kind, ast_id } = &self.tree[it];
ModItemId::Mod(ast_id) => {
let Mod { name, visibility, kind } = &self.tree[ast_id];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
w!(self, "mod {}", name.display(self.db, self.edition));
@ -289,8 +287,8 @@ impl Printer<'_> {
}
}
}
ModItem::MacroCall(it) => {
let MacroCall { path, ast_id, expand_to, ctxt } = &self.tree[it];
ModItemId::MacroCall(ast_id) => {
let MacroCall { path, expand_to, ctxt } = &self.tree[ast_id];
let _ = writeln!(
self,
"// AstId: {:#?}, SyntaxContextId: {}, ExpandTo: {:?}",
@ -300,13 +298,13 @@ impl Printer<'_> {
);
wln!(self, "{}!(...);", path.display(self.db, self.edition));
}
ModItem::MacroRules(it) => {
let MacroRules { name, ast_id } = &self.tree[it];
ModItemId::MacroRules(ast_id) => {
let MacroRules { name } = &self.tree[ast_id];
self.print_ast_id(ast_id.erase());
wln!(self, "macro_rules! {} {{ ... }}", name.display(self.db, self.edition));
}
ModItem::Macro2(it) => {
let Macro2 { name, visibility, ast_id } = &self.tree[it];
ModItemId::Macro2(ast_id) => {
let Macro2 { name, visibility } = &self.tree[ast_id];
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
wln!(self, "macro {} {{ ... }}", name.display(self.db, self.edition));

View file

@ -80,7 +80,7 @@ use crate::{
LocalModuleId, Lookup, MacroExpander, MacroId, ModuleId, ProcMacroId, UseId,
db::DefDatabase,
item_scope::{BuiltinShadowMode, ItemScope},
item_tree::{ItemTreeId, Mod, TreeId},
item_tree::TreeId,
nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode},
per_ns::PerNs,
visibility::{Visibility, VisibilityExplicitness},
@ -289,11 +289,11 @@ pub enum ModuleOrigin {
File {
is_mod_rs: bool,
declaration: FileAstId<ast::Module>,
declaration_tree_id: ItemTreeId<Mod>,
declaration_tree_id: TreeId,
definition: EditionedFileId,
},
Inline {
definition_tree_id: ItemTreeId<Mod>,
definition_tree_id: TreeId,
definition: FileAstId<ast::Module>,
},
/// Pseudo-module introduced by a block scope (contains only inner items).

View file

@ -35,8 +35,8 @@ use crate::{
db::DefDatabase,
item_scope::{GlobId, ImportId, ImportOrExternCrate, PerNsGlobImports},
item_tree::{
self, FieldsShape, FileItemTreeId, ImportAlias, ImportKind, ItemTree, ItemTreeId,
ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, UseTreeKind,
self, FieldsShape, ImportAlias, ImportKind, ItemTree, ItemTreeAstId, Macro2, MacroCall,
MacroRules, Mod, ModItemId, ModKind, TreeId,
},
macro_call_as_call_id,
nameres::{
@ -140,7 +140,6 @@ struct ImportSource {
id: UseId,
is_prelude: bool,
kind: ImportKind,
item_tree_id: ItemTreeId<item_tree::Use>,
}
#[derive(Debug, Eq, PartialEq)]
@ -154,19 +153,19 @@ struct Import {
impl Import {
fn from_use(
tree: &ItemTree,
item_tree_id: ItemTreeId<item_tree::Use>,
item: FileAstId<ast::Use>,
id: UseId,
is_prelude: bool,
mut cb: impl FnMut(Self),
) {
let it = &tree[item_tree_id.value];
let it = &tree[item];
let visibility = &tree[it.visibility];
it.use_tree.expand(|idx, path, kind, alias| {
it.expand(|idx, path, kind, alias| {
cb(Self {
path,
alias,
visibility: visibility.clone(),
source: ImportSource { use_tree: idx, id, is_prelude, kind, item_tree_id },
source: ImportSource { use_tree: idx, id, is_prelude, kind },
});
});
}
@ -181,15 +180,15 @@ struct ImportDirective {
}
#[derive(Clone, Debug, Eq, PartialEq)]
struct MacroDirective {
struct MacroDirective<'db> {
module_id: LocalModuleId,
depth: usize,
kind: MacroDirectiveKind,
kind: MacroDirectiveKind<'db>,
container: ItemContainerId,
}
#[derive(Clone, Debug, Eq, PartialEq)]
enum MacroDirectiveKind {
enum MacroDirectiveKind<'db> {
FnLike {
ast_id: AstIdWithPath<ast::MacroCall>,
expand_to: ExpandTo,
@ -206,30 +205,31 @@ enum MacroDirectiveKind {
Attr {
ast_id: AstIdWithPath<ast::Item>,
attr: Attr,
mod_item: ModItem,
mod_item: ModItemId,
/* is this needed? */ tree: TreeId,
item_tree: &'db ItemTree,
},
}
/// Walks the tree of module recursively
struct DefCollector<'a> {
db: &'a dyn DefDatabase,
struct DefCollector<'db> {
db: &'db dyn DefDatabase,
def_map: DefMap,
local_def_map: LocalDefMap,
/// Set only in case of blocks.
crate_local_def_map: Option<&'a LocalDefMap>,
crate_local_def_map: Option<&'db LocalDefMap>,
// The dependencies of the current crate, including optional deps like `test`.
deps: FxHashMap<Name, BuiltDependency>,
glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility, GlobId)>>,
unresolved_imports: Vec<ImportDirective>,
indeterminate_imports: Vec<(ImportDirective, PerNs)>,
unresolved_macros: Vec<MacroDirective>,
unresolved_macros: Vec<MacroDirective<'db>>,
// We'd like to avoid emitting a diagnostics avalanche when some `extern crate` doesn't
// resolve. When we emit diagnostics for unresolved imports, we only do so if the import
// doesn't start with an unresolved crate's name.
unresolved_extern_crates: FxHashSet<Name>,
mod_dirs: FxHashMap<LocalModuleId, ModDir>,
cfg_options: &'a CfgOptions,
cfg_options: &'db CfgOptions,
/// List of procedural macros defined by this crate. This is read from the dynamic library
/// built by the build system, and is the list of proc-macros we can actually expand. It is
/// empty when proc-macro support is disabled (in which case we still do name resolution for
@ -244,10 +244,10 @@ struct DefCollector<'a> {
/// This also stores the attributes to skip when we resolve derive helpers and non-macro
/// non-builtin attributes in general.
// FIXME: There has to be a better way to do this
skip_attrs: FxHashMap<InFile<ModItem>, AttrId>,
skip_attrs: FxHashMap<InFile<FileAstId<ast::Item>>, AttrId>,
}
impl DefCollector<'_> {
impl<'db> DefCollector<'db> {
fn seed_with_top_level(&mut self) {
let _p = tracing::info_span!("seed_with_top_level").entered();
@ -355,7 +355,7 @@ impl DefCollector<'_> {
macro_depth: 0,
module_id: DefMap::ROOT,
tree_id: TreeId::new(file_id.into(), None),
item_tree: &item_tree,
item_tree,
mod_dir: ModDir::root(),
}
.collect_in_top_module(item_tree.top_level_items());
@ -376,7 +376,7 @@ impl DefCollector<'_> {
macro_depth: 0,
module_id: DefMap::ROOT,
tree_id,
item_tree: &item_tree,
item_tree,
mod_dir: ModDir::root(),
}
.collect_in_top_module(item_tree.top_level_items());
@ -459,7 +459,7 @@ impl DefCollector<'_> {
self.unresolved_macros.iter().enumerate().find_map(|(idx, directive)| match &directive
.kind
{
MacroDirectiveKind::Attr { ast_id, mod_item, attr, tree } => {
MacroDirectiveKind::Attr { ast_id, mod_item, attr, tree, item_tree } => {
self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
directive.module_id,
MacroCallKind::Attr {
@ -470,16 +470,22 @@ impl DefCollector<'_> {
attr.path().clone(),
));
self.skip_attrs.insert(ast_id.ast_id.with_value(*mod_item), attr.id);
self.skip_attrs.insert(ast_id.ast_id.with_value(mod_item.ast_id()), attr.id);
Some((idx, directive, *mod_item, *tree))
Some((idx, directive, *mod_item, *tree, *item_tree))
}
_ => None,
});
match unresolved_attr {
Some((pos, &MacroDirective { module_id, depth, container, .. }, mod_item, tree_id)) => {
let item_tree = &tree_id.item_tree(self.db);
Some((
pos,
&MacroDirective { module_id, depth, container, .. },
mod_item,
tree_id,
item_tree,
)) => {
// FIXME: Remove this clone
let mod_dir = self.mod_dirs[&module_id].clone();
ModCollector {
def_collector: self,
@ -860,7 +866,6 @@ impl DefCollector<'_> {
kind: kind @ (ImportKind::Plain | ImportKind::TypeOnly),
id,
use_tree,
item_tree_id,
..
} => {
let name = match &import.alias {
@ -893,13 +898,11 @@ impl DefCollector<'_> {
let Some(ImportOrExternCrate::ExternCrate(_)) = def.import else {
return false;
};
let item_tree = item_tree_id.item_tree(self.db);
let use_kind = item_tree[item_tree_id.value].use_tree.kind();
let UseTreeKind::Single { path, .. } = use_kind else {
if kind == ImportKind::Glob {
return false;
};
matches!(path.kind, PathKind::Plain | PathKind::SELF)
&& path.segments().len() < 2
}
matches!(import.path.kind, PathKind::Plain | PathKind::SELF)
&& import.path.segments().len() < 2
};
if is_extern_crate_reimport_without_prefix() {
def.vis = vis;
@ -1253,7 +1256,7 @@ impl DefCollector<'_> {
fn resolve_macros(&mut self) -> ReachedFixedPoint {
let mut macros = mem::take(&mut self.unresolved_macros);
let mut resolved = Vec::new();
let mut push_resolved = |directive: &MacroDirective, call_id| {
let mut push_resolved = |directive: &MacroDirective<'_>, call_id| {
resolved.push((directive.module_id, directive.depth, directive.container, call_id));
};
@ -1266,7 +1269,7 @@ impl DefCollector<'_> {
let mut eager_callback_buffer = vec![];
let mut res = ReachedFixedPoint::Yes;
// Retain unresolved macros after this round of resolution.
let mut retain = |directive: &MacroDirective| {
let mut retain = |directive: &MacroDirective<'db>| {
let subns = match &directive.kind {
MacroDirectiveKind::FnLike { .. } => MacroSubNs::Bang,
MacroDirectiveKind::Attr { .. } | MacroDirectiveKind::Derive { .. } => {
@ -1361,22 +1364,29 @@ impl DefCollector<'_> {
return Resolved::Yes;
}
}
MacroDirectiveKind::Attr { ast_id: file_ast_id, mod_item, attr, tree } => {
MacroDirectiveKind::Attr {
ast_id: file_ast_id,
mod_item,
attr,
tree,
item_tree,
} => {
let &AstIdWithPath { ast_id, ref path } = file_ast_id;
let file_id = ast_id.file_id;
let mut recollect_without = |collector: &mut Self| {
// Remove the original directive since we resolved it.
let mod_dir = collector.mod_dirs[&directive.module_id].clone();
collector.skip_attrs.insert(InFile::new(file_id, *mod_item), attr.id);
collector
.skip_attrs
.insert(InFile::new(file_id, mod_item.ast_id()), attr.id);
let item_tree = tree.item_tree(self.db);
ModCollector {
def_collector: collector,
macro_depth: directive.depth,
module_id: directive.module_id,
tree_id: *tree,
item_tree: &item_tree,
item_tree,
mod_dir,
}
.collect(&[*mod_item], directive.container);
@ -1429,11 +1439,10 @@ impl DefCollector<'_> {
// normal (as that would just be an identity expansion with extra output)
// Instead we treat derive attributes special and apply them separately.
let item_tree = tree.item_tree(self.db);
let ast_adt_id: FileAstId<ast::Adt> = match *mod_item {
ModItem::Struct(strukt) => item_tree[strukt].ast_id().upcast(),
ModItem::Union(union) => item_tree[union].ast_id().upcast(),
ModItem::Enum(enum_) => item_tree[enum_].ast_id().upcast(),
ModItemId::Struct(ast_id) => ast_id.upcast(),
ModItemId::Union(ast_id) => ast_id.upcast(),
ModItemId::Enum(ast_id) => ast_id.upcast(),
_ => {
let diag = DefDiagnostic::invalid_derive_target(
directive.module_id,
@ -1565,7 +1574,7 @@ impl DefCollector<'_> {
macro_depth: depth,
tree_id: TreeId::new(file_id, None),
module_id,
item_tree: &item_tree,
item_tree,
mod_dir,
}
.collect(item_tree.top_level_items(), container);
@ -1642,8 +1651,7 @@ impl DefCollector<'_> {
import:
Import {
ref path,
source:
ImportSource { use_tree, id, is_prelude: _, kind: _, item_tree_id: _ },
source: ImportSource { use_tree, id, is_prelude: _, kind: _ },
..
},
..
@ -1667,22 +1675,22 @@ impl DefCollector<'_> {
}
/// Walks a single module, populating defs, imports and macros
struct ModCollector<'a, 'b> {
def_collector: &'a mut DefCollector<'b>,
struct ModCollector<'a, 'db> {
def_collector: &'a mut DefCollector<'db>,
macro_depth: usize,
module_id: LocalModuleId,
tree_id: TreeId,
item_tree: &'a ItemTree,
item_tree: &'db ItemTree,
mod_dir: ModDir,
}
impl ModCollector<'_, '_> {
fn collect_in_top_module(&mut self, items: &[ModItem]) {
fn collect_in_top_module(&mut self, items: &[ModItemId]) {
let module = self.def_collector.def_map.module_id(self.module_id);
self.collect(items, module.into())
}
fn collect(&mut self, items: &[ModItem], container: ItemContainerId) {
fn collect(&mut self, items: &[ModItemId], container: ItemContainerId) {
let krate = self.def_collector.def_map.krate;
let is_crate_root =
self.module_id == DefMap::ROOT && self.def_collector.def_map.block.is_none();
@ -1721,29 +1729,11 @@ impl ModCollector<'_, '_> {
.unwrap_or(Visibility::Public)
};
let mut process_mod_item = |item: ModItem| {
let attrs = self.item_tree.attrs(db, krate, item.into());
let mut process_mod_item = |item: ModItemId| {
let attrs = self.item_tree.attrs(db, krate, item.ast_id());
if let Some(cfg) = attrs.cfg() {
if !self.is_cfg_enabled(&cfg) {
let ast_id = match item {
ModItem::Use(it) => self.item_tree[it].ast_id.erase(),
ModItem::ExternCrate(it) => self.item_tree[it].ast_id.erase(),
ModItem::ExternBlock(it) => self.item_tree[it].ast_id.erase(),
ModItem::Function(it) => self.item_tree[it].ast_id.erase(),
ModItem::Struct(it) => self.item_tree[it].ast_id.erase(),
ModItem::Union(it) => self.item_tree[it].ast_id.erase(),
ModItem::Enum(it) => self.item_tree[it].ast_id.erase(),
ModItem::Const(it) => self.item_tree[it].ast_id.erase(),
ModItem::Static(it) => self.item_tree[it].ast_id.erase(),
ModItem::Trait(it) => self.item_tree[it].ast_id.erase(),
ModItem::TraitAlias(it) => self.item_tree[it].ast_id.erase(),
ModItem::Impl(it) => self.item_tree[it].ast_id.erase(),
ModItem::TypeAlias(it) => self.item_tree[it].ast_id.erase(),
ModItem::Mod(it) => self.item_tree[it].ast_id.erase(),
ModItem::MacroCall(it) => self.item_tree[it].ast_id.erase(),
ModItem::MacroRules(it) => self.item_tree[it].ast_id.erase(),
ModItem::Macro2(it) => self.item_tree[it].ast_id.erase(),
};
let ast_id = item.ast_id().erase();
self.emit_unconfigured_diagnostic(InFile::new(self.file_id(), ast_id), &cfg);
return;
}
@ -1761,35 +1751,27 @@ impl ModCollector<'_, '_> {
self.def_collector.crate_local_def_map.unwrap_or(&self.def_collector.local_def_map);
match item {
ModItem::Mod(m) => self.collect_module(m, &attrs),
ModItem::Use(item_tree_id) => {
let id = UseLoc {
container: module,
id: InFile::new(self.file_id(), self.item_tree[item_tree_id].ast_id),
}
.intern(db);
ModItemId::Mod(m) => self.collect_module(m, &attrs),
ModItemId::Use(item_tree_id) => {
let id =
UseLoc { container: module, id: InFile::new(self.file_id(), item_tree_id) }
.intern(db);
let is_prelude = attrs.by_key(sym::prelude_import).exists();
Import::from_use(
self.item_tree,
ItemTreeId::new(self.tree_id, item_tree_id),
id,
is_prelude,
|import| {
self.def_collector.unresolved_imports.push(ImportDirective {
module_id: self.module_id,
import,
status: PartialResolvedImport::Unresolved,
});
},
)
Import::from_use(self.item_tree, item_tree_id, id, is_prelude, |import| {
self.def_collector.unresolved_imports.push(ImportDirective {
module_id: self.module_id,
import,
status: PartialResolvedImport::Unresolved,
});
})
}
ModItem::ExternCrate(item_tree_id) => {
let item_tree::ExternCrate { name, visibility, alias, ast_id } =
ModItemId::ExternCrate(item_tree_id) => {
let item_tree::ExternCrate { name, visibility, alias } =
&self.item_tree[item_tree_id];
let id = ExternCrateLoc {
container: module,
id: InFile::new(self.tree_id.file_id(), *ast_id),
id: InFile::new(self.tree_id.file_id(), item_tree_id),
}
.intern(db);
def_map.modules[self.module_id].scope.define_extern_crate_decl(id);
@ -1852,15 +1834,15 @@ impl ModCollector<'_, '_> {
self.def_collector.def_map.diagnostics.push(
DefDiagnostic::unresolved_extern_crate(
module_id,
InFile::new(self.file_id(), *ast_id),
InFile::new(self.file_id(), item_tree_id),
),
);
}
}
ModItem::ExternBlock(block) => {
ModItemId::ExternBlock(block) => {
let extern_block_id = ExternBlockLoc {
container: module,
id: InFile::new(self.file_id(), self.item_tree[block].ast_id),
id: InFile::new(self.file_id(), block),
}
.intern(db);
self.def_collector.def_map.modules[self.module_id]
@ -1871,24 +1853,20 @@ impl ModCollector<'_, '_> {
ItemContainerId::ExternBlockId(extern_block_id),
)
}
ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac], container),
ModItem::MacroRules(id) => self.collect_macro_rules(id, module),
ModItem::Macro2(id) => self.collect_macro_def(id, module),
ModItem::Impl(imp) => {
let impl_id = ImplLoc {
container: module,
id: InFile::new(self.file_id(), self.item_tree[imp].ast_id),
}
.intern(db);
ModItemId::MacroCall(mac) => self.collect_macro_call(mac, container),
ModItemId::MacroRules(id) => self.collect_macro_rules(id, module),
ModItemId::Macro2(id) => self.collect_macro_def(id, module),
ModItemId::Impl(imp) => {
let impl_id =
ImplLoc { container: module, id: InFile::new(self.file_id(), imp) }
.intern(db);
self.def_collector.def_map.modules[self.module_id].scope.define_impl(impl_id)
}
ModItem::Function(id) => {
ModItemId::Function(id) => {
let it = &self.item_tree[id];
let fn_id = FunctionLoc {
container,
id: InFile::new(self.tree_id.file_id(), it.ast_id),
}
.intern(db);
let fn_id =
FunctionLoc { container, id: InFile::new(self.tree_id.file_id(), id) }
.intern(db);
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
@ -1899,7 +1877,7 @@ impl ModCollector<'_, '_> {
if let Some(proc_macro) = attrs.parse_proc_macro_decl(&it.name) {
self.def_collector.export_proc_macro(
proc_macro,
InFile::new(self.file_id(), self.item_tree[id].ast_id()),
InFile::new(self.file_id(), id),
fn_id,
);
}
@ -1907,13 +1885,13 @@ impl ModCollector<'_, '_> {
update_def(self.def_collector, fn_id.into(), &it.name, vis, false);
}
ModItem::Struct(id) => {
ModItemId::Struct(id) => {
let it = &self.item_tree[id];
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
update_def(
self.def_collector,
StructLoc { container: module, id: InFile::new(self.file_id(), it.ast_id) }
StructLoc { container: module, id: InFile::new(self.file_id(), id) }
.intern(db)
.into(),
&it.name,
@ -1921,13 +1899,13 @@ impl ModCollector<'_, '_> {
!matches!(it.shape, FieldsShape::Record),
);
}
ModItem::Union(id) => {
ModItemId::Union(id) => {
let it = &self.item_tree[id];
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
update_def(
self.def_collector,
UnionLoc { container: module, id: InFile::new(self.file_id(), it.ast_id) }
UnionLoc { container: module, id: InFile::new(self.file_id(), id) }
.intern(db)
.into(),
&it.name,
@ -1935,21 +1913,19 @@ impl ModCollector<'_, '_> {
false,
);
}
ModItem::Enum(id) => {
ModItemId::Enum(id) => {
let it = &self.item_tree[id];
let enum_ = EnumLoc {
container: module,
id: InFile::new(self.tree_id.file_id(), it.ast_id),
}
.intern(db);
let enum_ =
EnumLoc { container: module, id: InFile::new(self.tree_id.file_id(), id) }
.intern(db);
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
update_def(self.def_collector, enum_.into(), &it.name, vis, false);
}
ModItem::Const(id) => {
ModItemId::Const(id) => {
let it = &self.item_tree[id];
let const_id =
ConstLoc { container, id: InFile::new(self.tree_id.file_id(), it.ast_id) }
ConstLoc { container, id: InFile::new(self.tree_id.file_id(), id) }
.intern(db);
match &it.name {
@ -1966,13 +1942,13 @@ impl ModCollector<'_, '_> {
}
}
}
ModItem::Static(id) => {
ModItemId::Static(id) => {
let it = &self.item_tree[id];
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
update_def(
self.def_collector,
StaticLoc { container, id: InFile::new(self.file_id(), it.ast_id) }
StaticLoc { container, id: InFile::new(self.file_id(), id) }
.intern(db)
.into(),
&it.name,
@ -1980,13 +1956,13 @@ impl ModCollector<'_, '_> {
false,
);
}
ModItem::Trait(id) => {
ModItemId::Trait(id) => {
let it = &self.item_tree[id];
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
update_def(
self.def_collector,
TraitLoc { container: module, id: InFile::new(self.file_id(), it.ast_id) }
TraitLoc { container: module, id: InFile::new(self.file_id(), id) }
.intern(db)
.into(),
&it.name,
@ -1994,30 +1970,27 @@ impl ModCollector<'_, '_> {
false,
);
}
ModItem::TraitAlias(id) => {
ModItemId::TraitAlias(id) => {
let it = &self.item_tree[id];
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
update_def(
self.def_collector,
TraitAliasLoc {
container: module,
id: InFile::new(self.file_id(), it.ast_id),
}
.intern(db)
.into(),
TraitAliasLoc { container: module, id: InFile::new(self.file_id(), id) }
.intern(db)
.into(),
&it.name,
vis,
false,
);
}
ModItem::TypeAlias(id) => {
ModItemId::TypeAlias(id) => {
let it = &self.item_tree[id];
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
update_def(
self.def_collector,
TypeAliasLoc { container, id: InFile::new(self.file_id(), it.ast_id) }
TypeAliasLoc { container, id: InFile::new(self.file_id(), id) }
.intern(db)
.into(),
&it.name,
@ -2034,12 +2007,12 @@ impl ModCollector<'_, '_> {
if is_crate_root {
items
.iter()
.filter(|it| matches!(it, ModItem::ExternCrate(..)))
.filter(|it| matches!(it, ModItemId::ExternCrate(..)))
.copied()
.for_each(&mut process_mod_item);
items
.iter()
.filter(|it| !matches!(it, ModItem::ExternCrate(..)))
.filter(|it| !matches!(it, ModItemId::ExternCrate(..)))
.copied()
.for_each(process_mod_item);
} else {
@ -2080,19 +2053,18 @@ impl ModCollector<'_, '_> {
);
}
fn collect_module(&mut self, module_id: FileItemTreeId<Mod>, attrs: &Attrs) {
fn collect_module(&mut self, module_ast_id: ItemTreeAstId<Mod>, attrs: &Attrs) {
let path_attr = attrs.by_key(sym::path).string_value_unescape();
let is_macro_use = attrs.by_key(sym::macro_use).exists();
let module = &self.item_tree[module_id];
let module = &self.item_tree[module_ast_id];
match &module.kind {
// inline module, just recurse
ModKind::Inline { items } => {
let module_id = self.push_child_module(
module.name.clone(),
module.ast_id,
module_ast_id,
None,
&self.item_tree[module.visibility],
module_id,
);
let Some(mod_dir) =
@ -2115,7 +2087,7 @@ impl ModCollector<'_, '_> {
}
// out of line module, resolve, parse and recurse
ModKind::Outline => {
let ast_id = AstId::new(self.file_id(), module.ast_id);
let ast_id = AstId::new(self.file_id(), module_ast_id);
let db = self.def_collector.db;
match self.mod_dir.resolve_declaration(
db,
@ -2134,10 +2106,7 @@ impl ModCollector<'_, '_> {
match is_enabled {
Err(cfg) => {
self.emit_unconfigured_diagnostic(
InFile::new(
self.file_id(),
self.item_tree[module_id].ast_id.erase(),
),
InFile::new(self.file_id(), module_ast_id.erase()),
&cfg,
);
}
@ -2147,14 +2116,13 @@ impl ModCollector<'_, '_> {
ast_id.value,
Some((file_id, is_mod_rs)),
&self.item_tree[module.visibility],
module_id,
);
ModCollector {
def_collector: self.def_collector,
macro_depth: self.macro_depth,
module_id,
tree_id: TreeId::new(file_id.into(), None),
item_tree: &item_tree,
item_tree,
mod_dir,
}
.collect_in_top_module(item_tree.top_level_items());
@ -2175,7 +2143,6 @@ impl ModCollector<'_, '_> {
ast_id.value,
None,
&self.item_tree[module.visibility],
module_id,
);
self.def_collector.def_map.diagnostics.push(
DefDiagnostic::unresolved_module(self.module_id, ast_id, candidates),
@ -2192,7 +2159,6 @@ impl ModCollector<'_, '_> {
declaration: FileAstId<ast::Module>,
definition: Option<(EditionedFileId, bool)>,
visibility: &crate::visibility::RawVisibility,
mod_tree_id: FileItemTreeId<Mod>,
) -> LocalModuleId {
let def_map = &mut self.def_collector.def_map;
let vis = def_map
@ -2205,15 +2171,14 @@ impl ModCollector<'_, '_> {
)
.unwrap_or(Visibility::Public);
let origin = match definition {
None => ModuleOrigin::Inline {
definition: declaration,
definition_tree_id: ItemTreeId::new(self.tree_id, mod_tree_id),
},
None => {
ModuleOrigin::Inline { definition: declaration, definition_tree_id: self.tree_id }
}
Some((definition, is_mod_rs)) => ModuleOrigin::File {
declaration,
definition,
is_mod_rs,
declaration_tree_id: ItemTreeId::new(self.tree_id, mod_tree_id),
declaration_tree_id: self.tree_id,
},
};
@ -2254,11 +2219,14 @@ impl ModCollector<'_, '_> {
fn resolve_attributes(
&mut self,
attrs: &Attrs,
mod_item: ModItem,
mod_item: ModItemId,
container: ItemContainerId,
) -> Result<(), ()> {
let mut ignore_up_to =
self.def_collector.skip_attrs.get(&InFile::new(self.file_id(), mod_item)).copied();
let mut ignore_up_to = self
.def_collector
.skip_attrs
.get(&InFile::new(self.file_id(), mod_item.ast_id()))
.copied();
let iter = attrs
.iter()
.dedup_by(|a, b| {
@ -2288,11 +2256,7 @@ impl ModCollector<'_, '_> {
attr.path.display(self.def_collector.db, Edition::LATEST)
);
let ast_id = AstIdWithPath::new(
self.file_id(),
mod_item.ast_id(self.item_tree),
attr.path.clone(),
);
let ast_id = AstIdWithPath::new(self.file_id(), mod_item.ast_id(), attr.path.clone());
self.def_collector.unresolved_macros.push(MacroDirective {
module_id: self.module_id,
depth: self.macro_depth + 1,
@ -2301,6 +2265,7 @@ impl ModCollector<'_, '_> {
attr: attr.clone(),
mod_item,
tree: self.tree_id,
item_tree: self.item_tree,
},
container,
});
@ -2311,11 +2276,11 @@ impl ModCollector<'_, '_> {
Ok(())
}
fn collect_macro_rules(&mut self, id: FileItemTreeId<MacroRules>, module: ModuleId) {
fn collect_macro_rules(&mut self, ast_id: ItemTreeAstId<MacroRules>, module: ModuleId) {
let krate = self.def_collector.def_map.krate;
let mac = &self.item_tree[id];
let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into());
let ast_id = InFile::new(self.file_id(), mac.ast_id.upcast());
let mac = &self.item_tree[ast_id];
let attrs = self.item_tree.attrs(self.def_collector.db, krate, ast_id.upcast());
let f_ast_id = InFile::new(self.file_id(), ast_id.upcast());
let export_attr = || attrs.by_key(sym::macro_export);
@ -2362,7 +2327,7 @@ impl ModCollector<'_, '_> {
self.def_collector
.def_map
.diagnostics
.push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id));
.push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, f_ast_id));
return;
}
}
@ -2378,16 +2343,13 @@ impl ModCollector<'_, '_> {
let macro_id = MacroRulesLoc {
container: module,
id: InFile::new(self.file_id(), mac.ast_id),
id: InFile::new(self.file_id(), ast_id),
flags,
expander,
edition: self.def_collector.def_map.data.edition,
}
.intern(self.def_collector.db);
self.def_collector.def_map.macro_def_to_macro_id.insert(
InFile::new(self.file_id(), self.item_tree[id].ast_id()).erase(),
macro_id.into(),
);
self.def_collector.def_map.macro_def_to_macro_id.insert(f_ast_id.erase(), macro_id.into());
self.def_collector.define_macro_rules(
self.module_id,
mac.name.clone(),
@ -2396,14 +2358,14 @@ impl ModCollector<'_, '_> {
);
}
fn collect_macro_def(&mut self, id: FileItemTreeId<Macro2>, module: ModuleId) {
fn collect_macro_def(&mut self, ast_id: ItemTreeAstId<Macro2>, module: ModuleId) {
let krate = self.def_collector.def_map.krate;
let mac = &self.item_tree[id];
let ast_id = InFile::new(self.file_id(), mac.ast_id.upcast());
let mac = &self.item_tree[ast_id];
let attrs = self.item_tree.attrs(self.def_collector.db, krate, ast_id.upcast());
let f_ast_id = InFile::new(self.file_id(), ast_id.upcast());
// Case 1: builtin macros
let mut helpers_opt = None;
let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into());
let expander = if attrs.by_key(sym::rustc_builtin_macro).exists() {
if let Some(expander) = find_builtin_macro(&mac.name) {
match expander {
@ -2435,7 +2397,7 @@ impl ModCollector<'_, '_> {
self.def_collector
.def_map
.diagnostics
.push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id));
.push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, f_ast_id));
return;
}
} else {
@ -2446,16 +2408,13 @@ impl ModCollector<'_, '_> {
let macro_id = Macro2Loc {
container: module,
id: InFile::new(self.file_id(), mac.ast_id),
id: InFile::new(self.file_id(), ast_id),
expander,
allow_internal_unsafe,
edition: self.def_collector.def_map.data.edition,
}
.intern(self.def_collector.db);
self.def_collector.def_map.macro_def_to_macro_id.insert(
InFile::new(self.file_id(), self.item_tree[id].ast_id()).erase(),
macro_id.into(),
);
self.def_collector.def_map.macro_def_to_macro_id.insert(f_ast_id.erase(), macro_id.into());
self.def_collector.define_macro_def(
self.module_id,
mac.name.clone(),
@ -2474,9 +2433,10 @@ impl ModCollector<'_, '_> {
fn collect_macro_call(
&mut self,
&MacroCall { ref path, ast_id, expand_to, ctxt }: &MacroCall,
ast_id: FileAstId<ast::MacroCall>,
container: ItemContainerId,
) {
let &MacroCall { ref path, expand_to, ctxt } = &self.item_tree[ast_id];
let ast_id = AstIdWithPath::new(self.file_id(), ast_id, path.clone());
let db = self.def_collector.db;

View file

@ -348,7 +348,7 @@ m!(Z);
assert_eq!(module_data.scope.resolutions().count(), 4);
});
let n_recalculated_item_trees =
events.iter().filter(|it| it.contains("file_item_tree_shim")).count();
events.iter().filter(|it| it.contains("file_item_tree_query")).count();
assert_eq!(n_recalculated_item_trees, 6);
let n_reparsed_macros =
events.iter().filter(|it| it.contains("parse_macro_expansion_shim")).count();
@ -370,7 +370,7 @@ m!(Z);
assert_eq!(module_data.scope.resolutions().count(), 4);
});
let n_recalculated_item_trees =
events.iter().filter(|it| it.contains("file_item_tree_shim")).count();
events.iter().filter(|it| it.contains("file_item_tree_query")).count();
assert_eq!(n_recalculated_item_trees, 1, "{events:#?}");
let n_reparsed_macros =
events.iter().filter(|it| it.contains("parse_macro_expansion_shim")).count();
@ -405,10 +405,10 @@ pub type Ty = ();
db.file_item_tree(pos.file_id.into());
});
let n_calculated_item_trees =
events.iter().filter(|it| it.contains("file_item_tree_shim")).count();
assert_eq!(n_calculated_item_trees, 1);
events.iter().filter(|it| it.contains("file_item_tree_query")).count();
assert_eq!(n_calculated_item_trees, 1, "{events:#?}");
let n_parsed_files = events.iter().filter(|it| it.contains("parse")).count();
assert_eq!(n_parsed_files, 1);
assert_eq!(n_parsed_files, 1, "{events:#?}");
}
// FIXME(salsa-transition): bring this back
@ -446,6 +446,6 @@ pub type Ty = ();
}
});
let n_reparsed_files = events.iter().filter(|it| it.contains("parse(")).count();
assert_eq!(n_reparsed_files, 0);
assert_eq!(n_reparsed_files, 0, "{events:?}");
}
}

View file

@ -156,7 +156,7 @@ pub struct NewStruct {
let expected = vec![
"parse_shim".to_owned(),
"ast_id_map_shim".to_owned(),
"file_item_tree_shim".to_owned(),
"file_item_tree_query".to_owned(),
"real_span_map_shim".to_owned(),
"crate_local_def_map".to_owned(),
"trait_impls_in_crate_shim".to_owned(),
@ -216,7 +216,7 @@ pub enum SomeEnum {
let expected = vec![
"parse_shim".to_owned(),
"ast_id_map_shim".to_owned(),
"file_item_tree_shim".to_owned(),
"file_item_tree_query".to_owned(),
"real_span_map_shim".to_owned(),
"crate_local_def_map".to_owned(),
"trait_impls_in_crate_shim".to_owned(),
@ -273,7 +273,7 @@ fn bar() -> f32 {
let expected = vec![
"parse_shim".to_owned(),
"ast_id_map_shim".to_owned(),
"file_item_tree_shim".to_owned(),
"file_item_tree_query".to_owned(),
"real_span_map_shim".to_owned(),
"crate_local_def_map".to_owned(),
"trait_impls_in_crate_shim".to_owned(),
@ -342,7 +342,7 @@ impl SomeStruct {
let expected = vec![
"parse_shim".to_owned(),
"ast_id_map_shim".to_owned(),
"file_item_tree_shim".to_owned(),
"file_item_tree_query".to_owned(),
"real_span_map_shim".to_owned(),
"crate_local_def_map".to_owned(),
"trait_impls_in_crate_shim".to_owned(),