mod tests;
use std::{
- any::type_name,
fmt::{self, Debug},
hash::{Hash, Hasher},
marker::PhantomData,
- ops::{Index, Range},
+ ops::Index,
sync::Arc,
};
-use ast::{AstNode, NameOwner, StructKind};
+use ast::{AstNode, HasName, StructKind};
use base_db::CrateId;
use either::Either;
use hir_expand::{
ast_id_map::FileAstId,
hygiene::Hygiene,
name::{name, AsName, Name},
- FragmentKind, HirFileId, InFile,
+ ExpandTo, HirFileId, InFile,
};
-use la_arena::{Arena, Idx, RawIdx};
+use la_arena::{Arena, Idx, IdxRange, RawIdx};
use profile::Count;
use rustc_hash::FxHashMap;
use smallvec::SmallVec;
path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind},
type_ref::{Mutability, TraitRef, TypeBound, TypeRef},
visibility::RawVisibility,
+ BlockId,
};
#[derive(Copy, Clone, Eq, PartialEq)]
impl ItemTree {
pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
- let _p = profile::span("item_tree_query").detail(|| format!("{:?}", file_id));
- let syntax = if let Some(node) = db.parse_or_expand(file_id) {
- if node.kind() == SyntaxKind::ERROR {
- // FIXME: not 100% sure why these crop up, but return an empty tree to avoid a panic
- return Default::default();
- }
- node
- } else {
- return Default::default();
+ let _p = profile::span("file_item_tree_query").detail(|| format!("{:?}", file_id));
+ let syntax = match db.parse_or_expand(file_id) {
+ Some(node) => node,
+ None => return Default::default(),
};
+ if syntax.kind() == SyntaxKind::ERROR {
+ // FIXME: not 100% sure why these crop up, but return an empty tree to avoid a panic
+ return Default::default();
+ }
let hygiene = Hygiene::new(db.upcast(), file_id);
let ctx = lower::Ctx::new(db, hygiene.clone(), file_id);
// items.
ctx.lower_macro_stmts(stmts)
},
- ast::Pat(_pat) => {
- // FIXME: This occurs because macros in pattern position are treated as inner
- // items and expanded during block DefMap computation
- return Default::default();
- },
- ast::Type(ty) => {
- // Types can contain inner items. We return an empty item tree in this case, but
- // still need to collect inner items.
- ctx.lower_inner_items(ty.syntax())
- },
- ast::Expr(e) => {
- // Macros can expand to expressions. We return an empty item tree in this case, but
- // still need to collect inner items.
- ctx.lower_inner_items(e.syntax())
- },
_ => {
panic!("cannot create item tree from {:?} {}", syntax, syntax);
},
Arc::new(item_tree)
}
+ fn block_item_tree(db: &dyn DefDatabase, block: BlockId) -> Arc<ItemTree> {
+ let loc = db.lookup_intern_block(block);
+ let block = loc.ast_id.to_node(db.upcast());
+ let hygiene = Hygiene::new(db.upcast(), loc.ast_id.file_id);
+ let ctx = lower::Ctx::new(db, hygiene.clone(), loc.ast_id.file_id);
+ Arc::new(ctx.lower_block(&block))
+ }
+
fn shrink_to_fit(&mut self) {
if let Some(data) = &mut self.data {
let ItemTreeData {
macro_rules,
macro_defs,
vis,
- inner_items,
} = &mut **data;
imports.shrink_to_fit();
macro_defs.shrink_to_fit();
vis.arena.shrink_to_fit();
-
- inner_items.shrink_to_fit();
}
}
self.attrs.get(&of).unwrap_or(&RawAttrs::EMPTY)
}
- pub fn attrs(&self, db: &dyn DefDatabase, krate: CrateId, of: AttrOwner) -> Attrs {
+ pub(crate) fn attrs(&self, db: &dyn DefDatabase, krate: CrateId, of: AttrOwner) -> Attrs {
self.raw_attrs(of).clone().filter(db, krate)
}
- pub fn inner_items_of_block(&self, block: FileAstId<ast::BlockExpr>) -> &[ModItem] {
- match &self.data {
- Some(data) => data.inner_items.get(&block).map(|it| &**it).unwrap_or(&[]),
- None => &[],
- }
- }
-
pub fn pretty_print(&self) -> String {
pretty::print_item_tree(self)
}
macro_defs: Arena<MacroDef>,
vis: ItemVisibilities,
-
- inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>,
}
#[derive(Debug, Eq, PartialEq, Hash)]
}
}
+/// Identifies a particular [`ItemTree`].
+#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
+pub struct TreeId {
+ file: HirFileId,
+ block: Option<BlockId>,
+}
+
+impl TreeId {
+ pub(crate) fn new(file: HirFileId, block: Option<BlockId>) -> Self {
+ Self { file, block }
+ }
+
+ pub(crate) fn item_tree(&self, db: &dyn DefDatabase) -> Arc<ItemTree> {
+ match self.block {
+ Some(block) => ItemTree::block_item_tree(db, block),
+ None => db.file_item_tree(self.file),
+ }
+ }
+
+ pub(crate) fn file_id(self) -> HirFileId {
+ self.file
+ }
+
+ pub(crate) fn is_block(self) -> bool {
+ self.block.is_some()
+ }
+}
+
#[derive(Debug)]
pub struct ItemTreeId<N: ItemTreeNode> {
- file: HirFileId,
+ tree: TreeId,
pub value: FileItemTreeId<N>,
}
impl<N: ItemTreeNode> ItemTreeId<N> {
- pub fn new(file: HirFileId, idx: FileItemTreeId<N>) -> Self {
- Self { file, value: idx }
+ pub fn new(tree: TreeId, idx: FileItemTreeId<N>) -> Self {
+ Self { tree, value: idx }
}
pub fn file_id(self) -> HirFileId {
- self.file
+ self.tree.file
+ }
+
+ pub fn tree_id(self) -> TreeId {
+ self.tree
}
pub fn item_tree(self, db: &dyn DefDatabase) -> Arc<ItemTree> {
- db.file_item_tree(self.file)
+ self.tree.item_tree(db)
}
}
impl<N: ItemTreeNode> PartialEq for ItemTreeId<N> {
fn eq(&self, other: &Self) -> bool {
- self.file == other.file && self.value == other.value
+ self.tree == other.tree && self.value == other.value
}
}
impl<N: ItemTreeNode> Hash for ItemTreeId<N> {
fn hash<H: Hasher>(&self, state: &mut H) {
- self.file.hash(state);
+ self.tree.hash(state);
self.value.hash(state);
}
}
}
fn id_from_mod_item(mod_item: ModItem) -> Option<FileItemTreeId<Self>> {
- if let ModItem::$typ(id) = mod_item {
- Some(id)
- } else {
- None
+ match mod_item {
+ ModItem::$typ(id) => Some(id),
+ _ => None,
}
}
pub struct Function {
pub name: Name,
pub visibility: RawVisibilityId,
- pub generic_params: Interned<GenericParams>,
+ pub explicit_generic_params: Interned<GenericParams>,
pub abi: Option<Interned<str>>,
- pub params: IdRange<Param>,
+ pub params: IdxRange<Param>,
pub ret_type: Interned<TypeRef>,
pub async_ret_type: Option<Interned<TypeRef>>,
pub ast_id: FileAstId<ast::Fn>,
pub name: Name,
pub visibility: RawVisibilityId,
pub generic_params: Interned<GenericParams>,
- pub variants: IdRange<Variant>,
+ pub variants: IdxRange<Variant>,
pub ast_id: FileAstId<ast::Enum>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Const {
- /// const _: () = ();
+ /// `None` for `const _: () = ();`
pub name: Option<Name>,
pub visibility: RawVisibilityId,
pub type_ref: Interned<TypeRef>,
pub name: Name,
pub visibility: RawVisibilityId,
pub mutable: bool,
- /// Whether the static is in an `extern` block.
- pub is_extern: bool,
pub type_ref: Interned<TypeRef>,
pub ast_id: FileAstId<ast::Static>,
}
pub bounds: Box<[Interned<TypeBound>]>,
pub generic_params: Interned<GenericParams>,
pub type_ref: Option<Interned<TypeRef>>,
- pub is_extern: bool,
pub ast_id: FileAstId<ast::TypeAlias>,
}
/// Path to the called macro.
pub path: Interned<ModPath>,
pub ast_id: FileAstId<ast::MacroCall>,
- pub fragment: FragmentKind,
+ pub expand_to: ExpandTo,
}
#[derive(Debug, Clone, Eq, PartialEq)]
}
}
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub enum ImportKind {
+ /// The `ModPath` is imported normally.
+ Plain,
+ /// This is a glob-import of all names in the `ModPath`.
+ Glob,
+ /// This is a `some::path::self` import, which imports `some::path` only in type namespace.
+ TypeOnly,
+}
+
impl UseTree {
/// Expands the `UseTree` into individually imported `ModPath`s.
pub fn expand(
&self,
- mut cb: impl FnMut(Idx<ast::UseTree>, ModPath, /* is_glob */ bool, Option<ImportAlias>),
+ mut cb: impl FnMut(Idx<ast::UseTree>, ModPath, ImportKind, Option<ImportAlias>),
) {
self.expand_impl(None, &mut cb)
}
fn expand_impl(
&self,
prefix: Option<ModPath>,
- cb: &mut dyn FnMut(
- Idx<ast::UseTree>,
- ModPath,
- /* is_glob */ bool,
- Option<ImportAlias>,
- ),
+ cb: &mut dyn FnMut(Idx<ast::UseTree>, ModPath, ImportKind, Option<ImportAlias>),
) {
- fn concat_mod_paths(prefix: Option<ModPath>, path: &ModPath) -> Option<ModPath> {
+ fn concat_mod_paths(
+ prefix: Option<ModPath>,
+ path: &ModPath,
+ ) -> Option<(ModPath, ImportKind)> {
match (prefix, &path.kind) {
- (None, _) => Some(path.clone()),
+ (None, _) => Some((path.clone(), ImportKind::Plain)),
(Some(mut prefix), PathKind::Plain) => {
for segment in path.segments() {
prefix.push_segment(segment.clone());
}
- Some(prefix)
+ Some((prefix, ImportKind::Plain))
}
(Some(prefix), PathKind::Super(0)) => {
// `some::path::self` == `some::path`
if path.segments().is_empty() {
- Some(prefix)
+ Some((prefix, ImportKind::TypeOnly))
} else {
None
}
match &self.kind {
UseTreeKind::Single { path, alias } => {
- if let Some(path) = concat_mod_paths(prefix, path) {
- cb(self.index, path, false, alias.clone());
+ if let Some((path, kind)) = concat_mod_paths(prefix, path) {
+ cb(self.index, path, kind, alias.clone());
}
}
UseTreeKind::Glob { path: Some(path) } => {
- if let Some(path) = concat_mod_paths(prefix, path) {
- cb(self.index, path, true, None);
+ if let Some((path, _)) = concat_mod_paths(prefix, path) {
+ cb(self.index, path, ImportKind::Glob, None);
}
}
UseTreeKind::Glob { path: None } => {
if let Some(prefix) = prefix {
- cb(self.index, prefix, true, None);
+ cb(self.index, prefix, ImportKind::Glob, None);
}
}
UseTreeKind::Prefixed { prefix: additional_prefix, list } => {
let prefix = match additional_prefix {
Some(path) => match concat_mod_paths(prefix, path) {
- Some(path) => Some(path),
- None => return,
+ Some((path, ImportKind::Plain)) => Some(path),
+ _ => return,
},
None => prefix,
};
pub fields: Fields,
}
-/// A range of densely allocated ItemTree IDs.
-pub struct IdRange<T> {
- range: Range<u32>,
- _p: PhantomData<T>,
-}
-
-impl<T> IdRange<T> {
- fn new(range: Range<Idx<T>>) -> Self {
- Self { range: range.start.into_raw().into()..range.end.into_raw().into(), _p: PhantomData }
- }
-
- fn is_empty(&self) -> bool {
- self.range.is_empty()
- }
-}
-
-impl<T> Iterator for IdRange<T> {
- type Item = Idx<T>;
- fn next(&mut self) -> Option<Self::Item> {
- self.range.next().map(|raw| Idx::from_raw(raw.into()))
- }
-}
-
-impl<T> DoubleEndedIterator for IdRange<T> {
- fn next_back(&mut self) -> Option<Self::Item> {
- self.range.next_back().map(|raw| Idx::from_raw(raw.into()))
- }
-}
-
-impl<T> fmt::Debug for IdRange<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_tuple(&format!("IdRange::<{}>", type_name::<T>())).field(&self.range).finish()
- }
-}
-
-impl<T> Clone for IdRange<T> {
- fn clone(&self) -> Self {
- Self { range: self.range.clone(), _p: PhantomData }
- }
-}
-
-impl<T> PartialEq for IdRange<T> {
- fn eq(&self, other: &Self) -> bool {
- self.range == other.range
- }
-}
-
-impl<T> Eq for IdRange<T> {}
-
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Fields {
- Record(IdRange<Field>),
- Tuple(IdRange<Field>),
+ Record(IdxRange<Field>),
+ Tuple(IdxRange<Field>),
Unit,
}