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)]
#[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
// 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()
});
}
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 + '_ {
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
}
}
+ /// 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 {
.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> {
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<ast::Item>, call: MacroCallId) {
+ self.attr_macros.insert(item, call);
+ }
+
+ 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 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);
+ }
+ }
+ }
+
+ /// 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()
}
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
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 {
}
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),