]> git.lizzy.rs Git - rust.git/blobdiff - crates/hir_def/src/item_tree.rs
parameters.split_last()
[rust.git] / crates / hir_def / src / item_tree.rs
index 26621b8c7ebbafccce1bf81c7a9d6345306290a2..0af5d654af7e3a476ac5b5f64999ec5af392b79d 100644 (file)
 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::{
     name::{name, AsName, Name},
     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;
+use stdx::never;
 use syntax::{ast, match_ast, SyntaxKind};
 
 use crate::{
@@ -105,24 +105,22 @@ pub struct ItemTree {
 
 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 never!(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);
+        let ctx = lower::Ctx::new(db, 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, &hygiene));
+                    top_attrs = Some(RawAttrs::new(db, &file, ctx.hygiene()));
                     ctx.lower_module_items(&file)
                 },
                 ast::MacroItems(items) => {
@@ -133,21 +131,6 @@ pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) ->
                     // 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);
                 },
@@ -161,6 +144,13 @@ pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) ->
         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 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 {
@@ -184,7 +174,6 @@ fn shrink_to_fit(&mut self) {
                 macro_rules,
                 macro_defs,
                 vis,
-                inner_items,
             } = &mut **data;
 
             imports.shrink_to_fit();
@@ -208,8 +197,6 @@ fn shrink_to_fit(&mut self) {
             macro_defs.shrink_to_fit();
 
             vis.arena.shrink_to_fit();
-
-            inner_items.shrink_to_fit();
         }
     }
 
@@ -228,17 +215,10 @@ pub(crate) fn raw_attrs(&self, of: AttrOwner) -> &RawAttrs {
         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)
     }
@@ -298,8 +278,6 @@ struct ItemTreeData {
     macro_defs: Arena<MacroDef>,
 
     vis: ItemVisibilities,
-
-    inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>,
 }
 
 #[derive(Debug, Eq, PartialEq, Hash)]
@@ -389,7 +367,7 @@ pub(crate) fn new(file: HirFileId, block: Option<BlockId>) -> Self {
 
     pub(crate) fn item_tree(&self, db: &dyn DefDatabase) -> Arc<ItemTree> {
         match self.block {
-            Some(_) => unreachable!("per-block ItemTrees are not yet implemented"),
+            Some(block) => ItemTree::block_item_tree(db, block),
             None => db.file_item_tree(self.file),
         }
     }
@@ -397,6 +375,10 @@ pub(crate) fn item_tree(&self, db: &dyn DefDatabase) -> Arc<ItemTree> {
     pub(crate) fn file_id(self) -> HirFileId {
         self.file
     }
+
+    pub(crate) fn is_block(self) -> bool {
+        self.block.is_some()
+    }
 }
 
 #[derive(Debug)]
@@ -475,10 +457,9 @@ fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self {
                 }
 
                 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,
                     }
                 }
 
@@ -605,9 +586,9 @@ pub struct ExternBlock {
 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>,
@@ -616,7 +597,7 @@ pub struct Function {
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub enum Param {
-    Normal(Interned<TypeRef>),
+    Normal(Option<Name>, Interned<TypeRef>),
     Varargs,
 }
 
@@ -660,13 +641,13 @@ pub struct Enum {
     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>,
@@ -678,8 +659,6 @@ pub struct Static {
     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>,
 }
@@ -713,7 +692,6 @@ pub struct TypeAlias {
     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>,
 }
 
@@ -812,14 +790,26 @@ fn concat_mod_paths(
                     }
                     Some((prefix, ImportKind::Plain))
                 }
-                (Some(prefix), PathKind::Super(0)) => {
-                    // `some::path::self` == `some::path`
-                    if path.segments().is_empty() {
-                        Some((prefix, ImportKind::TypeOnly))
-                    } else {
-                        None
+                (Some(mut prefix), PathKind::Super(n))
+                    if *n > 0 && prefix.segments().is_empty() =>
+                {
+                    // `super::super` + `super::rest`
+                    match &mut prefix.kind {
+                        PathKind::Super(m) => {
+                            cov_mark::hit!(concat_super_mod_paths);
+                            *m += *n;
+                            for segment in path.segments() {
+                                prefix.push_segment(segment.clone());
+                            }
+                            Some((prefix, ImportKind::Plain))
+                        }
+                        _ => None,
                     }
                 }
+                (Some(prefix), PathKind::Super(0)) if path.segments().is_empty() => {
+                    // `some::path::self` == `some::path`
+                    Some((prefix, ImportKind::TypeOnly))
+                }
                 (Some(_), _) => None,
             }
         }
@@ -942,65 +932,27 @@ fn from(item: AssocItem) -> Self {
     }
 }
 
+impl AssocItem {
+    pub fn ast_id(self, tree: &ItemTree) -> FileAstId<ast::AssocItem> {
+        match self {
+            AssocItem::Function(id) => tree[id].ast_id.upcast(),
+            AssocItem::TypeAlias(id) => tree[id].ast_id.upcast(),
+            AssocItem::Const(id) => tree[id].ast_id.upcast(),
+            AssocItem::MacroCall(id) => tree[id].ast_id.upcast(),
+        }
+    }
+}
+
 #[derive(Debug, Eq, PartialEq)]
 pub struct Variant {
     pub name: Name,
     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,
 }