rust-analyzer/crates/ra_hir/src/nameres.rs

165 lines
4.6 KiB
Rust
Raw Normal View History

//! 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.
//!
//! 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.
//!
//! 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
//! 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.
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)
}
}
/// `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, 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
}
#[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
}
}
impl<T> PerNs<T> {
pub fn none() -> PerNs<T> {
2019-02-08 11:49:43 +00:00
PerNs { types: None, values: None }
}
pub fn values(t: T) -> PerNs<T> {
2019-02-08 11:49:43 +00:00
PerNs { types: None, values: Some(t) }
}
pub fn types(t: T) -> PerNs<T> {
2019-02-08 11:49:43 +00:00
PerNs { types: Some(t), values: None }
}
pub fn both(types: T, values: T) -> PerNs<T> {
2019-02-08 11:49:43 +00:00
PerNs { types: Some(types), values: Some(values) }
}
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()
}
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)
}
pub fn take_values(self) -> Option<T> {
2019-01-06 11:05:03 +00:00
self.take(Namespace::Values)
}
2018-11-28 00:42:26 +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() }
}
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
}
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) }
}
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-11-28 00:42:26 +00:00
#[derive(Debug, Clone)]
struct ResolvePathResult {
resolved_def: PerNs<ModuleDef>,
segment_index: Option<usize>,
reached_fixedpoint: ReachedFixedPoint,
}
impl ResolvePathResult {
fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None)
}
fn with(
resolved_def: PerNs<ModuleDef>,
reached_fixedpoint: ReachedFixedPoint,
segment_index: Option<usize>,
) -> ResolvePathResult {
ResolvePathResult { resolved_def, reached_fixedpoint, segment_index }
}
}
2019-02-11 22:11:12 +00:00
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ResolveMode {
Import,
Other,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ReachedFixedPoint {
Yes,
No,
}