1 //! Describes items defined or visible (ie, imported) in a certain scope.
2 //! This is shared between modules and blocks.
4 use std::collections::hash_map::Entry;
7 use hir_expand::name::Name;
8 use once_cell::sync::Lazy;
9 use rustc_hash::{FxHashMap, FxHashSet};
13 db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, HasModule, ImplId,
14 LocalModuleId, Lookup, MacroDefId, ModuleDefId, TraitId,
17 #[derive(Copy, Clone)]
18 pub(crate) enum ImportType {
23 #[derive(Debug, Default)]
24 pub struct PerNsGlobImports {
25 types: FxHashSet<(LocalModuleId, Name)>,
26 values: FxHashSet<(LocalModuleId, Name)>,
27 macros: FxHashSet<(LocalModuleId, Name)>,
30 #[derive(Debug, Default, PartialEq, Eq)]
31 pub struct ItemScope {
32 types: FxHashMap<Name, (ModuleDefId, Visibility)>,
33 values: FxHashMap<Name, (ModuleDefId, Visibility)>,
34 macros: FxHashMap<Name, (MacroDefId, Visibility)>,
35 unresolved: FxHashSet<Name>,
37 defs: Vec<ModuleDefId>,
39 /// Traits imported via `use Trait as _;`.
40 unnamed_trait_imports: FxHashMap<TraitId, Visibility>,
41 /// Macros visible in current module in legacy textual scope
43 /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first.
44 /// If it yields no result, then it turns to module scoped `macros`.
45 /// It macros with name qualified with a path like `crate::foo::bar!()`, `legacy_macros` will be skipped,
46 /// and only normal scoped `macros` will be searched in.
48 /// Note that this automatically inherit macros defined textually before the definition of module itself.
50 /// Module scoped macros will be inserted into `items` instead of here.
51 // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
52 // be all resolved to the last one defined if shadowing happens.
53 legacy_macros: FxHashMap<Name, MacroDefId>,
56 pub(crate) static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| {
59 .map(|(name, ty)| (name.clone(), PerNs::types(ty.clone().into(), Visibility::Public)))
63 /// Shadow mode for builtin type which can be shadowed by module.
64 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
65 pub(crate) enum BuiltinShadowMode {
66 /// Prefer user-defined modules (or other types) over builtins.
68 /// Prefer builtins over user-defined modules (but not other types).
72 /// Legacy macros can only be accessed through special methods like `get_legacy_macros`.
73 /// Other methods will only resolve values, types and module scoped macros only.
75 pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
77 let keys: FxHashSet<_> = self
80 .chain(self.values.keys())
81 .chain(self.macros.keys())
82 .chain(self.unresolved.iter())
85 keys.into_iter().map(move |name| (name, self.get(name)))
88 pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
89 self.defs.iter().copied()
92 pub fn impls(&self) -> impl Iterator<Item = ImplId> + ExactSizeIterator + '_ {
93 self.impls.iter().copied()
96 pub fn visibility_of(&self, def: ModuleDefId) -> Option<Visibility> {
97 self.name_of(ItemInNs::Types(def))
98 .or_else(|| self.name_of(ItemInNs::Values(def)))
102 /// Iterate over all module scoped macros
103 pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
104 self.entries().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_)))
107 /// Iterate over all legacy textual scoped macros visible at the end of the module
108 pub(crate) fn legacy_macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
109 self.legacy_macros.iter().map(|(name, def)| (name, *def))
112 /// Get a name from current module scope, legacy macros are not included
113 pub(crate) fn get(&self, name: &Name) -> PerNs {
115 types: self.types.get(name).copied(),
116 values: self.values.get(name).copied(),
117 macros: self.macros.get(name).copied(),
121 pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> {
122 for (name, per_ns) in self.entries() {
123 if let Some(vis) = item.match_with(per_ns) {
124 return Some((name, vis));
130 pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a {
133 .filter_map(|(def, _)| match def {
134 ModuleDefId::TraitId(t) => Some(*t),
137 .chain(self.unnamed_trait_imports.keys().copied())
140 pub(crate) fn define_def(&mut self, def: ModuleDefId) {
144 pub(crate) fn get_legacy_macro(&self, name: &Name) -> Option<MacroDefId> {
145 self.legacy_macros.get(name).copied()
148 pub(crate) fn define_impl(&mut self, imp: ImplId) {
152 pub(crate) fn define_legacy_macro(&mut self, name: Name, mac: MacroDefId) {
153 self.legacy_macros.insert(name, mac);
156 pub(crate) fn unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility> {
157 self.unnamed_trait_imports.get(&tr).copied()
160 pub(crate) fn push_unnamed_trait(&mut self, tr: TraitId, vis: Visibility) {
161 self.unnamed_trait_imports.insert(tr, vis);
164 pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool {
165 let mut changed = false;
167 if let Some(types) = def.types {
168 self.types.entry(name.clone()).or_insert_with(|| {
173 if let Some(values) = def.values {
174 self.values.entry(name.clone()).or_insert_with(|| {
179 if let Some(macros) = def.macros {
180 self.macros.entry(name.clone()).or_insert_with(|| {
187 if self.unresolved.insert(name) {
195 pub(crate) fn push_res_with_import(
197 glob_imports: &mut PerNsGlobImports,
198 lookup: (LocalModuleId, Name),
200 def_import_type: ImportType,
202 let mut changed = false;
204 macro_rules! check_changed {
207 ( $this:ident / $def:ident ) . $field:ident,
208 $glob_imports:ident [ $lookup:ident ],
209 $def_import_type:ident
211 let existing = $this.$field.entry($lookup.1.clone());
212 match (existing, $def.$field) {
213 (Entry::Vacant(entry), Some(_)) => {
214 match $def_import_type {
215 ImportType::Glob => {
216 $glob_imports.$field.insert($lookup.clone());
218 ImportType::Named => {
219 $glob_imports.$field.remove(&$lookup);
223 if let Some(fld) = $def.$field {
228 (Entry::Occupied(mut entry), Some(_))
229 if $glob_imports.$field.contains(&$lookup)
230 && matches!($def_import_type, ImportType::Named) =>
232 mark::hit!(import_shadowed);
233 $glob_imports.$field.remove(&$lookup);
234 if let Some(fld) = $def.$field {
244 check_changed!(changed, (self / def).types, glob_imports[lookup], def_import_type);
245 check_changed!(changed, (self / def).values, glob_imports[lookup], def_import_type);
246 check_changed!(changed, (self / def).macros, glob_imports[lookup], def_import_type);
249 if self.unresolved.insert(lookup.1) {
257 pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Option<Name>, PerNs)> + 'a {
258 self.entries().map(|(name, res)| (Some(name.clone()), res)).chain(
259 self.unnamed_trait_imports
261 .map(|(tr, vis)| (None, PerNs::types(ModuleDefId::TraitId(*tr), *vis))),
265 pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> {
266 self.legacy_macros.clone()
271 pub(crate) fn from_def(def: ModuleDefId, v: Visibility, has_constructor: bool) -> PerNs {
273 ModuleDefId::ModuleId(_) => PerNs::types(def, v),
274 ModuleDefId::FunctionId(_) => PerNs::values(def, v),
275 ModuleDefId::AdtId(adt) => match adt {
276 AdtId::UnionId(_) => PerNs::types(def, v),
277 AdtId::EnumId(_) => PerNs::types(def, v),
278 AdtId::StructId(_) => {
280 PerNs::both(def, def, v)
286 ModuleDefId::EnumVariantId(_) => PerNs::both(def, def, v),
287 ModuleDefId::ConstId(_) | ModuleDefId::StaticId(_) => PerNs::values(def, v),
288 ModuleDefId::TraitId(_) => PerNs::types(def, v),
289 ModuleDefId::TypeAliasId(_) => PerNs::types(def, v),
290 ModuleDefId::BuiltinType(_) => PerNs::types(def, v),
295 #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
303 fn match_with(self, per_ns: PerNs) -> Option<Visibility> {
305 ItemInNs::Types(def) => {
306 per_ns.types.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
308 ItemInNs::Values(def) => {
309 per_ns.values.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
311 ItemInNs::Macros(def) => {
312 per_ns.macros.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
317 pub fn as_module_def_id(self) -> Option<ModuleDefId> {
319 ItemInNs::Types(id) | ItemInNs::Values(id) => Some(id),
320 ItemInNs::Macros(_) => None,
324 /// Returns the crate defining this item (or `None` if `self` is built-in).
325 pub fn krate(&self, db: &dyn DefDatabase) -> Option<CrateId> {
327 ItemInNs::Types(did) | ItemInNs::Values(did) => match did {
328 ModuleDefId::ModuleId(id) => id.krate,
329 ModuleDefId::FunctionId(id) => id.lookup(db).module(db).krate,
330 ModuleDefId::AdtId(id) => id.module(db).krate,
331 ModuleDefId::EnumVariantId(id) => id.parent.lookup(db).container.module(db).krate,
332 ModuleDefId::ConstId(id) => id.lookup(db).container.module(db).krate,
333 ModuleDefId::StaticId(id) => id.lookup(db).container.module(db).krate,
334 ModuleDefId::TraitId(id) => id.lookup(db).container.module(db).krate,
335 ModuleDefId::TypeAliasId(id) => id.lookup(db).module(db).krate,
336 ModuleDefId::BuiltinType(_) => return None,
338 ItemInNs::Macros(id) => return id.krate,