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-03-13 13:38:02 +00:00
|
|
|
pub(crate) mod crate_def_map;
|
2019-01-23 05:21:29 +00:00
|
|
|
|
2019-03-14 09:54:03 +00:00
|
|
|
use rustc_hash::FxHashMap;
|
2019-02-11 22:11:12 +00:00
|
|
|
use ra_db::Edition;
|
2018-11-28 00:42:26 +00:00
|
|
|
|
|
|
|
use crate::{
|
2019-03-14 09:54:03 +00:00
|
|
|
ModuleDef, Name,
|
|
|
|
nameres::lower::ImportId,
|
2018-11-28 00:42:26 +00:00
|
|
|
};
|
|
|
|
|
2019-03-14 09:54:03 +00:00
|
|
|
pub(crate) use self::crate_def_map::{CrateDefMap, ModuleId};
|
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 {
|
2019-01-26 21:52:04 +00:00
|
|
|
pub(crate) 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.
|
2019-02-10 15:19:50 +00:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
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>,
|
|
|
|
}
|
|
|
|
|
2019-01-27 19:50:57 +00:00
|
|
|
impl<T> Default for PerNs<T> {
|
|
|
|
fn default() -> Self {
|
2019-02-08 11:49:43 +00:00
|
|
|
PerNs { types: None, values: None }
|
2019-01-27 19:50:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-24 19:32:39 +00:00
|
|
|
impl<T> PerNs<T> {
|
|
|
|
pub fn none() -> PerNs<T> {
|
2019-02-08 11:49:43 +00:00
|
|
|
PerNs { types: None, values: None }
|
2018-12-24 19:32:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn values(t: T) -> PerNs<T> {
|
2019-02-08 11:49:43 +00:00
|
|
|
PerNs { types: None, values: Some(t) }
|
2018-12-24 19:32:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn types(t: T) -> PerNs<T> {
|
2019-02-08 11:49:43 +00:00
|
|
|
PerNs { types: Some(t), values: None }
|
2018-12-24 19:32:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn both(types: T, values: T) -> PerNs<T> {
|
2019-02-08 11:49:43 +00:00
|
|
|
PerNs { types: Some(types), values: Some(values) }
|
2018-12-24 19:32:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_none(&self) -> bool {
|
|
|
|
self.types.is_none() && self.values.is_none()
|
|
|
|
}
|
|
|
|
|
2019-01-26 21:52:04 +00:00
|
|
|
pub fn is_both(&self) -> bool {
|
|
|
|
self.types.is_some() && self.values.is_some()
|
|
|
|
}
|
|
|
|
|
2018-12-24 19:32:39 +00:00
|
|
|
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> {
|
2019-02-08 11:49:43 +00:00
|
|
|
PerNs { types: self.types.as_ref(), values: self.values.as_ref() }
|
2018-12-24 19:32:39 +00:00
|
|
|
}
|
|
|
|
|
2019-02-11 14:29:20 +00:00
|
|
|
pub fn or(self, other: PerNs<T>) -> PerNs<T> {
|
2019-02-08 11:49:43 +00:00
|
|
|
PerNs { types: self.types.or(other.types), values: self.values.or(other.values) }
|
2019-01-26 21:52:04 +00:00
|
|
|
}
|
|
|
|
|
2018-12-24 19:32:39 +00:00
|
|
|
pub fn and_then<U>(self, f: impl Fn(T) -> Option<U>) -> PerNs<U> {
|
2019-02-08 11:49:43 +00:00
|
|
|
PerNs { types: self.types.and_then(&f), values: self.values.and_then(&f) }
|
2018-12-24 19:32:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn map<U>(self, f: impl Fn(T) -> U) -> PerNs<U> {
|
2019-02-08 11:49:43 +00:00
|
|
|
PerNs { types: self.types.map(&f), values: self.values.map(&f) }
|
2018-12-24 19:32:39 +00:00
|
|
|
}
|
|
|
|
}
|
2018-11-28 00:42:26 +00:00
|
|
|
|
2019-02-21 10:04:14 +00:00
|
|
|
#[derive(Debug, Clone)]
|
2019-02-21 22:11:21 +00:00
|
|
|
struct ResolvePathResult {
|
|
|
|
resolved_def: PerNs<ModuleDef>,
|
|
|
|
segment_index: Option<usize>,
|
2019-02-21 10:04:14 +00:00
|
|
|
reached_fixedpoint: ReachedFixedPoint,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ResolvePathResult {
|
|
|
|
fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
|
|
|
|
ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn with(
|
2019-02-21 22:11:21 +00:00
|
|
|
resolved_def: PerNs<ModuleDef>,
|
2019-02-21 10:04:14 +00:00
|
|
|
reached_fixedpoint: ReachedFixedPoint,
|
|
|
|
segment_index: Option<usize>,
|
|
|
|
) -> ResolvePathResult {
|
2019-02-21 22:11:21 +00:00
|
|
|
ResolvePathResult { resolved_def, reached_fixedpoint, segment_index }
|
2019-02-21 10:04:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-11 22:11:12 +00:00
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
|
|
enum ResolveMode {
|
|
|
|
Import,
|
|
|
|
Other,
|
|
|
|
}
|
|
|
|
|
2019-01-25 07:08:21 +00:00
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
|
|
enum ReachedFixedPoint {
|
|
|
|
Yes,
|
|
|
|
No,
|
|
|
|
}
|