about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/hir-def/src/attr.rs10
-rw-r--r--crates/hir-def/src/body/lower.rs4
-rw-r--r--crates/hir-def/src/db.rs3
-rw-r--r--crates/hir-def/src/item_tree.rs21
-rw-r--r--crates/hir-def/src/item_tree/lower.rs3
-rw-r--r--crates/hir-def/src/nameres.rs49
-rw-r--r--crates/hir-def/src/nameres/collector.rs18
-rw-r--r--crates/hir-expand/src/attrs.rs9
-rw-r--r--crates/hir-expand/src/lib.rs5
-rw-r--r--crates/hir-ty/src/mir/lower.rs4
-rw-r--r--crates/hir/src/lib.rs20
-rw-r--r--crates/syntax/src/ast/node_ext.rs8
12 files changed, 81 insertions, 73 deletions
diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs
index fae07111806..a5db75a91eb 100644
--- a/crates/hir-def/src/attr.rs
+++ b/crates/hir-def/src/attr.rs
@@ -431,12 +431,10 @@ impl AttrsWithOwner {
                         .item_tree(db)
                         .raw_attrs(AttrOwner::ModItem(definition_tree_id.value.into()))
                         .clone(),
-                    ModuleOrigin::BlockExpr { block } => RawAttrs::from_attrs_owner(
-                        db.upcast(),
-                        InFile::new(block.file_id, block.to_node(db.upcast()))
-                            .as_ref()
-                            .map(|it| it as &dyn ast::HasAttrs),
-                    ),
+                    ModuleOrigin::BlockExpr { id, .. } => {
+                        let tree = db.block_item_tree_query(id);
+                        tree.raw_attrs(AttrOwner::TopLevel).clone()
+                    }
                 }
             }
             AttrDefId::FieldId(it) => {
diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs
index 3853a6ab3a5..889544e151f 100644
--- a/crates/hir-def/src/body/lower.rs
+++ b/crates/hir-def/src/body/lower.rs
@@ -1100,7 +1100,9 @@ impl ExprCollector<'_> {
                 ast::Stmt::ExprStmt(es) => matches!(es.expr(), Some(ast::Expr::MacroExpr(_))),
                 _ => false,
             });
-            statement_has_item || matches!(block.tail_expr(), Some(ast::Expr::MacroExpr(_)))
+            statement_has_item
+                || matches!(block.tail_expr(), Some(ast::Expr::MacroExpr(_)))
+                || (block.may_carry_attributes() && block.attrs().next().is_some())
         };
 
         let block_id = if block_has_items {
diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs
index e34a6768f28..31c1a713031 100644
--- a/crates/hir-def/src/db.rs
+++ b/crates/hir-def/src/db.rs
@@ -82,6 +82,9 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
     #[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_query(&self, block_id: BlockId) -> Arc<ItemTree>;
+
     #[salsa::invoke(crate_def_map_wait)]
     #[salsa::transparent]
     fn crate_def_map(&self, krate: CrateId) -> Arc<DefMap>;
diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs
index 1495cc68e3f..957a5cf2e2b 100644
--- a/crates/hir-def/src/item_tree.rs
+++ b/crates/hir-def/src/item_tree.rs
@@ -68,7 +68,7 @@ use crate::{
     path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind},
     type_ref::{Mutability, TraitRef, TypeBound, TypeRef},
     visibility::RawVisibility,
-    BlockId,
+    BlockId, Lookup,
 };
 
 #[derive(Copy, Clone, Eq, PartialEq)]
@@ -143,6 +143,16 @@ impl ItemTree {
         Arc::new(item_tree)
     }
 
