]> git.lizzy.rs Git - rust.git/blobdiff - crates/hir_def/src/item_scope.rs
Replaced fold with for loop
[rust.git] / crates / hir_def / src / item_scope.rs
index 919933813928c5e043ff862bf5ef2dd924a3f1b5..258d1e0f6c5191a5c17cd97b5d3ef3ef31943344 100644 (file)
@@ -4,15 +4,17 @@
 use std::collections::hash_map::Entry;
 
 use base_db::CrateId;
-use hir_expand::name::Name;
-use hir_expand::MacroDefKind;
+use hir_expand::{name::Name, AstId, MacroCallId, MacroDefKind};
 use once_cell::sync::Lazy;
+use profile::Count;
 use rustc_hash::{FxHashMap, FxHashSet};
+use smallvec::{smallvec, SmallVec};
 use stdx::format_to;
+use syntax::ast;
 
 use crate::{
-    db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ImplId,
-    LocalModuleId, MacroDefId, ModuleDefId, ModuleId, TraitId,
+    attr::AttrId, db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType,
+    ConstId, ImplId, LocalModuleId, MacroDefId, ModuleDefId, ModuleId, TraitId,
 };
 
 #[derive(Copy, Clone)]
@@ -30,13 +32,22 @@ pub struct PerNsGlobImports {
 
 #[derive(Debug, Default, PartialEq, Eq)]
 pub struct ItemScope {
+    _c: Count<Self>,
+
+    /// Defs visible in this scope. This includes `declarations`, but also
+    /// imports.
     types: FxHashMap<Name, (ModuleDefId, Visibility)>,
     values: FxHashMap<Name, (ModuleDefId, Visibility)>,
     macros: FxHashMap<Name, (MacroDefId, Visibility)>,
     unresolved: FxHashSet<Name>,
 
-    defs: Vec<ModuleDefId>,
+    /// The defs declared in this scope. Each def has a single scope where it is
+    /// declared.
+    declarations: Vec<ModuleDefId>,
+    macro_declarations: Vec<MacroDefId>,
+
     impls: Vec<ImplId>,
+    unnamed_consts: Vec<ConstId>,
     /// Traits imported via `use Trait as _;`.
     unnamed_trait_imports: FxHashMap<TraitId, Visibility>,
     /// Macros visible in current module in legacy textual scope
@@ -52,12 +63,17 @@ pub struct ItemScope {
     // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
     // be all resolved to the last one defined if shadowing happens.
     legacy_macros: FxHashMap<Name, MacroDefId>,
+    attr_macros: FxHashMap<AstId<ast::Item>, MacroCallId>,
+    /// The derive macro invocations in this scope, keyed by the owner item over the actual derive attributes
+    /// paired with the derive macro invocations for the specific attribute.
+    derive_macros:
+        FxHashMap<AstId<ast::Adt>, SmallVec<[(AttrId, SmallVec<[Option<MacroCallId>; 1]>); 1]>>,
 }
 
 pub(crate) static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| {
     BuiltinType::ALL
         .iter()
-        .map(|(name, ty)| (name.clone(), PerNs::types(ty.clone().into(), Visibility::Public)))
+        .map(|(name, ty)| (name.clone(), PerNs::types((*ty).into(), Visibility::Public)))
         .collect()
 });
 
@@ -87,7 +103,11 @@ pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
     }
 
     pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
-        self.defs.iter().copied()
+        self.declarations.iter().copied()
+    }
+
+    pub fn macro_declarations(&self) -> impl Iterator<Item = MacroDefId> + '_ {
+        self.macro_declarations.iter().copied()
     }
 
     pub fn impls(&self) -> impl Iterator<Item = ImplId> + ExactSizeIterator + '_ {
@@ -100,10 +120,8 @@ pub fn values(
         self.values.values().copied()
     }
 
