Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/item_scope.rs')
-rw-r--r--crates/hir-def/src/item_scope.rs477
1 files changed, 380 insertions, 97 deletions
diff --git a/crates/hir-def/src/item_scope.rs b/crates/hir-def/src/item_scope.rs
index 873accafb4..7c11fb9d13 100644
--- a/crates/hir-def/src/item_scope.rs
+++ b/crates/hir-def/src/item_scope.rs
@@ -6,6 +6,7 @@ use std::collections::hash_map::Entry;
use base_db::CrateId;
use hir_expand::{attrs::AttrId, db::ExpandDatabase, name::Name, AstId, MacroCallId};
use itertools::Itertools;
+use la_arena::Idx;
use once_cell::sync::Lazy;
use profile::Count;
use rustc_hash::{FxHashMap, FxHashSet};
@@ -15,16 +16,10 @@ use syntax::ast;
use crate::{
db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ConstId,
- ExternCrateId, HasModule, ImplId, LocalModuleId, MacroId, ModuleDefId, ModuleId, TraitId,
- UseId,
+ ExternCrateId, HasModule, ImplId, LocalModuleId, Lookup, MacroId, ModuleDefId, ModuleId,
+ TraitId, UseId,
};
-#[derive(Copy, Clone, Debug)]
-pub(crate) enum ImportType {
- Glob,
- Named,
-}
-
#[derive(Debug, Default)]
pub struct PerNsGlobImports {
types: FxHashSet<(LocalModuleId, Name)>,
@@ -32,15 +27,50 @@ pub struct PerNsGlobImports {
macros: FxHashSet<(LocalModuleId, Name)>,
}
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub enum ImportOrExternCrate {
+ Import(ImportId),
+ ExternCrate(ExternCrateId),
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub(crate) enum ImportType {
+ Import(ImportId),
+ Glob(UseId),
+ ExternCrate(ExternCrateId),
+}
+
+impl ImportOrExternCrate {
+ pub fn into_import(self) -> Option<ImportId> {
+ match self {
+ ImportOrExternCrate::Import(it) => Some(it),
+ _ => None,
+ }
+ }
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub enum ImportOrDef {
+ Import(ImportId),
+ ExternCrate(ExternCrateId),
+ Def(ModuleDefId),
+}
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
+pub struct ImportId {
+ pub import: UseId,
+ pub idx: Idx<ast::UseTree>,
+}
+
#[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, (MacroId, Visibility)>,
+ /// imports. The imports belong to this module and can be resolved by using them on
+ /// the `use_imports_*` fields.
+ types: FxHashMap<Name, (ModuleDefId, Visibility, Option<ImportOrExternCrate>)>,
+ values: FxHashMap<Name, (ModuleDefId, Visibility, Option<ImportId>)>,
+ macros: FxHashMap<Name, (MacroId, Visibility, Option<ImportId>)>,
unresolved: FxHashSet<Name>,
/// The defs declared in this scope. Each def has a single scope where it is
@@ -50,7 +80,14 @@ pub struct ItemScope {
impls: Vec<ImplId>,
unnamed_consts: Vec<ConstId>,
/// Traits imported via `use Trait as _;`.
- unnamed_trait_imports: FxHashMap<TraitId, Visibility>,
+ unnamed_trait_imports: FxHashMap<TraitId, (Visibility, Option<ImportId>)>,
+
+ // the resolutions of the imports of this scope
+ use_imports_types: FxHashMap<ImportOrExternCrate, ImportOrDef>,
+ use_imports_values: FxHashMap<ImportId, ImportOrDef>,
+ use_imports_macros: FxHashMap<ImportId, ImportOrDef>,
+
+ use_decls: Vec<UseId>,
extern_crate_decls: Vec<ExternCrateId>,
/// Macros visible in current module in legacy textual scope
///
@@ -82,7 +119,7 @@ struct DeriveMacroInvocation {
pub(crate) static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| {
BuiltinType::ALL
.iter()
- .map(|(name, ty)| (name.clone(), PerNs::types((*ty).into(), Visibility::Public)))
+ .map(|(name, ty)| (name.clone(), PerNs::types((*ty).into(), Visibility::Public, None)))
.collect()
});
@@ -105,11 +142,77 @@ impl ItemScope {
.chain(self.values.keys())
.chain(self.macros.keys())
.chain(self.unresolved.iter())
- .sorted()
.unique()
+ .sorted()
.map(move |name| (name, self.get(name)))
}
+ pub fn imports(&self) -> impl Iterator<Item = ImportId> + '_ {
+ self.use_imports_types
+ .keys()
+ .copied()
+ .filter_map(ImportOrExternCrate::into_import)
+ .chain(self.use_imports_values.keys().copied())
+ .chain(self.use_imports_macros.keys().copied())
+ .unique()
+ .sorted()
+ }
+
+ pub fn fully_resolve_import(&self, db: &dyn DefDatabase, mut import: ImportId) -> PerNs {
+ let mut res = PerNs::none();
+
+ let mut def_map;
+ let mut scope = self;
+ while let Some(&m) = scope.use_imports_macros.get(&import) {
+ match m {
+ ImportOrDef::Import(i) => {
+ let module_id = i.import.lookup(db).container;
+ def_map = module_id.def_map(db);
+ scope = &def_map[module_id.local_id].scope;
+ import = i;
+ }
+ ImportOrDef::Def(ModuleDefId::MacroId(def)) => {
+ res.macros = Some((def, Visibility::Public, None));
+ break;
+ }
+ _ => break,
+ }
+ }
+ let mut scope = self;
+ while let Some(&m) = scope.use_imports_types.get(&ImportOrExternCrate::Import(import)) {
+ match m {
+ ImportOrDef::Import(i) => {
+ let module_id = i.import.lookup(db).container;
+ def_map = module_id.def_map(db);
+ scope = &def_map[module_id.local_id].scope;
+ import = i;
+ }
+ ImportOrDef::Def(def) => {
+ res.types = Some((def, Visibility::Public, None));
+ break;
+ }
+ _ => break,
+ }
+ }
+ let mut scope = self;
+ while let Some(&m) = scope.use_imports_values.get(&import) {
+ match m {
+ ImportOrDef::Import(i) => {
+ let module_id = i.import.lookup(db).container;
+ def_map = module_id.def_map(db);
+ scope = &def_map[module_id.local_id].scope;
+ import = i;
+ }
+ ImportOrDef::Def(def) => {
+ res.values = Some((def, Visibility::Public, None));
+ break;
+ }
+ _ => break,
+ }
+ }
+ res
+ }
+
pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
self.declarations.iter().copied()
}
@@ -121,8 +224,7 @@ impl ItemScope {
}
pub fn use_decls(&self) -> impl Iterator<Item = UseId> + ExactSizeIterator + '_ {
- // FIXME: to be implemented
- std::iter::empty()
+ self.use_decls.iter().copied()
}
pub fn impls(&self) -> impl Iterator<Item = ImplId> + ExactSizeIterator + '_ {
@@ -132,13 +234,13 @@ impl ItemScope {
pub fn values(
&self,
) -> impl Iterator<Item = (ModuleDefId, Visibility)> + ExactSizeIterator + '_ {
- self.values.values().copied()
+ self.values.values().copied().map(|(a, b, _)| (a, b))
}
- pub fn types(
+ pub(crate) fn types(
&self,
) -> impl Iterator<Item = (ModuleDefId, Visibility)> + ExactSizeIterator + '_ {
- self.types.values().copied()
+ self.types.values().copied().map(|(def, vis, _)| (def, vis))
}
pub fn unnamed_consts(&self) -> impl Iterator<Item = ConstId> + '_ {
@@ -165,33 +267,55 @@ impl ItemScope {
}
pub(crate) fn type_(&self, name: &Name) -> Option<(ModuleDefId, Visibility)> {
- self.types.get(name).copied()
+ self.types.get(name).copied().map(|(a, b, _)| (a, b))
}
/// 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)> {
- let (def, mut iter) = match item {
- ItemInNs::Macros(def) => {
- return self.macros.iter().find_map(|(name, &(other_def, vis))| {
- (other_def == def).then_some((name, vis))
- });
- }
- 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_some((name, vis)))
+ match item {
+ ItemInNs::Macros(def) => self
+ .macros
+ .iter()
+ .find_map(|(name, &(other_def, vis, _))| (other_def == def).then_some((name, vis))),
+ ItemInNs::Types(def) => self
+ .types
+ .iter()
+ .find_map(|(name, &(other_def, vis, _))| (other_def == def).then_some((name, vis))),
+
+ ItemInNs::Values(def) => self
+ .values
+ .iter()
+ .find_map(|(name, &(other_def, vis, _))| (other_def == def).then_some((name, vis))),
+ }
}
pub(crate) fn traits(&self) -> impl Iterator<Item = TraitId> + '_ {
self.types
.values()
- .filter_map(|&(def, _)| match def {
+ .filter_map(|&(def, _, _)| match def {
ModuleDefId::TraitId(t) => Some(t),
_ => None,
})
.chain(self.unnamed_trait_imports.keys().copied())
}
+ pub(crate) fn resolutions(&self) -> impl Iterator<Item = (Option<Name>, PerNs)> + '_ {
+ self.entries().map(|(name, res)| (Some(name.clone()), res)).chain(
+ self.unnamed_trait_imports.iter().map(|(tr, (vis, i))| {
+ (
+ None,
+ PerNs::types(
+ ModuleDefId::TraitId(*tr),
+ *vis,
+ i.map(ImportOrExternCrate::Import),
+ ),
+ )
+ }),
+ )
+ }
+}
+
+impl ItemScope {
pub(crate) fn declare(&mut self, def: ModuleDefId) {
self.declarations.push(def)
}
@@ -277,12 +401,14 @@ impl ItemScope {
})
}
+ // FIXME: This is only used in collection, we should move the relevant parts of it out of ItemScope
pub(crate) fn unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility> {
- self.unnamed_trait_imports.get(&tr).copied()
+ self.unnamed_trait_imports.get(&tr).copied().map(|(a, _)| a)
}
pub(crate) fn push_unnamed_trait(&mut self, tr: TraitId, vis: Visibility) {
- self.unnamed_trait_imports.insert(tr, vis);
+ // FIXME: import
+ self.unnamed_trait_imports.insert(tr, (vis, None));
}
pub(crate) fn push_res_with_import(
@@ -290,51 +416,187 @@ impl ItemScope {
glob_imports: &mut PerNsGlobImports,
lookup: (LocalModuleId, Name),
def: PerNs,
- def_import_type: ImportType,
+ import: Option<ImportType>,
) -> bool {
let mut changed = false;
- macro_rules! check_changed {
- (
- $changed:ident,
- ( $this:ident / $def:ident ) . $field:ident,
- $glob_imports:ident [ $lookup:ident ],
- $def_import_type:ident
- ) => {{
- if let Some(fld) = $def.$field {
- let existing = $this.$field.entry($lookup.1.clone());
- match existing {
- Entry::Vacant(entry) => {
- match $def_import_type {
- ImportType::Glob => {
- $glob_imports.$field.insert($lookup.clone());
+ // FIXME: Document and simplify this
+
+ if let Some(mut fld) = def.types {
+ let existing = self.types.entry(lookup.1.clone());
+ match existing {
+ Entry::Vacant(entry) => {
+ match import {
+ Some(ImportType::Glob(_)) => {
+ glob_imports.types.insert(lookup.clone());
+ }
+ _ => _ = glob_imports.types.remove(&lookup),
+ }
+ let import = match import {
+ Some(ImportType::ExternCrate(extern_crate)) => {
+ Some(ImportOrExternCrate::ExternCrate(extern_crate))
+ }
+ Some(ImportType::Import(import)) => {
+ Some(ImportOrExternCrate::Import(import))
+ }
+ None | Some(ImportType::Glob(_)) => None,
+ };
+ let prev = std::mem::replace(&mut fld.2, import);
+ if let Some(import) = import {
+ self.use_imports_types.insert(
+ import,
+ match prev {
+ Some(ImportOrExternCrate::Import(import)) => {
+ ImportOrDef::Import(import)
}
- ImportType::Named => {
- $glob_imports.$field.remove(&$lookup);
+ Some(ImportOrExternCrate::ExternCrate(import)) => {
+ ImportOrDef::ExternCrate(import)
}
+ None => ImportOrDef::Def(fld.0),
+ },
+ );
+ }
+ entry.insert(fld);
+ changed = true;
+ }
+ Entry::Occupied(mut entry) if !matches!(import, Some(ImportType::Glob(..))) => {
+ if glob_imports.types.remove(&lookup) {
+ let import = match import {
+ Some(ImportType::ExternCrate(extern_crate)) => {
+ Some(ImportOrExternCrate::ExternCrate(extern_crate))
+ }
+ Some(ImportType::Import(import)) => {
+ Some(ImportOrExternCrate::Import(import))
}
+ None | Some(ImportType::Glob(_)) => None,
+ };
+ let prev = std::mem::replace(&mut fld.2, import);
+ if let Some(import) = import {
+ self.use_imports_types.insert(
+ import,
+ match prev {
+ Some(ImportOrExternCrate::Import(import)) => {
+ ImportOrDef::Import(import)
+ }
+ Some(ImportOrExternCrate::ExternCrate(import)) => {
+ ImportOrDef::ExternCrate(import)
+ }
+ None => ImportOrDef::Def(fld.0),
+ },
+ );
+ }
+ cov_mark::hit!(import_shadowed);
+ entry.insert(fld);
+ changed = true;
+ }
+ }
+ _ => {}
+ }
+ }
- entry.insert(fld);
- $changed = true;
+ if let Some(mut fld) = def.values {
+ let existing = self.values.entry(lookup.1.clone());
+ match existing {
+ Entry::Vacant(entry) => {
+ match import {
+ Some(ImportType::Glob(_)) => {
+ glob_imports.values.insert(lookup.clone());
}
- Entry::Occupied(mut entry)
- if matches!($def_import_type, ImportType::Named) =>
- {
- if $glob_imports.$field.remove(&$lookup) {
- cov_mark::hit!(import_shadowed);
- entry.insert(fld);
- $changed = true;
- }
+ _ => _ = glob_imports.values.remove(&lookup),
+ }
+ let import = match import {
+ Some(ImportType::Import(import)) => Some(import),
+ _ => None,
+ };
+ let prev = std::mem::replace(&mut fld.2, import);
+ if let Some(import) = import {
+ self.use_imports_values.insert(
+ import,
+ match prev {
+ Some(import) => ImportOrDef::Import(import),
+ None => ImportOrDef::Def(fld.0),
+ },
+ );
+ }
+ entry.insert(fld);
+ changed = true;
+ }
+ Entry::Occupied(mut entry) if !matches!(import, Some(ImportType::Glob(..))) => {
+ if glob_imports.values.remove(&lookup) {
+ cov_mark::hit!(import_shadowed);
+ let import = match import {
+ Some(ImportType::Import(import)) => Some(import),
+ _ => None,
+ };
+ let prev = std::mem::replace(&mut fld.2, import);
+ if let Some(import) = import {
+ self.use_imports_values.insert(
+ import,
+ match prev {
+ Some(import) => ImportOrDef::Import(import),
+ None => ImportOrDef::Def(fld.0),
+ },
+ );
}
- _ => {}
+ entry.insert(fld);
+ changed = true;
}
}
- }};
+ _ => {}
+ }
}
- 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 let Some(mut fld) = def.macros {
+ let existing = self.macros.entry(lookup.1.clone());
+ match existing {
+ Entry::Vacant(entry) => {
+ match import {
+ Some(ImportType::Glob(_)) => {
+ glob_imports.macros.insert(lookup.clone());
+ }
+ _ => _ = glob_imports.macros.remove(&lookup),
+ }
+ let import = match import {
+ Some(ImportType::Import(import)) => Some(import),
+ _ => None,
+ };
+ let prev = std::mem::replace(&mut fld.2, import);
+ if let Some(import) = import {
+ self.use_imports_macros.insert(
+ import,
+ match prev {
+ Some(import) => ImportOrDef::Import(import),
+ None => ImportOrDef::Def(fld.0.into()),
+ },
+ );
+ }
+ entry.insert(fld);
+ changed = true;
+ }
+ Entry::Occupied(mut entry) if !matches!(import, Some(ImportType::Glob(..))) => {
+ if glob_imports.macros.remove(&lookup) {
+ cov_mark::hit!(import_shadowed);
+ let import = match import {
+ Some(ImportType::Import(import)) => Some(import),
+ _ => None,
+ };
+ let prev = std::mem::replace(&mut fld.2, import);
+ if let Some(import) = import {
+ self.use_imports_macros.insert(
+ import,
+ match prev {
+ Some(import) => ImportOrDef::Import(import),
+ None => ImportOrDef::Def(fld.0.into()),
+ },
+ );
+ }
+ entry.insert(fld);
+ changed = true;
+ }
+ }
+ _ => {}
+ }
+ }
if def.is_none() && self.unresolved.insert(lookup.1) {
changed = true;
@@ -343,27 +605,18 @@ impl ItemScope {
changed
}
- pub(crate) fn resolutions(&self) -> impl Iterator<Item = (Option<Name>, PerNs)> + '_ {
- self.entries().map(|(name, res)| (Some(name.clone()), res)).chain(
- self.unnamed_trait_imports
- .iter()
- .map(|(tr, vis)| (None, PerNs::types(ModuleDefId::TraitId(*tr), *vis))),
- )
- }
-
/// Marks everything that is not a procedural macro as private to `this_module`.
pub(crate) fn censor_non_proc_macros(&mut self, this_module: ModuleId) {
self.types
.values_mut()
- .chain(self.values.values_mut())
+ .map(|(def, vis, _)| (def, vis))
+ .chain(self.values.values_mut().map(|(def, vis, _)| (def, vis)))
.map(|(_, v)| v)
- .chain(self.unnamed_trait_imports.values_mut())
+ .chain(self.unnamed_trait_imports.values_mut().map(|(vis, _)| vis))
.for_each(|vis| *vis = Visibility::Module(this_module));
- for (mac, vis) in self.macros.values_mut() {
- if let MacroId::ProcMacroId(_) = mac {
- // FIXME: Technically this is insufficient since reexports of proc macros are also
- // forbidden. Practically nobody does that.
+ for (mac, vis, import) in self.macros.values_mut() {
+ if matches!(mac, MacroId::ProcMacroId(_) if import.is_none()) {
continue;
}
@@ -382,14 +635,25 @@ impl ItemScope {
name.map_or("_".to_string(), |name| name.display(db).to_string())
);
- if def.types.is_some() {
+ if let Some((.., i)) = def.types {
buf.push_str(" t");
+ match i {
+ Some(ImportOrExternCrate::Import(_)) => buf.push('i'),
+ Some(ImportOrExternCrate::ExternCrate(_)) => buf.push('e'),
+ None => (),
+ }
}
- if def.values.is_some() {
+ if let Some((.., i)) = def.values {
buf.push_str(" v");
+ if i.is_some() {
+ buf.push('i');
+ }
}
- if def.macros.is_some() {
+ if let Some((.., i)) = def.macros {
buf.push_str(" m");
+ if i.is_some() {
+ buf.push('i');
+ }
}
if def.is_none() {
buf.push_str(" _");
@@ -415,10 +679,17 @@ impl ItemScope {
attr_macros,
derive_macros,
extern_crate_decls,
+ use_decls,
+ use_imports_values,
+ use_imports_types,
+ use_imports_macros,
} = self;
types.shrink_to_fit();
values.shrink_to_fit();
macros.shrink_to_fit();
+ use_imports_types.shrink_to_fit();
+ use_imports_values.shrink_to_fit();
+ use_imports_macros.shrink_to_fit();
unresolved.shrink_to_fit();
declarations.shrink_to_fit();
impls.shrink_to_fit();
@@ -428,32 +699,44 @@ impl ItemScope {
attr_macros.shrink_to_fit();
derive_macros.shrink_to_fit();
extern_crate_decls.shrink_to_fit();
+ use_decls.shrink_to_fit();
}
}
impl PerNs {
- pub(crate) fn from_def(def: ModuleDefId, v: Visibility, has_constructor: bool) -> PerNs {
+ pub(crate) fn from_def(
+ def: ModuleDefId,
+ v: Visibility,
+ has_constructor: bool,
+ import: Option<ImportOrExternCrate>,
+ ) -> PerNs {
match def {
- ModuleDefId::ModuleId(_) => PerNs::types(def, v),
- ModuleDefId::FunctionId(_) => PerNs::values(def, v),
+ ModuleDefId::ModuleId(_) => PerNs::types(def, v, import),
+ ModuleDefId::FunctionId(_) => {
+ PerNs::values(def, v, import.and_then(ImportOrExternCrate::into_import))
+ }
ModuleDefId::AdtId(adt) => match adt {
- AdtId::UnionId(_) => PerNs::types(def, v),
- AdtId::EnumId(_) => PerNs::types(def, v),
+ AdtId::UnionId(_) => PerNs::types(def, v, import),
+ AdtId::EnumId(_) => PerNs::types(def, v, import),
AdtId::StructId(_) => {
if has_constructor {
- PerNs::both(def, def, v)
+ PerNs::both(def, def, v, import)
} else {
- PerNs::types(def, v)
+ PerNs::types(def, v, import)
}
}
},
- ModuleDefId::EnumVariantId(_) => PerNs::both(def, def, v),
- ModuleDefId::ConstId(_) | ModuleDefId::StaticId(_) => PerNs::values(def, v),
- ModuleDefId::TraitId(_) => PerNs::types(def, v),
- ModuleDefId::TraitAliasId(_) => PerNs::types(def, v),
- ModuleDefId::TypeAliasId(_) => PerNs::types(def, v),
- ModuleDefId::BuiltinType(_) => PerNs::types(def, v),
- ModuleDefId::MacroId(mac) => PerNs::macros(mac, v),
+ ModuleDefId::EnumVariantId(_) => PerNs::both(def, def, v, import),
+ ModuleDefId::ConstId(_) | ModuleDefId::StaticId(_) => {
+ PerNs::values(def, v, import.and_then(ImportOrExternCrate::into_import))
+ }
+ ModuleDefId::TraitId(_) => PerNs::types(def, v, import),
+ ModuleDefId::TraitAliasId(_) => PerNs::types(def, v, import),
+ ModuleDefId::TypeAliasId(_) => PerNs::types(def, v, import),
+ ModuleDefId::BuiltinType(_) => PerNs::types(def, v, import),
+ ModuleDefId::MacroId(mac) => {
+ PerNs::macros(mac, v, import.and_then(ImportOrExternCrate::into_import))
+ }
}
}
}