diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs index 4d446c7073b..beeb9855954 100644 --- a/crates/ra_hir_def/src/item_scope.rs +++ b/crates/ra_hir_def/src/item_scope.rs @@ -1,6 +1,8 @@ //! Describes items defined or visible (ie, imported) in a certain scope. //! This is shared between modules and blocks. +use std::collections::hash_map::Entry; + use hir_expand::name::Name; use once_cell::sync::Lazy; use ra_db::CrateId; @@ -27,7 +29,11 @@ pub struct PerNsGlobImports { #[derive(Debug, Default, PartialEq, Eq)] pub struct ItemScope { - visible: FxHashMap, + types: FxHashMap, + values: FxHashMap, + macros: FxHashMap, + unresolved: FxHashSet, + defs: Vec, impls: Vec, /// Macros visible in current module in legacy textual scope @@ -65,14 +71,16 @@ pub(crate) enum BuiltinShadowMode { /// Other methods will only resolve values, types and module scoped macros only. impl ItemScope { pub fn entries<'a>(&'a self) -> impl Iterator + 'a { - //FIXME: shadowing - self.visible.iter().map(|(n, def)| (n, *def)) - } + // FIXME: shadowing + let keys: FxHashSet<_> = self + .types + .keys() + .chain(self.values.keys()) + .chain(self.macros.keys()) + .chain(self.unresolved.iter()) + .collect(); - pub fn entries_without_primitives<'a>( - &'a self, - ) -> impl Iterator + 'a { - self.visible.iter().map(|(n, def)| (n, *def)) + keys.into_iter().map(move |name| (name, self.get(name))) } pub fn declarations(&self) -> impl Iterator + '_ { @@ -91,7 +99,7 @@ impl ItemScope { /// Iterate over all module scoped macros pub(crate) fn macros<'a>(&'a self) -> impl Iterator + 'a { - self.visible.iter().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_))) + self.entries().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_))) } /// Iterate over all legacy textual scoped macros visible at the end of the module @@ -101,12 +109,16 @@ impl ItemScope { /// Get a name from current module scope, legacy macros are not included pub(crate) fn get(&self, name: &Name) -> PerNs { - self.visible.get(name).copied().unwrap_or_else(PerNs::none) + PerNs { + types: self.types.get(name).copied(), + values: self.values.get(name).copied(), + macros: self.macros.get(name).copied(), + } } pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> { - for (name, per_ns) in &self.visible { - if let Some(vis) = item.match_with(*per_ns) { + for (name, per_ns) in self.entries() { + if let Some(vis) = item.match_with(per_ns) { return Some((name, vis)); } } @@ -114,8 +126,8 @@ impl ItemScope { } pub(crate) fn traits<'a>(&'a self) -> impl Iterator + 'a { - self.visible.values().filter_map(|def| match def.take_types() { - Some(ModuleDefId::TraitId(t)) => Some(t), + self.types.values().filter_map(|(def, _)| match def { + ModuleDefId::TraitId(t) => Some(*t), _ => None, }) } @@ -138,21 +150,30 @@ impl ItemScope { pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool { let mut changed = false; - let existing = self.visible.entry(name).or_default(); - if existing.types.is_none() && def.types.is_some() { - existing.types = def.types; - changed = true; + 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 existing.values.is_none() && def.values.is_some() { - existing.values = def.values; - changed = true; - } - - if existing.macros.is_none() && def.macros.is_some() { - existing.macros = def.macros; - changed = true; + if def.is_none() { + if self.unresolved.insert(name) { + changed = true; + } } changed @@ -166,17 +187,17 @@ impl ItemScope { def_import_type: ImportType, ) -> bool { let mut changed = false; - let existing = self.visible.entry(lookup.1.clone()).or_default(); macro_rules! check_changed { ( $changed:ident, - ( $existing:ident / $def:ident ) . $field:ident, + ( $this:ident / $def:ident ) . $field:ident, $glob_imports:ident [ $lookup:ident ], $def_import_type:ident - ) => { - match ($existing.$field, $def.$field) { - (None, Some(_)) => { + ) => {{ + let existing = $this.$field.entry($lookup.1.clone()); + match (existing, $def.$field) { + (Entry::Vacant(entry), Some(_)) => { match $def_import_type { ImportType::Glob => { $glob_imports.$field.insert($lookup.clone()); @@ -186,32 +207,42 @@ impl ItemScope { } } - $existing.$field = $def.$field; + if let Some(fld) = $def.$field { + entry.insert(fld); + } $changed = true; } - (Some(_), Some(_)) + (Entry::Occupied(mut entry), Some(_)) if $glob_imports.$field.contains(&$lookup) && matches!($def_import_type, ImportType::Named) => { mark::hit!(import_shadowed); $glob_imports.$field.remove(&$lookup); - $existing.$field = $def.$field; + if let Some(fld) = $def.$field { + entry.insert(fld); + } $changed = true; } _ => {} } - }; + }}; } - check_changed!(changed, (existing / def).types, glob_imports[lookup], def_import_type); - check_changed!(changed, (existing / def).values, glob_imports[lookup], def_import_type); - check_changed!(changed, (existing / def).macros, glob_imports[lookup], def_import_type); + check_changed!(changed, (self / def).types, glob_imports[lookup], def_import_type); + 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; + } + } changed } pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator + 'a { - self.visible.iter().map(|(name, res)| (name.clone(), *res)) + self.entries().map(|(name, res)| (name.clone(), res)) } pub(crate) fn collect_legacy_macros(&self) -> FxHashMap { diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs index 15fdd9019b7..0bf51eb7b83 100644 --- a/crates/ra_hir_def/src/resolver.rs +++ b/crates/ra_hir_def/src/resolver.rs @@ -511,11 +511,9 @@ impl Scope { }); } } - Scope::LocalItemsScope(body) => { - body.item_scope.entries_without_primitives().for_each(|(name, def)| { - f(name.clone(), ScopeDef::PerNs(def)); - }) - } + Scope::LocalItemsScope(body) => body.item_scope.entries().for_each(|(name, def)| { + f(name.clone(), ScopeDef::PerNs(def)); + }), Scope::GenericParams { params, def } => { for (local_id, param) in params.types.iter() { if let Some(name) = ¶m.name {