-    pub fn visibility_of(&self, def: ModuleDefId) -> Option<Visibility> {
-        self.name_of(ItemInNs::Types(def))
-            .or_else(|| self.name_of(ItemInNs::Values(def)))
-            .map(|(_, v)| v)
+    pub fn unnamed_consts(&self) -> impl Iterator<Item = ConstId> + '_ {
+        self.unnamed_consts.iter().copied()
     }
 
     /// Iterate over all module scoped macros
@@ -125,13 +143,19 @@ pub(crate) fn get(&self, name: &Name) -> PerNs {
         }
     }
 
+    /// XXX: this is O(N) rather than O(1), try to not introduce new usages.
     pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> {
-        for (name, per_ns) in self.entries() {
-            if let Some(vis) = item.match_with(per_ns) {
-                return Some((name, vis));
+        let (def, mut iter) = match item {
+            ItemInNs::Macros(def) => {
+                return self
+                    .macros
+                    .iter()
+                    .find_map(|(name, &(other_def, vis))| (other_def == def).then(|| (name, vis)));
             }
-        }
-        None
+            ItemInNs::Types(def) => (def, self.types.iter()),
+            ItemInNs::Values(def) => (def, self.values.iter()),
+        };
+        iter.find_map(|(name, &(other_def, vis))| (other_def == def).then(|| (name, vis)))
     }
 
     pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a {
@@ -144,8 +168,12 @@ pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a {
             .chain(self.unnamed_trait_imports.keys().copied())
     }
 
-    pub(crate) fn define_def(&mut self, def: ModuleDefId) {
-        self.defs.push(def)
+    pub(crate) fn declare(&mut self, def: ModuleDefId) {
+        self.declarations.push(def)
+    }
+
+    pub(crate) fn declare_macro(&mut self, def: MacroDefId) {
+        self.macro_declarations.push(def);
     }
 
     pub(crate) fn get_legacy_macro(&self, name: &Name) -> Option<MacroDefId> {
@@ -156,47 +184,66 @@ pub(crate) fn define_impl(&mut self, imp: ImplId) {
         self.impls.push(imp)
     }
 
+    pub(crate) fn define_unnamed_const(&mut self, konst: ConstId) {
+        self.unnamed_consts.push(konst);
+    }
+
     pub(crate) fn define_legacy_macro(&mut self, name: Name, mac: MacroDefId) {
         self.legacy_macros.insert(name, mac);
     }
 
-    pub(crate) fn unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility> {
-        self.unnamed_trait_imports.get(&tr).copied()
+    pub(crate) fn add_attr_macro_invoc(&mut self, item: AstId<ast::Item>, call: MacroCallId) {
+        self.attr_macros.insert(item, call);
     }
 
-    pub(crate) fn push_unnamed_trait(&mut self, tr: TraitId, vis: Visibility) {
-        self.unnamed_trait_imports.insert(tr, vis);
+    pub(crate) fn attr_macro_invocs(
+        &self,
+    ) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ {
+        self.attr_macros.iter().map(|(k, v)| (*k, *v))
     }
 
-    pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool {
-        let mut changed = false;
-
-        if let Some(types) = def.types {
-            self.types.entry(name.clone()).or_insert_with(|| {
-                changed = true;
-                types
-            });
-        }
-        if let Some(values) = def.values {
-            self.values.entry(name.clone()).or_insert_with(|| {
-                changed = true;
-                values
-            });
-        }
-        if let Some(macros) = def.macros {
-            self.macros.entry(name.clone()).or_insert_with(|| {
-                changed = true;
-                macros
-            });
-        }
-
-        if def.is_none() {
-            if self.unresolved.insert(name) {
-                changed = true;
+    pub(crate) fn set_derive_macro_invoc(
+        &mut self,
+        adt: AstId<ast::Adt>,
+        call: MacroCallId,
+        attr_id: AttrId,
+        idx: usize,
+    ) {
+        if let Some(derives) = self.derive_macros.get_mut(&adt) {
+            if let Some((_, invocs)) = derives.iter_mut().find(|&&mut (id, _)| id == attr_id) {
+                invocs[idx] = Some(call);
             }
         }
+    }
 
-        changed
+    /// We are required to set this up front as derive invocation recording happens out of order
+    /// due to the fixed pointer iteration loop being able to record some derives later than others
+    /// independent of their indices.
+    pub(crate) fn init_derive_attribute(
+        &mut self,
+        adt: AstId<ast::Adt>,
+        attr_id: AttrId,
+        len: usize,
+    ) {
+        self.derive_macros.entry(adt).or_default().push((attr_id, smallvec![None; len]));
+    }
+
+    pub(crate) fn derive_macro_invocs(
+        &self,
+    ) -> impl Iterator<
+        Item = (AstId<ast::Adt>, impl Iterator<Item = (AttrId, &[Option<MacroCallId>])>),
+    > + '_ {
+        self.derive_macros
+            .iter()
+            .map(|(k, v)| (*k, v.iter().map(|(attr_id, invocs)| (*attr_id, &**invocs))))
+    }
+
+    pub(crate) fn unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility> {
+        self.unnamed_trait_imports.get(&tr).copied()
+    }
+
+    pub(crate) fn push_unnamed_trait(&mut self, tr: TraitId, vis: Visibility) {
+        self.unnamed_trait_imports.insert(tr, vis);
     }
 
     pub(crate) fn push_res_with_import(
@@ -252,10 +299,8 @@ macro_rules! check_changed {
         check_changed!(changed, (self / def).values, glob_imports[lookup], def_import_type);
         check_changed!(changed, (self / def).macros, glob_imports[lookup], def_import_type);
 
-        if def.is_none() {
-            if self.unresolved.insert(lookup.1) {
-                changed = true;
-            }
+        if def.is_none() && self.unresolved.insert(lookup.1) {
+            changed = true;
         }
 
         changed
@@ -283,7 +328,7 @@ pub(crate) fn censor_non_proc_macros(&mut self, this_module: ModuleId) {
             .for_each(|vis| *vis = Visibility::Module(this_module));
 
         for (mac, vis) in self.macros.values_mut() {
-            if let MacroDefKind::ProcMacro(_) = mac.kind {
+            if let MacroDefKind::ProcMacro(..) = mac.kind {
                 // FIXME: Technically this is insufficient since reexports of proc macros are also
                 // forbidden. Practically nobody does that.
                 continue;
@@ -316,6 +361,37 @@ pub(crate) fn dump(&self, buf: &mut String) {
             buf.push('\n');
         }
     }
+
+    pub(crate) fn shrink_to_fit(&mut self) {
+        // Exhaustive match to require handling new fields.
+        let Self {
+            _c: _,
+            types,
+            values,
+            macros,
+            unresolved,
+            declarations,
+            macro_declarations,
+            impls,
+            unnamed_consts,
+            unnamed_trait_imports,
+            legacy_macros,
+            attr_macros,
+            derive_macros,
+        } = self;
+        types.shrink_to_fit();
+        values.shrink_to_fit();
+        macros.shrink_to_fit();
+        unresolved.shrink_to_fit();
+        declarations.shrink_to_fit();
+        macro_declarations.shrink_to_fit();
+        impls.shrink_to_fit();
+        unnamed_consts.shrink_to_fit();
+        unnamed_trait_imports.shrink_to_fit();
+        legacy_macros.shrink_to_fit();
+        attr_macros.shrink_to_fit();
+        derive_macros.shrink_to_fit();
+    }
 }
 
 impl PerNs {
@@ -351,20 +427,6 @@ pub enum ItemInNs {
 }
 
 impl ItemInNs {
-    fn match_with(self, per_ns: PerNs) -> Option<Visibility> {
-        match self {
-            ItemInNs::Types(def) => {
-                per_ns.types.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
-            }
-            ItemInNs::Values(def) => {
-                per_ns.values.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
-            }
-            ItemInNs::Macros(def) => {
-                per_ns.macros.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
-            }
-        }
-    }
-
     pub fn as_module_def_id(self) -> Option<ModuleDefId> {
         match self {
             ItemInNs::Types(id) | ItemInNs::Values(id) => Some(id),