X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=crates%2Fhir_def%2Fsrc%2Fitem_scope.rs;h=258d1e0f6c5191a5c17cd97b5d3ef3ef31943344;hb=0db0dec9993b510efeb61cb1d8ff113270d4ca51;hp=aafd73b606d18046f475914546220056212132b9;hpb=9a5c72d9f07760fe875ef653a956fcaa1fe5d0de;p=rust.git diff --git a/crates/hir_def/src/item_scope.rs b/crates/hir_def/src/item_scope.rs index aafd73b606d..258d1e0f6c5 100644 --- a/crates/hir_def/src/item_scope.rs +++ b/crates/hir_def/src/item_scope.rs @@ -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, + + /// Defs visible in this scope. This includes `declarations`, but also + /// imports. types: FxHashMap, values: FxHashMap, macros: FxHashMap, unresolved: FxHashSet, - defs: Vec, + /// The defs declared in this scope. Each def has a single scope where it is + /// declared. + declarations: Vec, + macro_declarations: Vec, + impls: Vec, + unnamed_consts: Vec, /// Traits imported via `use Trait as _;`. unnamed_trait_imports: FxHashMap, /// 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, + attr_macros: FxHashMap, 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, SmallVec<[(AttrId, SmallVec<[Option; 1]>); 1]>>, } pub(crate) static BUILTIN_SCOPE: Lazy> = 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 + 'a { } pub fn declarations(&self) -> impl Iterator + '_ { - self.defs.iter().copied() + self.declarations.iter().copied() + } + + pub fn macro_declarations(&self) -> impl Iterator + '_ { + self.macro_declarations.iter().copied() } pub fn impls(&self) -> impl Iterator + ExactSizeIterator + '_ { @@ -100,10 +120,8 @@ pub fn values( self.values.values().copied() } - pub fn visibility_of(&self, def: ModuleDefId) -> Option { - self.name_of(ItemInNs::Types(def)) - .or_else(|| self.name_of(ItemInNs::Values(def))) - .map(|(_, v)| v) + pub fn unnamed_consts(&self) -> impl Iterator + '_ { + 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 + 'a { @@ -144,8 +168,12 @@ pub(crate) fn traits<'a>(&'a self) -> impl Iterator + '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 { @@ -156,10 +184,60 @@ 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 add_attr_macro_invoc(&mut self, item: AstId, call: MacroCallId) { + self.attr_macros.insert(item, call); + } + + pub(crate) fn attr_macro_invocs( + &self, + ) -> impl Iterator, MacroCallId)> + '_ { + self.attr_macros.iter().map(|(k, v)| (*k, *v)) + } + + pub(crate) fn set_derive_macro_invoc( + &mut self, + adt: AstId, + 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); + } + } + } + + /// 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, + 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, impl Iterator])>), + > + '_ { + 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 { self.unnamed_trait_imports.get(&tr).copied() } @@ -221,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 @@ -252,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; @@ -285,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 { @@ -320,20 +427,6 @@ pub enum ItemInNs { } impl ItemInNs { - fn match_with(self, per_ns: PerNs) -> Option { - 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 { match self { ItemInNs::Types(id) | ItemInNs::Values(id) => Some(id),