mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-11 16:15:03 +00:00
remove ItemMap
This commit is contained in:
parent
71e5adf694
commit
c7259a899c
@ -173,7 +173,7 @@ impl Module {
|
||||
|
||||
/// Returns a `ModuleScope`: a set of items, visible in this module.
|
||||
pub fn scope(&self, db: &impl HirDatabase) -> ModuleScope {
|
||||
db.item_map(self.krate)[self.module_id].clone()
|
||||
db.crate_def_map(self.krate)[self.module_id].scope.clone()
|
||||
}
|
||||
|
||||
pub fn problems(&self, db: &impl HirDatabase) -> Vec<(TreeArc<SyntaxNode>, Problem)> {
|
||||
@ -181,8 +181,8 @@ impl Module {
|
||||
}
|
||||
|
||||
pub fn resolver(&self, db: &impl HirDatabase) -> Resolver {
|
||||
let item_map = db.item_map(self.krate);
|
||||
Resolver::default().push_module_scope(item_map, *self)
|
||||
let def_map = db.crate_def_map(self.krate);
|
||||
Resolver::default().push_module_scope(def_map, self.module_id)
|
||||
}
|
||||
|
||||
pub fn declarations(self, db: &impl HirDatabase) -> Vec<ModuleDef> {
|
||||
|
@ -10,7 +10,7 @@ use crate::{
|
||||
Struct, Enum, StructField,
|
||||
Const, ConstSignature, Static,
|
||||
macros::MacroExpansion,
|
||||
nameres::{Namespace, ItemMap, lower::{LoweredModule, ImportSourceMap}, crate_def_map::{RawItems, CrateDefMap}},
|
||||
nameres::{Namespace, lower::{LoweredModule, ImportSourceMap}, crate_def_map::{RawItems, CrateDefMap}},
|
||||
ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef, CallableDef, FnSig},
|
||||
adt::{StructData, EnumData},
|
||||
impl_block::{ModuleImplBlocks, ImplSourceMap},
|
||||
@ -50,9 +50,6 @@ pub trait PersistentHirDatabase: SourceDatabase + AsRef<HirInterner> {
|
||||
#[salsa::invoke(RawItems::raw_items_query)]
|
||||
fn raw_items(&self, file_id: FileId) -> Arc<RawItems>;
|
||||
|
||||
#[salsa::invoke(crate::nameres::ItemMap::item_map_query)]
|
||||
fn item_map(&self, krate: Crate) -> Arc<ItemMap>;
|
||||
|
||||
#[salsa::invoke(CrateDefMap::crate_def_map_query)]
|
||||
fn crate_def_map(&self, krate: Crate) -> Arc<CrateDefMap>;
|
||||
|
||||
|
@ -54,7 +54,7 @@ pub use self::{
|
||||
name::Name,
|
||||
ids::{HirFileId, MacroCallId, MacroCallLoc, HirInterner},
|
||||
macros::{MacroDef, MacroInput, MacroExpansion},
|
||||
nameres::{ItemMap, PerNs, Namespace},
|
||||
nameres::{PerNs, Namespace},
|
||||
ty::{Ty, Substs, display::HirDisplay},
|
||||
impl_block::{ImplBlock, ImplItem},
|
||||
docs::{Docs, Documentation},
|
||||
|
@ -17,43 +17,15 @@
|
||||
pub(crate) mod lower;
|
||||
pub(crate) mod crate_def_map;
|
||||
|
||||
use std::{time, sync::Arc};
|
||||
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use ra_arena::map::ArenaMap;
|
||||
use rustc_hash::FxHashMap;
|
||||
use ra_db::Edition;
|
||||
use test_utils::tested_by;
|
||||
|
||||
use crate::{
|
||||
Module, ModuleDef,
|
||||
Path, PathKind, PersistentHirDatabase,
|
||||
Crate, Name,
|
||||
nameres::{
|
||||
crate_def_map::{CrateDefMap, ModuleId},
|
||||
lower::{ImportId, LoweredModule, ImportData}
|
||||
},
|
||||
ModuleDef, Name,
|
||||
nameres::lower::ImportId,
|
||||
};
|
||||
|
||||
/// `ItemMap` is the result of module name resolution. It contains, for each
|
||||
/// module, the set of visible items.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct ItemMap {
|
||||
edition: Edition,
|
||||
/// The prelude module for this crate. This either comes from an import
|
||||
/// marked with the `prelude_import` attribute, or (in the normal case) from
|
||||
/// a dependency (`std` or `core`).
|
||||
pub(crate) prelude: Option<Module>,
|
||||
pub(crate) extern_prelude: FxHashMap<Name, ModuleDef>,
|
||||
per_module: ArenaMap<ModuleId, ModuleScope>,
|
||||
}
|
||||
|
||||
impl std::ops::Index<ModuleId> for ItemMap {
|
||||
type Output = ModuleScope;
|
||||
fn index(&self, id: ModuleId) -> &ModuleScope {
|
||||
&self.per_module[id]
|
||||
}
|
||||
}
|
||||
pub(crate) use self::crate_def_map::{CrateDefMap, ModuleId};
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Eq, Clone)]
|
||||
pub struct ModuleScope {
|
||||
@ -158,292 +130,6 @@ impl<T> PerNs<T> {
|
||||
}
|
||||
}
|
||||
|
||||
struct Resolver<'a, DB> {
|
||||
db: &'a DB,
|
||||
input: &'a FxHashMap<ModuleId, Arc<LoweredModule>>,
|
||||
krate: Crate,
|
||||
def_map: Arc<CrateDefMap>,
|
||||
processed_imports: FxHashSet<(ModuleId, ImportId)>,
|
||||
/// If module `a` has `use b::*`, then this contains the mapping b -> a (and the import)
|
||||
glob_imports: FxHashMap<ModuleId, Vec<(ModuleId, ImportId)>>,
|
||||
result: ItemMap,
|
||||
}
|
||||
|
||||
impl<'a, DB> Resolver<'a, DB>
|
||||
where
|
||||
DB: PersistentHirDatabase,
|
||||
{
|
||||
fn new(
|
||||
db: &'a DB,
|
||||
input: &'a FxHashMap<ModuleId, Arc<LoweredModule>>,
|
||||
krate: Crate,
|
||||
) -> Resolver<'a, DB> {
|
||||
Resolver {
|
||||
db,
|
||||
input,
|
||||
krate,
|
||||
def_map: db.crate_def_map(krate),
|
||||
processed_imports: FxHashSet::default(),
|
||||
glob_imports: FxHashMap::default(),
|
||||
result: ItemMap {
|
||||
edition: krate.edition(db),
|
||||
prelude: None,
|
||||
extern_prelude: FxHashMap::default(),
|
||||
per_module: ArenaMap::default(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn resolve(mut self) -> ItemMap {
|
||||
self.populate_extern_prelude();
|
||||
for (&module_id, items) in self.input.iter() {
|
||||
self.populate_module(module_id, Arc::clone(items));
|
||||
}
|
||||
|
||||
let mut iter = 0;
|
||||
loop {
|
||||
iter += 1;
|
||||
if iter > 1000 {
|
||||
panic!("failed to reach fixedpoint after 1000 iters")
|
||||
}
|
||||
let processed_imports_count = self.processed_imports.len();
|
||||
for &module_id in self.input.keys() {
|
||||
self.db.check_canceled();
|
||||
self.resolve_imports(module_id);
|
||||
}
|
||||
if processed_imports_count == self.processed_imports.len() {
|
||||
// no new imports resolved
|
||||
break;
|
||||
}
|
||||
}
|
||||
self.result
|
||||
}
|
||||
|
||||
fn populate_extern_prelude(&mut self) {
|
||||
for dep in self.krate.dependencies(self.db) {
|
||||
log::debug!("crate dep {:?} -> {:?}", dep.name, dep.krate);
|
||||
if let Some(module) = dep.krate.root_module(self.db) {
|
||||
self.result.extern_prelude.insert(dep.name.clone(), module.into());
|
||||
}
|
||||
// look for the prelude
|
||||
if self.result.prelude.is_none() {
|
||||
let item_map = self.db.item_map(dep.krate);
|
||||
if item_map.prelude.is_some() {
|
||||
self.result.prelude = item_map.prelude;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn populate_module(&mut self, module_id: ModuleId, input: Arc<LoweredModule>) {
|
||||
let mut module_items = ModuleScope::default();
|
||||
for (import_id, import_data) in input.imports.iter() {
|
||||
if let Some(last_segment) = import_data.path.segments.iter().last() {
|
||||
if !import_data.is_glob {
|
||||
let name =
|
||||
import_data.alias.clone().unwrap_or_else(|| last_segment.name.clone());
|
||||
module_items
|
||||
.items
|
||||
.insert(name, Resolution { def: PerNs::none(), import: Some(import_id) });
|
||||
}
|
||||
}
|
||||
}
|
||||
// Populate explicitly declared items, except modules
|
||||
for (name, &def) in input.declarations.iter() {
|
||||
let resolution = Resolution { def, import: None };
|
||||
module_items.items.insert(name.clone(), resolution);
|
||||
}
|
||||
|
||||
// Populate modules
|
||||
for (name, module_id) in self.def_map[module_id].children.iter() {
|
||||
let module = Module { module_id: *module_id, krate: self.krate };
|
||||
self.add_module_item(&mut module_items, name.clone(), PerNs::types(module.into()));
|
||||
}
|
||||
|
||||
self.result.per_module.insert(module_id, module_items);
|
||||
}
|
||||
|
||||
fn add_module_item(&self, module_items: &mut ModuleScope, name: Name, def: PerNs<ModuleDef>) {
|
||||
let resolution = Resolution { def, import: None };
|
||||
module_items.items.insert(name, resolution);
|
||||
}
|
||||
|
||||
fn resolve_imports(&mut self, module_id: ModuleId) {
|
||||
for (import_id, import_data) in self.input[&module_id].imports.iter() {
|
||||
if self.processed_imports.contains(&(module_id, import_id)) {
|
||||
// already done
|
||||
continue;
|
||||
}
|
||||
if self.resolve_import(module_id, import_id, import_data) == ReachedFixedPoint::Yes {
|
||||
log::debug!("import {:?} resolved (or definite error)", import_id);
|
||||
self.processed_imports.insert((module_id, import_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_import(
|
||||
&mut self,
|
||||
module_id: ModuleId,
|
||||
import_id: ImportId,
|
||||
import: &ImportData,
|
||||
) -> ReachedFixedPoint {
|
||||
log::debug!("resolving import: {:?} ({:?})", import, self.result.edition);
|
||||
let original_module = Module { krate: self.krate, module_id };
|
||||
|
||||
let (def, reached_fixedpoint) = if import.is_extern_crate {
|
||||
let res = self.result.resolve_name_in_extern_prelude(
|
||||
&import
|
||||
.path
|
||||
.as_ident()
|
||||
.expect("extern crate should have been desugared to one-element path"),
|
||||
);
|
||||
(res, if res.is_none() { ReachedFixedPoint::No } else { ReachedFixedPoint::Yes })
|
||||
} else {
|
||||
let res = self.result.resolve_path_fp(
|
||||
self.db,
|
||||
ResolveMode::Import,
|
||||
original_module,
|
||||
&import.path,
|
||||
);
|
||||
|
||||
(res.resolved_def, res.reached_fixedpoint)
|
||||
};
|
||||
|
||||
if reached_fixedpoint != ReachedFixedPoint::Yes {
|
||||
return reached_fixedpoint;
|
||||
}
|
||||
|
||||
if import.is_glob {
|
||||
log::debug!("glob import: {:?}", import);
|
||||
match def.take_types() {
|
||||
Some(ModuleDef::Module(m)) => {
|
||||
if import.is_prelude {
|
||||
tested_by!(std_prelude);
|
||||
self.result.prelude = Some(m);
|
||||
} else if m.krate != self.krate {
|
||||
tested_by!(glob_across_crates);
|
||||
// glob import from other crate => we can just import everything once
|
||||
let item_map = self.db.item_map(m.krate);
|
||||
let scope = &item_map[m.module_id];
|
||||
let items = scope
|
||||
.items
|
||||
.iter()
|
||||
.map(|(name, res)| (name.clone(), res.clone()))
|
||||
.collect::<Vec<_>>();
|
||||
self.update(module_id, Some(import_id), &items);
|
||||
} else {
|
||||
// glob import from same crate => we do an initial
|
||||
// import, and then need to propagate any further
|
||||
// additions
|
||||
let scope = &self.result[m.module_id];
|
||||
let items = scope
|
||||
.items
|
||||
.iter()
|
||||
.map(|(name, res)| (name.clone(), res.clone()))
|
||||
.collect::<Vec<_>>();
|
||||
self.update(module_id, Some(import_id), &items);
|
||||
// record the glob import in case we add further items
|
||||
self.glob_imports
|
||||
.entry(m.module_id)
|
||||
.or_default()
|
||||
.push((module_id, import_id));
|
||||
}
|
||||
}
|
||||
Some(ModuleDef::Enum(e)) => {
|
||||
tested_by!(glob_enum);
|
||||
// glob import from enum => just import all the variants
|
||||
let variants = e.variants(self.db);
|
||||
let resolutions = variants
|
||||
.into_iter()
|
||||
.filter_map(|variant| {
|
||||
let res = Resolution {
|
||||
def: PerNs::both(variant.into(), variant.into()),
|
||||
import: Some(import_id),
|
||||
};
|
||||
let name = variant.name(self.db)?;
|
||||
Some((name, res))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
self.update(module_id, Some(import_id), &resolutions);
|
||||
}
|
||||
Some(d) => {
|
||||
log::debug!("glob import {:?} from non-module/enum {:?}", import, d);
|
||||
}
|
||||
None => {
|
||||
log::debug!("glob import {:?} didn't resolve as type", import);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let last_segment = import.path.segments.last().unwrap();
|
||||
let name = import.alias.clone().unwrap_or_else(|| last_segment.name.clone());
|
||||
log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
|
||||
|
||||
// extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
|
||||
if let Some(root_module) = self.krate.root_module(self.db) {
|
||||
if import.is_extern_crate && module_id == root_module.module_id {
|
||||
if let Some(def) = def.take_types() {
|
||||
self.result.extern_prelude.insert(name.clone(), def);
|
||||
}
|
||||
}
|
||||
}
|
||||
let resolution = Resolution { def, import: Some(import_id) };
|
||||
self.update(module_id, None, &[(name, resolution)]);
|
||||
}
|
||||
reached_fixedpoint
|
||||
}
|
||||
|
||||
fn update(
|
||||
&mut self,
|
||||
module_id: ModuleId,
|
||||
import: Option<ImportId>,
|
||||
resolutions: &[(Name, Resolution)],
|
||||
) {
|
||||
self.update_recursive(module_id, import, resolutions, 0)
|
||||
}
|
||||
|
||||
fn update_recursive(
|
||||
&mut self,
|
||||
module_id: ModuleId,
|
||||
import: Option<ImportId>,
|
||||
resolutions: &[(Name, Resolution)],
|
||||
depth: usize,
|
||||
) {
|
||||
if depth > 100 {
|
||||
// prevent stack overflows (but this shouldn't be possible)
|
||||
panic!("infinite recursion in glob imports!");
|
||||
}
|
||||
let module_items = self.result.per_module.get_mut(module_id).unwrap();
|
||||
let mut changed = false;
|
||||
for (name, res) in resolutions {
|
||||
let existing = module_items.items.entry(name.clone()).or_default();
|
||||
if existing.def.types.is_none() && res.def.types.is_some() {
|
||||
existing.def.types = res.def.types;
|
||||
existing.import = import.or(res.import);
|
||||
changed = true;
|
||||
}
|
||||
if existing.def.values.is_none() && res.def.values.is_some() {
|
||||
existing.def.values = res.def.values;
|
||||
existing.import = import.or(res.import);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if !changed {
|
||||
return;
|
||||
}
|
||||
let glob_imports = self
|
||||
.glob_imports
|
||||
.get(&module_id)
|
||||
.into_iter()
|
||||
.flat_map(|v| v.iter())
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
for (glob_importing_module, glob_import) in glob_imports {
|
||||
// We pass the glob import so that the tracked import in those modules is that glob import
|
||||
self.update_recursive(glob_importing_module, Some(glob_import), resolutions, depth + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct ResolvePathResult {
|
||||
resolved_def: PerNs<ModuleDef>,
|
||||
@ -476,220 +162,3 @@ enum ReachedFixedPoint {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
impl ItemMap {
|
||||
pub(crate) fn item_map_query(db: &impl PersistentHirDatabase, krate: Crate) -> Arc<ItemMap> {
|
||||
let start = time::Instant::now();
|
||||
let def_map = db.crate_def_map(krate);
|
||||
let input = def_map
|
||||
.modules()
|
||||
.map(|module_id| (module_id, db.lower_module(Module { krate, module_id })))
|
||||
.collect::<FxHashMap<_, _>>();
|
||||
|
||||
let resolver = Resolver::new(db, &input, krate);
|
||||
let res = resolver.resolve();
|
||||
let elapsed = start.elapsed();
|
||||
log::info!("item_map: {:?}", elapsed);
|
||||
Arc::new(res)
|
||||
}
|
||||
|
||||
pub(crate) fn resolve_path(
|
||||
&self,
|
||||
db: &impl PersistentHirDatabase,
|
||||
original_module: Module,
|
||||
path: &Path,
|
||||
) -> (PerNs<ModuleDef>, Option<usize>) {
|
||||
let res = self.resolve_path_fp(db, ResolveMode::Other, original_module, path);
|
||||
(res.resolved_def, res.segment_index)
|
||||
}
|
||||
|
||||
fn resolve_in_prelude(
|
||||
&self,
|
||||
db: &impl PersistentHirDatabase,
|
||||
original_module: Module,
|
||||
name: &Name,
|
||||
) -> PerNs<ModuleDef> {
|
||||
if let Some(prelude) = self.prelude {
|
||||
let resolution = if prelude.krate == original_module.krate {
|
||||
self[prelude.module_id].items.get(name).cloned()
|
||||
} else {
|
||||
db.item_map(prelude.krate)[prelude.module_id].items.get(name).cloned()
|
||||
};
|
||||
resolution.map(|r| r.def).unwrap_or_else(PerNs::none)
|
||||
} else {
|
||||
PerNs::none()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn resolve_name_in_module(
|
||||
&self,
|
||||
db: &impl PersistentHirDatabase,
|
||||
module: Module,
|
||||
name: &Name,
|
||||
) -> PerNs<ModuleDef> {
|
||||
// Resolve in:
|
||||
// - current module / scope
|
||||
// - extern prelude
|
||||
// - std prelude
|
||||
let from_scope = self[module.module_id].items.get(name).map_or(PerNs::none(), |it| it.def);
|
||||
let from_extern_prelude =
|
||||
self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
|
||||
let from_prelude = self.resolve_in_prelude(db, module, name);
|
||||
|
||||
from_scope.or(from_extern_prelude).or(from_prelude)
|
||||
}
|
||||
|
||||
fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> {
|
||||
self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it))
|
||||
}
|
||||
|
||||
fn resolve_name_in_crate_root_or_extern_prelude(
|
||||
&self,
|
||||
db: &impl PersistentHirDatabase,
|
||||
module: Module,
|
||||
name: &Name,
|
||||
) -> PerNs<ModuleDef> {
|
||||
let crate_root = module.crate_root(db);
|
||||
let from_crate_root =
|
||||
self[crate_root.module_id].items.get(name).map_or(PerNs::none(), |it| it.def);
|
||||
let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
|
||||
|
||||
from_crate_root.or(from_extern_prelude)
|
||||
}
|
||||
|
||||
// Returns Yes if we are sure that additions to `ItemMap` wouldn't change
|
||||
// the result.
|
||||
fn resolve_path_fp(
|
||||
&self,
|
||||
db: &impl PersistentHirDatabase,
|
||||
mode: ResolveMode,
|
||||
original_module: Module,
|
||||
path: &Path,
|
||||
) -> ResolvePathResult {
|
||||
let mut segments = path.segments.iter().enumerate();
|
||||
let mut curr_per_ns: PerNs<ModuleDef> = match path.kind {
|
||||
PathKind::Crate => PerNs::types(original_module.crate_root(db).into()),
|
||||
PathKind::Self_ => PerNs::types(original_module.into()),
|
||||
// plain import or absolute path in 2015: crate-relative with
|
||||
// fallback to extern prelude (with the simplification in
|
||||
// rust-lang/rust#57745)
|
||||
// TODO there must be a nicer way to write this condition
|
||||
PathKind::Plain | PathKind::Abs
|
||||
if self.edition == Edition::Edition2015
|
||||
&& (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
|
||||
{
|
||||
let segment = match segments.next() {
|
||||
Some((_, segment)) => segment,
|
||||
None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
|
||||
};
|
||||
log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
|
||||
self.resolve_name_in_crate_root_or_extern_prelude(
|
||||
db,
|
||||
original_module,
|
||||
&segment.name,
|
||||
)
|
||||
}
|
||||
PathKind::Plain => {
|
||||
let segment = match segments.next() {
|
||||
Some((_, segment)) => segment,
|
||||
None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
|
||||
};
|
||||
log::debug!("resolving {:?} in module", segment);
|
||||
self.resolve_name_in_module(db, original_module, &segment.name)
|
||||
}
|
||||
PathKind::Super => {
|
||||
if let Some(p) = original_module.parent(db) {
|
||||
PerNs::types(p.into())
|
||||
} else {
|
||||
log::debug!("super path in root module");
|
||||
return ResolvePathResult::empty(ReachedFixedPoint::Yes);
|
||||
}
|
||||
}
|
||||
PathKind::Abs => {
|
||||
// 2018-style absolute path -- only extern prelude
|
||||
let segment = match segments.next() {
|
||||
Some((_, segment)) => segment,
|
||||
None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
|
||||
};
|
||||
if let Some(def) = self.extern_prelude.get(&segment.name) {
|
||||
log::debug!("absolute path {:?} resolved to crate {:?}", path, def);
|
||||
PerNs::types(*def)
|
||||
} else {
|
||||
return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (i, segment) in segments {
|
||||
let curr = match curr_per_ns.as_ref().take_types() {
|
||||
Some(r) => r,
|
||||
None => {
|
||||
// we still have path segments left, but the path so far
|
||||
// didn't resolve in the types namespace => no resolution
|
||||
// (don't break here because `curr_per_ns` might contain
|
||||
// something in the value namespace, and it would be wrong
|
||||
// to return that)
|
||||
return ResolvePathResult::empty(ReachedFixedPoint::No);
|
||||
}
|
||||
};
|
||||
// resolve segment in curr
|
||||
|
||||
curr_per_ns = match curr {
|
||||
ModuleDef::Module(module) => {
|
||||
if module.krate != original_module.krate {
|
||||
let path = Path {
|
||||
segments: path.segments[i..].iter().cloned().collect(),
|
||||
kind: PathKind::Self_,
|
||||
};
|
||||
log::debug!("resolving {:?} in other crate", path);
|
||||
let item_map = db.item_map(module.krate);
|
||||
let (def, s) = item_map.resolve_path(db, *module, &path);
|
||||
return ResolvePathResult::with(
|
||||
def,
|
||||
ReachedFixedPoint::Yes,
|
||||
s.map(|s| s + i),
|
||||
);
|
||||
}
|
||||
|
||||
match self[module.module_id].items.get(&segment.name) {
|
||||
Some(res) if !res.def.is_none() => res.def,
|
||||
_ => {
|
||||
log::debug!("path segment {:?} not found", segment.name);
|
||||
return ResolvePathResult::empty(ReachedFixedPoint::No);
|
||||
}
|
||||
}
|
||||
}
|
||||
ModuleDef::Enum(e) => {
|
||||
// enum variant
|
||||
tested_by!(can_import_enum_variant);
|
||||
match e.variant(db, &segment.name) {
|
||||
Some(variant) => PerNs::both(variant.into(), variant.into()),
|
||||
None => {
|
||||
return ResolvePathResult::with(
|
||||
PerNs::types((*e).into()),
|
||||
ReachedFixedPoint::Yes,
|
||||
Some(i),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
s => {
|
||||
// could be an inherent method call in UFCS form
|
||||
// (`Struct::method`), or some other kind of associated item
|
||||
log::debug!(
|
||||
"path segment {:?} resolved to non-module {:?}, but is not last",
|
||||
segment.name,
|
||||
curr,
|
||||
);
|
||||
|
||||
return ResolvePathResult::with(
|
||||
PerNs::types((*s).into()),
|
||||
ReachedFixedPoint::Yes,
|
||||
Some(i),
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None)
|
||||
}
|
||||
}
|
||||
|
@ -149,8 +149,16 @@ impl CrateDefMap {
|
||||
&self.problems
|
||||
}
|
||||
|
||||
pub(crate) fn modules<'a>(&'a self) -> impl Iterator<Item = ModuleId> + 'a {
|
||||
self.modules.iter().map(|(id, _data)| id)
|
||||
pub(crate) fn mk_module(&self, module_id: ModuleId) -> Module {
|
||||
Module { krate: self.krate, module_id }
|
||||
}
|
||||
|
||||
pub(crate) fn prelude(&self) -> Option<Module> {
|
||||
self.prelude
|
||||
}
|
||||
|
||||
pub(crate) fn extern_prelude(&self) -> &FxHashMap<Name, ModuleDef> {
|
||||
&self.extern_prelude
|
||||
}
|
||||
|
||||
pub(crate) fn find_module_by_source(
|
||||
@ -169,6 +177,16 @@ impl CrateDefMap {
|
||||
Some(module_id)
|
||||
}
|
||||
|
||||
pub(crate) fn resolve_path(
|
||||
&self,
|
||||
db: &impl PersistentHirDatabase,
|
||||
original_module: ModuleId,
|
||||
path: &Path,
|
||||
) -> (PerNs<ModuleDef>, Option<usize>) {
|
||||
let res = self.resolve_path_fp(db, ResolveMode::Other, original_module, path);
|
||||
(res.resolved_def, res.segment_index)
|
||||
}
|
||||
|
||||
// Returns Yes if we are sure that additions to `ItemMap` wouldn't change
|
||||
// the result.
|
||||
fn resolve_path_fp(
|
||||
@ -254,8 +272,8 @@ impl CrateDefMap {
|
||||
kind: PathKind::Self_,
|
||||
};
|
||||
log::debug!("resolving {:?} in other crate", path);
|
||||
let item_map = db.item_map(module.krate);
|
||||
let (def, s) = item_map.resolve_path(db, *module, &path);
|
||||
let defp_map = db.crate_def_map(module.krate);
|
||||
let (def, s) = defp_map.resolve_path(db, module.module_id, &path);
|
||||
return ResolvePathResult::with(
|
||||
def,
|
||||
ReachedFixedPoint::Yes,
|
||||
@ -313,7 +331,7 @@ impl CrateDefMap {
|
||||
from_crate_root.or(from_extern_prelude)
|
||||
}
|
||||
|
||||
fn resolve_name_in_module(
|
||||
pub(crate) fn resolve_name_in_module(
|
||||
&self,
|
||||
db: &impl PersistentHirDatabase,
|
||||
module: ModuleId,
|
||||
@ -340,7 +358,7 @@ impl CrateDefMap {
|
||||
let resolution = if prelude.krate == self.krate {
|
||||
self[prelude.module_id].scope.items.get(name).cloned()
|
||||
} else {
|
||||
db.item_map(prelude.krate)[prelude.module_id].items.get(name).cloned()
|
||||
db.crate_def_map(prelude.krate)[prelude.module_id].scope.items.get(name).cloned()
|
||||
};
|
||||
resolution.map(|r| r.def).unwrap_or_else(PerNs::none)
|
||||
} else {
|
||||
|
@ -26,9 +26,9 @@ pub(super) fn collect_defs(
|
||||
}
|
||||
// look for the prelude
|
||||
if def_map.prelude.is_none() {
|
||||
let item_map = db.item_map(dep.krate);
|
||||
if item_map.prelude.is_some() {
|
||||
def_map.prelude = item_map.prelude;
|
||||
let map = db.crate_def_map(dep.krate);
|
||||
if map.prelude.is_some() {
|
||||
def_map.prelude = map.prelude;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -162,8 +162,8 @@ where
|
||||
} else if m.krate != self.def_map.krate {
|
||||
tested_by!(glob_across_crates);
|
||||
// glob import from other crate => we can just import everything once
|
||||
let item_map = self.db.item_map(m.krate);
|
||||
let scope = &item_map[m.module_id];
|
||||
let item_map = self.db.crate_def_map(m.krate);
|
||||
let scope = &item_map[m.module_id].scope;
|
||||
let items = scope
|
||||
.items
|
||||
.iter()
|
||||
|
@ -4,10 +4,10 @@ use std::sync::Arc;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::{
|
||||
ModuleDef, Module,
|
||||
ModuleDef,
|
||||
db::HirDatabase,
|
||||
name::{Name, KnownName},
|
||||
nameres::{PerNs, ItemMap},
|
||||
nameres::{PerNs, CrateDefMap, ModuleId},
|
||||
generics::GenericParams,
|
||||
expr::{scope::{ExprScopes, ScopeId}, PatId, Body},
|
||||
impl_block::ImplBlock,
|
||||
@ -22,8 +22,8 @@ pub struct Resolver {
|
||||
// TODO how to store these best
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct ModuleItemMap {
|
||||
item_map: Arc<ItemMap>,
|
||||
module: Module,
|
||||
crate_def_map: Arc<CrateDefMap>,
|
||||
module_id: ModuleId,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -175,9 +175,9 @@ impl Resolver {
|
||||
names
|
||||
}
|
||||
|
||||
fn module(&self) -> Option<(&ItemMap, Module)> {
|
||||
fn module(&self) -> Option<(&CrateDefMap, ModuleId)> {
|
||||
self.scopes.iter().rev().find_map(|scope| match scope {
|
||||
Scope::ModuleScope(m) => Some((&*m.item_map, m.module.clone())),
|
||||
Scope::ModuleScope(m) => Some((&*m.crate_def_map, m.module_id)),
|
||||
|
||||
_ => None,
|
||||
})
|
||||
@ -206,8 +206,12 @@ impl Resolver {
|
||||
self.push_scope(Scope::ImplBlockScope(impl_block))
|
||||
}
|
||||
|
||||
pub(crate) fn push_module_scope(self, item_map: Arc<ItemMap>, module: Module) -> Resolver {
|
||||
self.push_scope(Scope::ModuleScope(ModuleItemMap { item_map, module }))
|
||||
pub(crate) fn push_module_scope(
|
||||
self,
|
||||
crate_def_map: Arc<CrateDefMap>,
|
||||
module_id: ModuleId,
|
||||
) -> Resolver {
|
||||
self.push_scope(Scope::ModuleScope(ModuleItemMap { crate_def_map, module_id }))
|
||||
}
|
||||
|
||||
pub(crate) fn push_expr_scope(
|
||||
@ -224,9 +228,11 @@ impl Scope {
|
||||
match self {
|
||||
Scope::ModuleScope(m) => {
|
||||
if let Some(KnownName::SelfParam) = name.as_known_name() {
|
||||
PerNs::types(Resolution::Def(m.module.into()))
|
||||
PerNs::types(Resolution::Def(m.crate_def_map.mk_module(m.module_id).into()))
|
||||
} else {
|
||||
m.item_map.resolve_name_in_module(db, m.module, name).map(Resolution::Def)
|
||||
m.crate_def_map
|
||||
.resolve_name_in_module(db, m.module_id, name)
|
||||
.map(Resolution::Def)
|
||||
}
|
||||
}
|
||||
Scope::GenericParams(gp) => match gp.find_by_name(name) {
|
||||
@ -261,15 +267,15 @@ impl Scope {
|
||||
// def: m.module.into(),
|
||||
// }),
|
||||
// );
|
||||
m.item_map[m.module.module_id].entries().for_each(|(name, res)| {
|
||||
m.crate_def_map[m.module_id].scope.entries().for_each(|(name, res)| {
|
||||
f(name.clone(), res.def.map(Resolution::Def));
|
||||
});
|
||||
m.item_map.extern_prelude.iter().for_each(|(name, def)| {
|
||||
m.crate_def_map.extern_prelude().iter().for_each(|(name, def)| {
|
||||
f(name.clone(), PerNs::types(Resolution::Def(*def)));
|
||||
});
|
||||
if let Some(prelude) = m.item_map.prelude {
|
||||
let prelude_item_map = db.item_map(prelude.krate);
|
||||
prelude_item_map[prelude.module_id].entries().for_each(|(name, res)| {
|
||||
if let Some(prelude) = m.crate_def_map.prelude() {
|
||||
let prelude_def_map = db.crate_def_map(prelude.krate);
|
||||
prelude_def_map[prelude.module_id].scope.entries().for_each(|(name, res)| {
|
||||
f(name.clone(), res.def.map(Resolution::Def));
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user