]> git.lizzy.rs Git - rust.git/blobdiff - crates/hir_def/src/item_tree.rs
Use block_def_map in body lowering
[rust.git] / crates / hir_def / src / item_tree.rs
index 100dbf5d6571ced6fcae71ef81722b2ecc244c74..4bde676490ec2a613a3cc548dddf0e08b6f790bc 100644 (file)
@@ -11,7 +11,6 @@
     sync::Arc,
 };
 
-use arena::{Arena, Idx, RawId};
 use ast::{AstNode, NameOwner, StructKind};
 use base_db::CrateId;
 use either::Either;
     name::{name, AsName, Name},
     HirFileId, InFile,
 };
+use la_arena::{Arena, Idx, RawIdx};
+use profile::Count;
 use rustc_hash::FxHashMap;
 use smallvec::SmallVec;
-use syntax::{ast, match_ast};
+use syntax::{ast, match_ast, SyntaxKind};
 use test_utils::mark;
 
 use crate::{
@@ -65,22 +66,27 @@ impl GenericParamsId {
 }
 
 /// The item tree of a source file.
-#[derive(Debug, Eq, PartialEq)]
+#[derive(Debug, Default, Eq, PartialEq)]
 pub struct ItemTree {
+    _c: Count<Self>,
+
     top_level: SmallVec<[ModItem; 1]>,
     attrs: FxHashMap<AttrOwner, RawAttrs>,
-    inner_items: FxHashMap<FileAstId<ast::Item>, SmallVec<[ModItem; 1]>>,
 
     data: Option<Box<ItemTreeData>>,
 }
 
 impl ItemTree {
-    pub fn item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
+    pub(crate) fn 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 Arc::new(Self::empty());
+            return Default::default();
         };
 
         let hygiene = Hygiene::new(db.upcast(), file_id);
@@ -96,15 +102,17 @@ pub fn item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree
                     ctx.lower_module_items(&items)
                 },
                 ast::MacroStmts(stmts) => {
-                    ctx.lower_inner_items(stmts.syntax())
+                    // The produced statements can include items, which should be added as top-level
+                    // items.
+                    ctx.lower_macro_stmts(stmts)
                 },
-                // Macros can expand to expressions. We return an empty item tree in this case, but
-                // still need to collect inner items.
                 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);
+                    panic!("cannot create item tree from {:?} {}", syntax, syntax);
                 },
             }
         };
@@ -116,15 +124,6 @@ pub fn item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree
         Arc::new(item_tree)
     }
 
-    fn empty() -> Self {
-        Self {
-            top_level: Default::default(),
-            attrs: Default::default(),
-            inner_items: Default::default(),
-            data: Default::default(),
-        }
-    }
-
     fn shrink_to_fit(&mut self) {
         if let Some(data) = &mut self.data {
             let ItemTreeData {
@@ -145,9 +144,9 @@ fn shrink_to_fit(&mut self) {
                 macro_calls,
                 macro_rules,
                 macro_defs,
-                exprs,
                 vis,
                 generics,
+                inner_items,
             } = &mut **data;
 
             imports.shrink_to_fit();
@@ -167,10 +166,11 @@ fn shrink_to_fit(&mut self) {
             macro_calls.shrink_to_fit();
             macro_rules.shrink_to_fit();
             macro_defs.shrink_to_fit();
-            exprs.shrink_to_fit();
 
             vis.arena.shrink_to_fit();
             generics.arena.shrink_to_fit();
+
+            inner_items.shrink_to_fit();
         }
     }
 
@@ -193,16 +193,18 @@ pub fn attrs(&self, db: &dyn DefDatabase, krate: CrateId, of: AttrOwner) -> Attr
         self.raw_attrs(of).clone().filter(db, krate)
     }
 
-    /// Returns the lowered inner items that `ast` corresponds to.
-    ///
-    /// Most AST items are lowered to a single `ModItem`, but some (eg. `use` items) may be lowered
-    /// to multiple items in the `ItemTree`.
-    pub fn inner_items(&self, ast: FileAstId<ast::Item>) -> &[ModItem] {
-        &self.inner_items[&ast]
+    pub fn all_inner_items(&self) -> impl Iterator<Item = ModItem> + '_ {
+        match &self.data {
+            Some(data) => Some(data.inner_items.values().flatten().copied()).into_iter().flatten(),
+            None => None.into_iter().flatten(),
+        }
     }
 
-    pub fn all_inner_items(&self) -> impl Iterator<Item = ModItem> + '_ {
-        self.inner_items.values().flatten().copied()
+    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 source<S: ItemTreeNode>(&self, db: &dyn DefDatabase, of: ItemTreeId<S>) -> S::Source {
@@ -260,6 +262,7 @@ impl GenericParamsStorage {
     fn alloc(&mut self, params: GenericParams) -> GenericParamsId {
         if params.types.is_empty()
             && params.lifetimes.is_empty()
+            && params.consts.is_empty()
             && params.where_predicates.is_empty()
         {
             return GenericParamsId::EMPTY;
@@ -269,8 +272,12 @@ fn alloc(&mut self, params: GenericParams) -> GenericParamsId {
     }
 }
 
-static EMPTY_GENERICS: GenericParams =
-    GenericParams { types: Arena::new(), lifetimes: Arena::new(), where_predicates: Vec::new() };
+static EMPTY_GENERICS: GenericParams = GenericParams {
+    types: Arena::new(),
+    lifetimes: Arena::new(),
+    consts: Arena::new(),
+    where_predicates: Vec::new(),
+};
 
 #[derive(Default, Debug, Eq, PartialEq)]
 struct ItemTreeData {
@@ -291,10 +298,11 @@ struct ItemTreeData {
     macro_calls: Arena<MacroCall>,
     macro_rules: Arena<MacroRules>,
     macro_defs: Arena<MacroDef>,
-    exprs: Arena<Expr>,
 
     vis: ItemVisibilities,
     generics: GenericParamsStorage,
+
+    inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>,
 }
 
 #[derive(Debug, Eq, PartialEq, Hash)]
@@ -456,7 +464,7 @@ fn index(&self, index: Idx<$t>) -> &Self::Output {
     };
 }
 
-impl_index!(fields: Field, variants: Variant, exprs: Expr);
+impl_index!(fields: Field, variants: Variant);
 
 impl Index<RawVisibilityId> for ItemTree {
     type Output = RawVisibility;
@@ -659,11 +667,6 @@ pub struct MacroDef {
     pub ast_id: FileAstId<ast::MacroDef>,
 }
 
-// NB: There's no `FileAstId` for `Expr`. The only case where this would be useful is for array
-// lengths, but we don't do much with them yet.
-#[derive(Debug, Clone, Eq, PartialEq)]
-pub struct Expr;
-
 macro_rules! impl_froms {
     ($e:ident { $($v:ident ($t:ty)),* $(,)? }) => {
         $(