2019-01-08 23:47:12 +00:00
|
|
|
//! Name resolution algorithm. The end result of the algorithm is an `ItemMap`:
|
|
|
|
//! a map which maps each module to its scope: the set of items visible in the
|
2018-11-28 00:42:26 +00:00
|
|
|
//! module. That is, we only resolve imports here, name resolution of item
|
|
|
|
//! bodies will be done in a separate step.
|
|
|
|
//!
|
2019-01-08 23:47:12 +00:00
|
|
|
//! Like Rustc, we use an interactive per-crate algorithm: we start with scopes
|
2018-11-28 00:42:26 +00:00
|
|
|
//! containing only directly defined items, and then iteratively resolve
|
|
|
|
//! imports.
|
|
|
|
//!
|
2019-01-08 23:47:12 +00:00
|
|
|
//! To make this work nicely in the IDE scenario, we place `InputModuleItems`
|
2018-11-28 00:42:26 +00:00
|
|
|
//! in between raw syntax and name resolution. `InputModuleItems` are computed
|
|
|
|
//! using only the module's syntax, and it is all directly defined items plus
|
2019-01-08 23:47:12 +00:00
|
|
|
//! imports. The plan is to make `InputModuleItems` independent of local
|
|
|
|
//! modifications (that is, typing inside a function should not change IMIs),
|
|
|
|
//! so that the results of name resolution can be preserved unless the module
|
2018-11-28 00:42:26 +00:00
|
|
|
//! structure itself is modified.
|
2019-01-18 11:34:13 +00:00
|
|
|
pub(crate) mod lower;
|
2019-01-23 05:21:29 +00:00
|
|
|
|
2019-01-30 19:18:17 +00:00
|
|
|
use std::{time, sync::Arc};
|
2018-11-28 00:42:26 +00:00
|
|
|
|
2019-01-25 07:29:00 +00:00
|
|
|
use ra_arena::map::ArenaMap;
|
2019-01-25 07:08:21 +00:00
|
|
|
use test_utils::tested_by;
|
2019-01-07 18:40:31 +00:00
|
|
|
use rustc_hash::{FxHashMap, FxHashSet};
|
2018-11-28 00:42:26 +00:00
|
|
|
|
|
|
|
use crate::{
|
2019-01-23 20:14:13 +00:00
|
|
|
Module, ModuleDef,
|
2019-02-01 10:33:41 +00:00
|
|
|
Path, PathKind, Crate,
|
|
|
|
Name, PersistentHirDatabase,
|
2019-01-06 14:33:27 +00:00
|
|
|
module_tree::{ModuleId, ModuleTree},
|
2019-01-25 07:29:55 +00:00
|
|
|
nameres::lower::{ImportId, LoweredModule, ImportData},
|
2018-11-28 00:42:26 +00:00
|
|
|
};
|
|
|
|
|
2019-01-19 20:23:26 +00:00
|
|
|
/// `ItemMap` is the result of module name resolution. It contains, for each
|
2018-11-28 00:42:26 +00:00
|
|
|
/// module, the set of visible items.
|
|
|
|
#[derive(Default, Debug, PartialEq, Eq)]
|
2018-11-28 01:09:44 +00:00
|
|
|
pub struct ItemMap {
|
2019-01-25 07:29:00 +00:00
|
|
|
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]
|
|
|
|
}
|
2018-11-28 00:42:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Default, PartialEq, Eq, Clone)]
|
2018-11-28 01:09:44 +00:00
|
|
|
pub struct ModuleScope {
|
2018-12-27 17:07:21 +00:00
|
|
|
items: FxHashMap<Name, Resolution>,
|
2018-11-28 00:42:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ModuleScope {
|
2018-12-27 17:07:21 +00:00
|
|
|
pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, &'a Resolution)> + 'a {
|
2018-11-28 00:42:26 +00:00
|
|
|
self.items.iter()
|
|
|
|
}
|
2018-12-27 17:07:21 +00:00
|
|
|
pub fn get(&self, name: &Name) -> Option<&Resolution> {
|
2018-11-28 00:42:26 +00:00
|
|
|
self.items.get(name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-08 23:47:12 +00:00
|
|
|
/// `Resolution` is basically `DefId` atm, but it should account for stuff like
|
2018-11-28 00:42:26 +00:00
|
|
|
/// multiple namespaces, ambiguity and errors.
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
2018-11-28 01:09:44 +00:00
|
|
|
pub struct Resolution {
|
2018-11-28 00:42:26 +00:00
|
|
|
/// None for unresolved
|
2019-01-25 07:16:28 +00:00
|
|
|
pub def: PerNs<ModuleDef>,
|
2019-01-23 05:21:29 +00:00
|
|
|
/// ident by which this is imported into local scope.
|
2019-01-18 13:56:02 +00:00
|
|
|
pub import: Option<ImportId>,
|
2018-11-28 00:42:26 +00:00
|
|
|
}
|
|
|
|
|
2018-12-24 19:32:39 +00:00
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
|
|
pub enum Namespace {
|
|
|
|
Types,
|
|
|
|
Values,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
|
|
|
pub struct PerNs<T> {
|
|
|
|
pub types: Option<T>,
|
|
|
|
pub values: Option<T>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> PerNs<T> {
|
|
|
|
pub fn none() -> PerNs<T> {
|
|
|
|
PerNs {
|
|
|
|
types: None,
|
|
|
|
values: None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn values(t: T) -> PerNs<T> {
|
|
|
|
PerNs {
|
|
|
|
types: None,
|
|
|
|
values: Some(t),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn types(t: T) -> PerNs<T> {
|
|
|
|
PerNs {
|
|
|
|
types: Some(t),
|
|
|
|
values: None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn both(types: T, values: T) -> PerNs<T> {
|
|
|
|
PerNs {
|
|
|
|
types: Some(types),
|
|
|
|
values: Some(values),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_none(&self) -> bool {
|
|
|
|
self.types.is_none() && self.values.is_none()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn take(self, namespace: Namespace) -> Option<T> {
|
|
|
|
match namespace {
|
|
|
|
Namespace::Types => self.types,
|
|
|
|
Namespace::Values => self.values,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn take_types(self) -> Option<T> {
|
2019-01-06 11:05:03 +00:00
|
|
|
self.take(Namespace::Types)
|
2018-12-24 19:32:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn take_values(self) -> Option<T> {
|
2019-01-06 11:05:03 +00:00
|
|
|
self.take(Namespace::Values)
|
2018-12-24 19:32:39 +00:00
|
|
|
}
|
2018-11-28 00:42:26 +00:00
|
|
|
|
2018-12-24 19:32:39 +00:00
|
|
|
pub fn get(&self, namespace: Namespace) -> Option<&T> {
|
|
|
|
self.as_ref().take(namespace)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn as_ref(&self) -> PerNs<&T> {
|
|
|
|
PerNs {
|
|
|
|
types: self.types.as_ref(),
|
|
|
|
values: self.values.as_ref(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn and_then<U>(self, f: impl Fn(T) -> Option<U>) -> PerNs<U> {
|
|
|
|
PerNs {
|
|
|
|
types: self.types.and_then(&f),
|
|
|
|
values: self.values.and_then(&f),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn map<U>(self, f: impl Fn(T) -> U) -> PerNs<U> {
|
|
|
|
PerNs {
|
|
|
|
types: self.types.map(&f),
|
|
|
|
values: self.values.map(&f),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-11-28 00:42:26 +00:00
|
|
|
|
2019-01-30 19:18:17 +00:00
|
|
|
struct Resolver<'a, DB> {
|
2018-12-09 09:24:52 +00:00
|
|
|
db: &'a DB,
|
2019-01-18 13:36:56 +00:00
|
|
|
input: &'a FxHashMap<ModuleId, Arc<LoweredModule>>,
|
2019-01-30 19:23:14 +00:00
|
|
|
krate: Crate,
|
2018-12-09 09:24:52 +00:00
|
|
|
module_tree: Arc<ModuleTree>,
|
2019-01-18 13:56:02 +00:00
|
|
|
processed_imports: FxHashSet<(ModuleId, ImportId)>,
|
2018-12-09 09:24:52 +00:00
|
|
|
result: ItemMap,
|
2018-11-28 00:42:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, DB> Resolver<'a, DB>
|
|
|
|
where
|
2019-02-01 10:33:41 +00:00
|
|
|
DB: PersistentHirDatabase,
|
2018-11-28 00:42:26 +00:00
|
|
|
{
|
2019-01-30 19:18:17 +00:00
|
|
|
fn new(
|
2018-12-09 09:24:52 +00:00
|
|
|
db: &'a DB,
|
2019-01-18 13:36:56 +00:00
|
|
|
input: &'a FxHashMap<ModuleId, Arc<LoweredModule>>,
|
2019-01-30 19:23:14 +00:00
|
|
|
krate: Crate,
|
2018-12-09 09:24:52 +00:00
|
|
|
) -> Resolver<'a, DB> {
|
2019-01-23 20:14:13 +00:00
|
|
|
let module_tree = db.module_tree(krate);
|
2018-12-09 09:24:52 +00:00
|
|
|
Resolver {
|
2018-12-09 09:45:47 +00:00
|
|
|
db,
|
|
|
|
input,
|
2019-01-23 20:14:13 +00:00
|
|
|
krate,
|
2018-12-09 09:24:52 +00:00
|
|
|
module_tree,
|
2019-01-07 18:40:31 +00:00
|
|
|
processed_imports: FxHashSet::default(),
|
2018-12-09 09:24:52 +00:00
|
|
|
result: ItemMap::default(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-15 16:15:01 +00:00
|
|
|
pub(crate) fn resolve(mut self) -> ItemMap {
|
2018-11-28 00:42:26 +00:00
|
|
|
for (&module_id, items) in self.input.iter() {
|
2019-01-15 16:15:01 +00:00
|
|
|
self.populate_module(module_id, Arc::clone(items));
|
2018-11-28 00:42:26 +00:00
|
|
|
}
|
|
|
|
|
2019-01-25 18:16:04 +00:00
|
|
|
let mut iter = 0;
|
2019-01-07 18:40:31 +00:00
|
|
|
loop {
|
2019-01-25 18:16:04 +00:00
|
|
|
iter += 1;
|
|
|
|
if iter > 1000 {
|
|
|
|
panic!("failed to reach fixedpoint after 1000 iters")
|
|
|
|
}
|
2019-01-07 18:40:31 +00:00
|
|
|
let processed_imports_count = self.processed_imports.len();
|
|
|
|
for &module_id in self.input.keys() {
|
2019-01-15 12:45:48 +00:00
|
|
|
self.db.check_canceled();
|
2019-01-15 16:15:01 +00:00
|
|
|
self.resolve_imports(module_id);
|
2019-01-07 18:40:31 +00:00
|
|
|
}
|
|
|
|
if processed_imports_count == self.processed_imports.len() {
|
|
|
|
// no new imports resolved
|
|
|
|
break;
|
|
|
|
}
|
2018-11-28 00:42:26 +00:00
|
|
|
}
|
2019-01-15 16:15:01 +00:00
|
|
|
self.result
|
2018-11-28 00:42:26 +00:00
|
|
|
}
|
|
|
|
|
2019-01-18 13:36:56 +00:00
|
|
|
fn populate_module(&mut self, module_id: ModuleId, input: Arc<LoweredModule>) {
|
2018-11-28 00:42:26 +00:00
|
|
|
let mut module_items = ModuleScope::default();
|
|
|
|
|
2018-12-09 10:49:54 +00:00
|
|
|
// Populate extern crates prelude
|
|
|
|
{
|
|
|
|
let root_id = module_id.crate_root(&self.module_tree);
|
2019-01-26 20:25:18 +00:00
|
|
|
let file_id = root_id.file_id(&self.module_tree);
|
2018-12-09 10:49:54 +00:00
|
|
|
let crate_graph = self.db.crate_graph();
|
2019-01-01 20:21:16 +00:00
|
|
|
if let Some(crate_id) = crate_graph.crate_id_for_crate_root(file_id.as_original_file())
|
|
|
|
{
|
2019-01-30 19:23:14 +00:00
|
|
|
let krate = Crate { crate_id };
|
2019-01-15 15:33:26 +00:00
|
|
|
for dep in krate.dependencies(self.db) {
|
|
|
|
if let Some(module) = dep.krate.root_module(self.db) {
|
2019-01-25 07:16:28 +00:00
|
|
|
let def = module.into();
|
2018-12-27 17:07:21 +00:00
|
|
|
self.add_module_item(
|
|
|
|
&mut module_items,
|
|
|
|
dep.name.clone(),
|
2019-01-25 07:16:28 +00:00
|
|
|
PerNs::types(def),
|
2018-12-27 17:07:21 +00:00
|
|
|
);
|
2018-12-09 10:49:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
2019-01-18 13:36:56 +00:00
|
|
|
for (import_id, import_data) in input.imports.iter() {
|
2019-01-12 23:19:20 +00:00
|
|
|
if let Some(segment) = import_data.path.segments.iter().last() {
|
2019-01-18 13:36:56 +00:00
|
|
|
if !import_data.is_glob {
|
2018-11-28 00:42:26 +00:00
|
|
|
module_items.items.insert(
|
2019-01-12 23:19:20 +00:00
|
|
|
segment.name.clone(),
|
2018-11-28 00:42:26 +00:00
|
|
|
Resolution {
|
2019-01-25 07:16:28 +00:00
|
|
|
def: PerNs::none(),
|
2019-01-18 13:36:56 +00:00
|
|
|
import: Some(import_id),
|
2018-11-28 00:42:26 +00:00
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-12-23 16:13:11 +00:00
|
|
|
// Populate explicitly declared items, except modules
|
2019-01-25 07:16:28 +00:00
|
|
|
for (name, &def) in input.declarations.iter() {
|
|
|
|
let resolution = Resolution { def, import: None };
|
2019-01-23 16:49:11 +00:00
|
|
|
module_items.items.insert(name.clone(), resolution);
|
2018-11-28 00:42:26 +00:00
|
|
|
}
|
|
|
|
|
2018-12-09 10:49:54 +00:00
|
|
|
// Populate modules
|
2018-12-04 20:01:53 +00:00
|
|
|
for (name, module_id) in module_id.children(&self.module_tree) {
|
2019-01-23 20:14:13 +00:00
|
|
|
let module = Module {
|
2018-12-19 15:04:17 +00:00
|
|
|
module_id,
|
2019-01-23 20:14:13 +00:00
|
|
|
krate: self.krate,
|
2018-12-19 15:04:17 +00:00
|
|
|
};
|
2019-01-23 20:14:13 +00:00
|
|
|
self.add_module_item(&mut module_items, name, PerNs::types(module.into()));
|
2018-11-28 00:42:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
self.result.per_module.insert(module_id, module_items);
|
2018-12-09 10:49:54 +00:00
|
|
|
}
|
|
|
|
|
2019-01-25 07:16:28 +00:00
|
|
|
fn add_module_item(&self, module_items: &mut ModuleScope, name: Name, def: PerNs<ModuleDef>) {
|
|
|
|
let resolution = Resolution { def, import: None };
|
2018-12-09 10:49:54 +00:00
|
|
|
module_items.items.insert(name, resolution);
|
2018-11-28 00:42:26 +00:00
|
|
|
}
|
|
|
|
|
2019-01-15 16:15:01 +00:00
|
|
|
fn resolve_imports(&mut self, module_id: ModuleId) {
|
2019-01-18 13:36:56 +00:00
|
|
|
for (import_id, import_data) in self.input[&module_id].imports.iter() {
|
|
|
|
if self.processed_imports.contains(&(module_id, import_id)) {
|
2019-01-07 18:40:31 +00:00
|
|
|
// already done
|
|
|
|
continue;
|
|
|
|
}
|
2019-01-25 07:08:21 +00:00
|
|
|
if self.resolve_import(module_id, import_id, import_data) == ReachedFixedPoint::Yes {
|
2019-01-18 13:36:56 +00:00
|
|
|
log::debug!("import {:?} resolved (or definite error)", import_id);
|
|
|
|
self.processed_imports.insert((module_id, import_id));
|
2019-01-07 18:40:31 +00:00
|
|
|
}
|
2018-11-28 00:42:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-18 13:36:56 +00:00
|
|
|
fn resolve_import(
|
|
|
|
&mut self,
|
|
|
|
module_id: ModuleId,
|
2019-01-18 13:56:02 +00:00
|
|
|
import_id: ImportId,
|
2019-01-18 13:36:56 +00:00
|
|
|
import: &ImportData,
|
2019-01-25 07:08:21 +00:00
|
|
|
) -> ReachedFixedPoint {
|
2019-01-08 13:40:41 +00:00
|
|
|
log::debug!("resolving import: {:?}", import);
|
2019-01-18 13:36:56 +00:00
|
|
|
if import.is_glob {
|
2019-01-25 07:08:21 +00:00
|
|
|
return ReachedFixedPoint::Yes;
|
2018-11-28 00:42:26 +00:00
|
|
|
};
|
2019-01-25 07:08:21 +00:00
|
|
|
let original_module = Module {
|
|
|
|
krate: self.krate,
|
|
|
|
module_id,
|
|
|
|
};
|
2019-01-25 07:16:28 +00:00
|
|
|
let (def, reached_fixedpoint) =
|
2019-01-25 07:08:21 +00:00
|
|
|
self.result
|
2019-01-25 07:15:10 +00:00
|
|
|
.resolve_path_fp(self.db, original_module, &import.path);
|
2019-01-25 07:08:21 +00:00
|
|
|
|
|
|
|
if reached_fixedpoint == ReachedFixedPoint::Yes {
|
|
|
|
let last_segment = import.path.segments.last().unwrap();
|
|
|
|
self.update(module_id, |items| {
|
|
|
|
let res = Resolution {
|
2019-01-25 07:16:28 +00:00
|
|
|
def,
|
2019-01-25 07:08:21 +00:00
|
|
|
import: Some(import_id),
|
|
|
|
};
|
|
|
|
items.items.insert(last_segment.name.clone(), res);
|
|
|
|
});
|
|
|
|
log::debug!(
|
|
|
|
"resolved import {:?} ({:?}) cross-source root to {:?}",
|
|
|
|
last_segment.name,
|
|
|
|
import,
|
2019-01-25 07:16:28 +00:00
|
|
|
def,
|
2019-01-25 07:08:21 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
reached_fixedpoint
|
|
|
|
}
|
|
|
|
|
|
|
|
fn update(&mut self, module_id: ModuleId, f: impl FnOnce(&mut ModuleScope)) {
|
2019-01-25 07:29:00 +00:00
|
|
|
let module_items = self.result.per_module.get_mut(module_id).unwrap();
|
2019-01-25 07:08:21 +00:00
|
|
|
f(module_items)
|
|
|
|
}
|
|
|
|
}
|
2018-11-28 00:42:26 +00:00
|
|
|
|
2019-01-25 07:08:21 +00:00
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
|
|
enum ReachedFixedPoint {
|
|
|
|
Yes,
|
|
|
|
No,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ItemMap {
|
2019-02-01 10:33:41 +00:00
|
|
|
pub(crate) fn item_map_query(db: &impl PersistentHirDatabase, krate: Crate) -> Arc<ItemMap> {
|
2019-01-30 19:18:17 +00:00
|
|
|
let start = time::Instant::now();
|
2019-01-30 19:23:14 +00:00
|
|
|
let module_tree = db.module_tree(krate);
|
2019-01-30 19:18:17 +00:00
|
|
|
let input = module_tree
|
|
|
|
.modules()
|
|
|
|
.map(|module_id| {
|
|
|
|
(
|
|
|
|
module_id,
|
2019-01-30 19:23:14 +00:00
|
|
|
db.lower_module_module(Module { krate, module_id }),
|
2019-01-30 19:18:17 +00:00
|
|
|
)
|
|
|
|
})
|
|
|
|
.collect::<FxHashMap<_, _>>();
|
|
|
|
|
2019-01-30 19:23:14 +00:00
|
|
|
let resolver = Resolver::new(db, &input, krate);
|
2019-01-30 19:18:17 +00:00
|
|
|
let res = resolver.resolve();
|
|
|
|
let elapsed = start.elapsed();
|
|
|
|
log::info!("item_map: {:?}", elapsed);
|
|
|
|
Arc::new(res)
|
|
|
|
}
|
|
|
|
|
2019-01-25 07:15:10 +00:00
|
|
|
pub(crate) fn resolve_path(
|
|
|
|
&self,
|
2019-02-01 10:33:41 +00:00
|
|
|
db: &impl PersistentHirDatabase,
|
2019-01-25 07:15:10 +00:00
|
|
|
original_module: Module,
|
|
|
|
path: &Path,
|
|
|
|
) -> PerNs<ModuleDef> {
|
|
|
|
self.resolve_path_fp(db, original_module, path).0
|
|
|
|
}
|
|
|
|
|
2019-01-25 07:17:50 +00:00
|
|
|
// Returns Yes if we are sure that additions to `ItemMap` wouldn't change
|
|
|
|
// the result.
|
2019-01-25 07:15:10 +00:00
|
|
|
fn resolve_path_fp(
|
2019-01-25 07:08:21 +00:00
|
|
|
&self,
|
2019-02-01 10:33:41 +00:00
|
|
|
db: &impl PersistentHirDatabase,
|
2019-01-25 07:08:21 +00:00
|
|
|
original_module: Module,
|
|
|
|
path: &Path,
|
|
|
|
) -> (PerNs<ModuleDef>, ReachedFixedPoint) {
|
|
|
|
let mut curr_per_ns: PerNs<ModuleDef> = PerNs::types(match path.kind {
|
|
|
|
PathKind::Crate => original_module.crate_root(db).into(),
|
|
|
|
PathKind::Self_ | PathKind::Plain => original_module.into(),
|
2018-11-28 00:42:26 +00:00
|
|
|
PathKind::Super => {
|
2019-01-25 07:08:21 +00:00
|
|
|
if let Some(p) = original_module.parent(db) {
|
|
|
|
p.into()
|
|
|
|
} else {
|
|
|
|
log::debug!("super path in root module");
|
|
|
|
return (PerNs::none(), ReachedFixedPoint::Yes);
|
2018-11-28 00:42:26 +00:00
|
|
|
}
|
|
|
|
}
|
2019-01-23 05:21:29 +00:00
|
|
|
PathKind::Abs => {
|
2019-01-25 07:08:21 +00:00
|
|
|
// TODO: absolute use is not supported
|
|
|
|
return (PerNs::none(), ReachedFixedPoint::Yes);
|
2019-01-23 05:21:29 +00:00
|
|
|
}
|
2019-01-25 07:08:21 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
for (i, segment) in path.segments.iter().enumerate() {
|
|
|
|
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 (PerNs::none(), ReachedFixedPoint::No);
|
2019-01-08 13:40:41 +00:00
|
|
|
}
|
2018-11-28 00:42:26 +00:00
|
|
|
};
|
2019-01-25 07:08:21 +00:00
|
|
|
// 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::Crate,
|
|
|
|
};
|
|
|
|
log::debug!("resolving {:?} in other crate", path);
|
2019-01-25 07:16:28 +00:00
|
|
|
let def = module.resolve_path(db, &path);
|
|
|
|
return (def, ReachedFixedPoint::Yes);
|
2019-01-25 07:08:21 +00:00
|
|
|
}
|
2018-11-28 00:42:26 +00:00
|
|
|
|
2019-01-25 07:29:00 +00:00
|
|
|
match self[module.module_id].items.get(&segment.name) {
|
2019-01-25 07:16:28 +00:00
|
|
|
Some(res) if !res.def.is_none() => res.def,
|
2019-01-25 07:08:21 +00:00
|
|
|
_ => {
|
|
|
|
log::debug!("path segment {:?} not found", segment.name);
|
|
|
|
return (PerNs::none(), ReachedFixedPoint::No);
|
2018-12-19 15:04:17 +00:00
|
|
|
}
|
|
|
|
}
|
2019-01-25 07:08:21 +00:00
|
|
|
}
|
|
|
|
ModuleDef::Enum(e) => {
|
|
|
|
// enum variant
|
|
|
|
tested_by!(item_map_enum_importing);
|
2019-01-25 09:41:23 +00:00
|
|
|
match e.variant(db, &segment.name) {
|
|
|
|
Some(variant) => PerNs::both(variant.into(), (*e).into()),
|
2019-01-25 07:08:21 +00:00
|
|
|
None => PerNs::none(),
|
2019-01-08 13:40:41 +00:00
|
|
|
}
|
2018-11-28 00:42:26 +00:00
|
|
|
}
|
2019-01-25 07:08:21 +00:00
|
|
|
_ => {
|
|
|
|
// could be an inherent method call in UFCS form
|
|
|
|
// (`Struct::method`), or some other kind of associated
|
|
|
|
// item... Which we currently don't handle (TODO)
|
|
|
|
log::debug!(
|
|
|
|
"path segment {:?} resolved to non-module {:?}, but is not last",
|
|
|
|
segment.name,
|
|
|
|
curr,
|
|
|
|
);
|
|
|
|
return (PerNs::none(), ReachedFixedPoint::Yes);
|
|
|
|
}
|
|
|
|
};
|
2018-11-28 00:42:26 +00:00
|
|
|
}
|
2019-01-25 07:08:21 +00:00
|
|
|
(curr_per_ns, ReachedFixedPoint::Yes)
|
2018-11-28 00:42:26 +00:00
|
|
|
}
|
|
|
|
}
|
2018-11-28 13:19:01 +00:00
|
|
|
|
|
|
|
#[cfg(test)]
|
2018-12-09 09:48:55 +00:00
|
|
|
mod tests;
|