+    pub(crate) fn block_item_tree_query(db: &dyn DefDatabase, block: BlockId) -> Arc<ItemTree> {
+        let loc = block.lookup(db);
+        let block = loc.ast_id.to_node(db.upcast());
+
+        let ctx = lower::Ctx::new(db, loc.ast_id.file_id);
+        let mut item_tree = ctx.lower_block(&block);
+        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] {
@@ -178,13 +188,6 @@ impl ItemTree {
         self.data.get_or_insert_with(Box::default)
     }
 
-    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 ctx = lower::Ctx::new(db, 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 {
@@ -382,7 +385,7 @@ impl TreeId {
 
     pub(crate) fn item_tree(&self, db: &dyn DefDatabase) -> Arc<ItemTree> {
         match self.block {
-            Some(block) => ItemTree::block_item_tree(db, block),
+            Some(block) => db.block_item_tree_query(block),
             None => db.file_item_tree(self.file),
         }
     }
diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs
index e719f9291bd..f8efc802234 100644
--- a/crates/hir-def/src/item_tree/lower.rs
+++ b/crates/hir-def/src/item_tree/lower.rs
@@ -77,6 +77,9 @@ impl<'a> Ctx<'a> {
     }
 
     pub(super) fn lower_block(mut self, block: &ast::BlockExpr) -> ItemTree {
+        self.tree
+            .attrs
+            .insert(AttrOwner::TopLevel, RawAttrs::new(self.db.upcast(), block, self.hygiene()));
         self.tree.top_level = block
             .statements()
             .filter_map(|stmt| match stmt {
diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs
index 5c99f691a64..f93125e224d 100644
--- a/crates/hir-def/src/nameres.rs
+++ b/crates/hir-def/src/nameres.rs
@@ -60,7 +60,7 @@ mod tests;
 use std::{cmp::Ord, ops::Deref};
 
 use base_db::{CrateId, Edition, FileId, ProcMacroKind};
-use hir_expand::{name::Name, HirFileId, InFile, MacroCallId, MacroDefId};
+use hir_expand::{ast_id_map::FileAstId, name::Name, HirFileId, InFile, MacroCallId, MacroDefId};
 use itertools::Itertools;
 use la_arena::Arena;
 use profile::Count;
@@ -217,16 +217,17 @@ pub enum ModuleOrigin {
     /// Note that non-inline modules, by definition, live inside non-macro file.
     File {
         is_mod_rs: bool,
-        declaration: AstId<ast::Module>,
+        declaration: FileAstId<ast::Module>,
         declaration_tree_id: ItemTreeId<Mod>,
         definition: FileId,
     },
     Inline {
         definition_tree_id: ItemTreeId<Mod>,
-        definition: AstId<ast::Module>,
+        definition: FileAstId<ast::Module>,
     },
     /// Pseudo-module introduced by a block scope (contains only inner items).
     BlockExpr {
+        id: BlockId,
         block: AstId<ast::BlockExpr>,
     },
 }
@@ -234,8 +235,12 @@ pub enum ModuleOrigin {
 impl ModuleOrigin {
     pub fn declaration(&self) -> Option<AstId<ast::Module>> {
         match self {
-            ModuleOrigin::File { declaration: module, .. }
-            | ModuleOrigin::Inline { definition: module, .. } => Some(*module),
+            &ModuleOrigin::File { declaration, declaration_tree_id, .. } => {
+                Some(AstId::new(declaration_tree_id.file_id(), declaration))
+            }
+            &ModuleOrigin::Inline { definition, definition_tree_id } => {
+                Some(AstId::new(definition_tree_id.file_id(), definition))
+            }
             ModuleOrigin::CrateRoot { .. } | ModuleOrigin::BlockExpr { .. } => None,
         }
     }
@@ -260,16 +265,17 @@ impl ModuleOrigin {
     /// That is, a file or a `mod foo {}` with items.
     fn definition_source(&self, db: &dyn DefDatabase) -> InFile<ModuleSource> {
         match self {
-            ModuleOrigin::File { definition, .. } | ModuleOrigin::CrateRoot { definition } => {
-                let file_id = *definition;
-                let sf = db.parse(file_id).tree();
-                InFile::new(file_id.into(), ModuleSource::SourceFile(sf))
+            &ModuleOrigin::File { definition, .. } | &ModuleOrigin::CrateRoot { definition } => {
+                let sf = db.parse(definition).tree();
+                InFile::new(definition.into(), ModuleSource::SourceFile(sf))
             }
-            ModuleOrigin::Inline { definition, .. } => InFile::new(
-                definition.file_id,
-                ModuleSource::Module(definition.to_node(db.upcast())),
+            &ModuleOrigin::Inline { definition, definition_tree_id } => InFile::new(
+                definition_tree_id.file_id(),
+                ModuleSource::Module(
+                    AstId::new(definition_tree_id.file_id(), definition).to_node(db.upcast()),
+                ),
             ),
-            ModuleOrigin::BlockExpr { block } => {
+            ModuleOrigin::BlockExpr { block, .. } => {
                 InFile::new(block.file_id, ModuleSource::BlockExpr(block.to_node(db.upcast())))
             }
         }
@@ -314,9 +320,7 @@ impl DefMap {
     }
 
     pub(crate) fn block_def_map_query(db: &dyn DefDatabase, block_id: BlockId) -> Arc<DefMap> {
-        let block: BlockLoc = db.lookup_intern_block(block_id);
-
-        let tree_id = TreeId::new(block.ast_id.file_id, Some(block_id));
+        let block: BlockLoc = block_id.lookup(db);
 
         let parent_map = block.module.def_map(db);
         let krate = block.module.krate;
@@ -325,8 +329,10 @@ impl DefMap {
         // modules declared by blocks with items. At the moment, we don't use
         // this visibility for anything outside IDE, so that's probably OK.
         let visibility = Visibility::Module(ModuleId { krate, local_id, block: None });
-        let module_data =
-            ModuleData::new(ModuleOrigin::BlockExpr { block: block.ast_id }, visibility);
+        let module_data = ModuleData::new(
+            ModuleOrigin::BlockExpr { block: block.ast_id, id: block_id },
+            visibility,
+        );
 
         let mut def_map = DefMap::empty(krate, parent_map.data.edition, module_data);
         def_map.data = parent_map.data.clone();
@@ -338,7 +344,8 @@ impl DefMap {
             },
         });
 
-        let def_map = collector::collect_defs(db, def_map, tree_id);
+        let def_map =
+            collector::collect_defs(db, def_map, TreeId::new(block.ast_id.file_id, Some(block_id)));
         Arc::new(def_map)
     }
 
@@ -642,8 +649,8 @@ impl ModuleData {
             ModuleOrigin::File { definition, .. } | ModuleOrigin::CrateRoot { definition } => {
                 definition.into()
             }
-            ModuleOrigin::Inline { definition, .. } => definition.file_id,
-            ModuleOrigin::BlockExpr { block } => block.file_id,
+            ModuleOrigin::Inline { definition_tree_id, .. } => definition_tree_id.file_id(),
+            ModuleOrigin::BlockExpr { block, .. } => block.file_id,
         }
     }
 
diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index 92d5cdd09bd..e3253404d49 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -53,9 +53,9 @@ use crate::{
     visibility::{RawVisibility, Visibility},
     AdtId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, EnumVariantId,
     ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId, FunctionLoc, ImplLoc, Intern,
-    ItemContainerId, LocalModuleId, Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId,
-    MacroRulesLoc, ModuleDefId, ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc, StructLoc,
-    TraitAliasLoc, TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro, UseId, UseLoc,
+    ItemContainerId, LocalModuleId, Lookup, Macro2Id, Macro2Loc, MacroExpander, MacroId,
+    MacroRulesId, MacroRulesLoc, ModuleDefId, ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc,
+    StructLoc, TraitAliasLoc, TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro, UseId, UseLoc,
 };
 
 static GLOB_RECURSION_LIMIT: Limit = Limit::new(100);
@@ -1461,7 +1461,7 @@ impl DefCollector<'_> {
         let mut diagnosed_extern_crates = FxHashSet::default();
         for directive in &self.unresolved_imports {
             if let ImportSource::ExternCrate { id } = directive.import.source {
-                let item_tree_id = self.db.lookup_intern_extern_crate(id).id;
+                let item_tree_id = id.lookup(self.db).id;
                 let item_tree = item_tree_id.item_tree(self.db);
                 let extern_crate = &item_tree[item_tree_id.value];
 
@@ -1482,7 +1482,7 @@ impl DefCollector<'_> {
                 ) {
                     continue;
                 }
-                let item_tree_id = self.db.lookup_intern_use(id).id;
+                let item_tree_id = id.lookup(self.db).id;
                 self.def_map.diagnostics.push(DefDiagnostic::unresolved_import(
                     directive.module_id,
                     item_tree_id,
@@ -1843,7 +1843,7 @@ impl ModCollector<'_, '_> {
             ModKind::Inline { items } => {
                 let module_id = self.push_child_module(
                     module.name.clone(),
-                    AstId::new(self.file_id(), module.ast_id),
+                    module.ast_id,
                     None,
                     &self.item_tree[module.visibility],
                     module_id,
@@ -1881,7 +1881,7 @@ impl ModCollector<'_, '_> {
                         if is_enabled {
                             let module_id = self.push_child_module(
                                 module.name.clone(),
-                                ast_id,
+                                ast_id.value,
                                 Some((file_id, is_mod_rs)),
                                 &self.item_tree[module.visibility],
                                 module_id,
@@ -1908,7 +1908,7 @@ impl ModCollector<'_, '_> {
                     Err(candidates) => {
                         self.push_child_module(
                             module.name.clone(),
-                            ast_id,
+                            ast_id.value,
                             None,
                             &self.item_tree[module.visibility],
                             module_id,
@@ -1925,7 +1925,7 @@ impl ModCollector<'_, '_> {
     fn push_child_module(
         &mut self,
         name: Name,
-        declaration: AstId<ast::Module>,
+        declaration: FileAstId<ast::Module>,
         definition: Option<(FileId, bool)>,
         visibility: &crate::visibility::RawVisibility,
         mod_tree_id: FileItemTreeId<Mod>,
diff --git a/crates/hir-expand/src/attrs.rs b/crates/hir-expand/src/attrs.rs
index 4c918e55b92..0ec2422b30c 100644
--- a/crates/hir-expand/src/attrs.rs
+++ b/crates/hir-expand/src/attrs.rs
@@ -342,14 +342,7 @@ fn inner_attributes(
             ast::Impl(it) => it.assoc_item_list()?.syntax().clone(),
             ast::Module(it) => it.item_list()?.syntax().clone(),
             ast::BlockExpr(it) => {
-                use syntax::SyntaxKind::{BLOCK_EXPR , EXPR_STMT};
-                // Block expressions accept outer and inner attributes, but only when they are the outer
-                // expression of an expression statement or the final expression of another block expression.
-                let may_carry_attributes = matches!(
-                    it.syntax().parent().map(|it| it.kind()),
-                     Some(BLOCK_EXPR | EXPR_STMT)
-                );
-                if !may_carry_attributes {
+                if !it.may_carry_attributes() {
                     return None
                 }
                 syntax.clone()
diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs
index 1f1e20f49e3..ba14553d90e 100644
--- a/crates/hir-expand/src/lib.rs
+++ b/crates/hir-expand/src/lib.rs
@@ -544,7 +544,7 @@ impl MacroCallKind {
         };
 
         let range = match kind {
-            MacroCallKind::FnLike { ast_id, .. } => ast_id.to_node(db).syntax().text_range(),
+            MacroCallKind::FnLike { ast_id, .. } => ast_id.to_ptr(db).text_range(),
             MacroCallKind::Derive { ast_id, derive_attr_index, .. } => {
                 // FIXME: should be the range of the macro name, not the whole derive
                 // FIXME: handle `cfg_attr`
@@ -840,9 +840,6 @@ impl<N: AstIdNode> AstId<N> {
 pub type ErasedAstId = InFile<ErasedFileAstId>;
 
 impl ErasedAstId {
-    pub fn to_node(&self, db: &dyn db::ExpandDatabase) -> SyntaxNode {
-        self.to_ptr(db).to_node(&db.parse_or_expand(self.file_id))
-    }
     pub fn to_ptr(&self, db: &dyn db::ExpandDatabase) -> SyntaxNodePtr {
         db.ast_id_map(self.file_id).get_raw(self.value)
     }
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index 9eaa9e1c2f5..7ab0c1f7f2f 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -15,7 +15,7 @@ use hir_def::{
     path::Path,
     resolver::{resolver_for_expr, HasResolver, ResolveValueResult, ValueNs},
     AdtId, DefWithBodyId, EnumVariantId, GeneralConstId, HasModule, ItemContainerId, LocalFieldId,
-    TraitId, TypeOrConstParamId,
+    Lookup, TraitId, TypeOrConstParamId,
 };
 use hir_expand::name::Name;
 use la_arena::ArenaMap;
@@ -372,7 +372,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
         match &self.body.exprs[expr_id] {
             Expr::Missing => {
                 if let DefWithBodyId::FunctionId(f) = self.owner {
-                    let assoc = self.db.lookup_intern_function(f);
+                    let assoc = f.lookup(self.db.upcast());
                     if let ItemContainerId::TraitId(t) = assoc.container {
                         let name = &self.db.function_data(f).name;
                         return Err(MirLowerError::TraitFunctionDefinition(t, name.clone()));
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index b1c00d816f8..46def6c052f 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -719,20 +719,18 @@ fn emit_def_diagnostic_(
 ) {
     match diag {
         DefDiagnosticKind::UnresolvedModule { ast: declaration, candidates } => {
-            let decl = declaration.to_node(db.upcast());
+            let decl = declaration.to_ptr(db.upcast());
             acc.push(
                 UnresolvedModule {
-                    decl: InFile::new(declaration.file_id, AstPtr::new(&decl)),
+                    decl: InFile::new(declaration.file_id, decl),
                     candidates: candidates.clone(),
                 }
                 .into(),
             )
         }
         DefDiagnosticKind::UnresolvedExternCrate { ast } => {
-            let item = ast.to_node(db.upcast());
-            acc.push(
-                UnresolvedExternCrate { decl: InFile::new(ast.file_id, AstPtr::new(&item)) }.into(),
-            );
+            let item = ast.to_ptr(db.upcast());
+            acc.push(UnresolvedExternCrate { decl: InFile::new(ast.file_id, item) }.into());
         }
 
         DefDiagnosticKind::UnresolvedImport { id, index } => {
@@ -747,14 +745,10 @@ fn emit_def_diagnostic_(
         }
 
         DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } => {
-            let item = ast.to_node(db.upcast());
+            let item = ast.to_ptr(db.upcast());
             acc.push(
-                InactiveCode {
-                    node: ast.with_value(SyntaxNodePtr::new(&item).into()),
-                    cfg: cfg.clone(),
-                    opts: opts.clone(),
-                }
-                .into(),
+                InactiveCode { node: ast.with_value(item), cfg: cfg.clone(), opts: opts.clone() }
+                    .into(),
             );
         }
         DefDiagnosticKind::UnresolvedProcMacro { ast, krate } => {
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index 3308077da5b..691d0c618f3 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -61,6 +61,14 @@ impl ast::BlockExpr {
     pub fn tail_expr(&self) -> Option<ast::Expr> {
         self.stmt_list()?.tail_expr()
     }
+    /// Block expressions accept outer and inner attributes, but only when they are the outer
+    /// expression of an expression statement or the final expression of another block expression.
+    pub fn may_carry_attributes(&self) -> bool {
+        matches!(
+            self.syntax().parent().map(|it| it.kind()),
+            Some(SyntaxKind::BLOCK_EXPR | SyntaxKind::EXPR_STMT)
+        )
+    }
 }
 
 #[derive(Debug, PartialEq, Eq, Clone)]