rust/crates/ra_hir/src/nameres.rs

510 lines
16 KiB
Rust
Raw Normal View History

2018-11-28 01:42:26 +01:00
//! Name resolution algorithm. The end result of the algorithm is `ItemMap`: a
//! map with maps each module to it's scope: the set of items, visible in the
//! 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 interative per-crate algorithm: we start with scopes
//! containing only directly defined items, and then iteratively resolve
//! imports.
//!
//! To make this work nicely in the IDE scenarios, we place `InputModuleItems`
//! 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 plain is to make `InputModuleItems` independent of local
//! modifications (that is, typing inside a function shold not change IMIs),
//! such that the results of name resolution can be preserved unless the module
//! structure itself is modified.
2018-12-27 18:07:21 +01:00
use std::sync::Arc;
2018-11-28 01:42:26 +01:00
use rustc_hash::FxHashMap;
use ra_syntax::{
TextRange,
2018-12-27 18:07:21 +01:00
SyntaxKind::{self, *},
2018-11-28 01:42:26 +01:00
ast::{self, AstNode}
};
2019-01-01 22:30:00 +01:00
use ra_db::{SourceRootId, Cancelable, FileId};
2018-11-28 01:42:26 +01:00
use crate::{
2019-01-01 22:30:00 +01:00
HirFileId,
2018-12-04 21:01:53 +01:00
DefId, DefLoc, DefKind,
2018-11-28 01:42:26 +01:00
SourceItemId, SourceFileItemId, SourceFileItems,
Path, PathKind,
2018-12-09 10:45:47 +01:00
HirDatabase, Crate,
2018-12-27 18:07:21 +01:00
Name, AsName,
2019-01-06 15:33:27 +01:00
module_tree::{ModuleId, ModuleTree},
2018-11-28 01:42:26 +01:00
};
/// Item map is the result of the name resolution. Item map contains, for each
/// module, the set of visible items.
2018-12-19 23:00:54 +01:00
// FIXME: currenty we compute item map per source-root. We should do it per crate instead.
2018-11-28 01:42:26 +01:00
#[derive(Default, Debug, PartialEq, Eq)]
2018-11-28 02:09:44 +01:00
pub struct ItemMap {
pub per_module: FxHashMap<ModuleId, ModuleScope>,
2018-11-28 01:42:26 +01:00
}
#[derive(Debug, Default, PartialEq, Eq, Clone)]
2018-11-28 02:09:44 +01:00
pub struct ModuleScope {
2018-12-27 18:07:21 +01:00
items: FxHashMap<Name, Resolution>,
2018-11-28 01:42:26 +01:00
}
impl ModuleScope {
2018-12-27 18:07:21 +01:00
pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, &'a Resolution)> + 'a {
2018-11-28 01:42:26 +01:00
self.items.iter()
}
2018-12-27 18:07:21 +01:00
pub fn get(&self, name: &Name) -> Option<&Resolution> {
2018-11-28 01:42:26 +01:00
self.items.get(name)
}
}
/// A set of items and imports declared inside a module, without relation to
/// other modules.
///
/// This stands in-between raw syntax and name resolution and alow us to avoid
/// recomputing name res: if `InputModuleItems` are the same, we can avoid
/// running name resolution.
#[derive(Debug, Default, PartialEq, Eq)]
2018-11-28 02:09:44 +01:00
pub struct InputModuleItems {
2019-01-03 19:28:35 +01:00
pub(crate) items: Vec<ModuleItem>,
2018-11-28 01:42:26 +01:00
imports: Vec<Import>,
}
#[derive(Debug, PartialEq, Eq)]
2019-01-03 19:28:35 +01:00
pub(crate) struct ModuleItem {
pub(crate) id: SourceItemId,
pub(crate) name: Name,
2018-11-28 01:42:26 +01:00
kind: SyntaxKind,
vis: Vis,
}
#[derive(Debug, PartialEq, Eq)]
enum Vis {
// Priv,
Other,
}
#[derive(Debug, Clone, PartialEq, Eq)]
struct Import {
path: Path,
kind: ImportKind,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2018-11-28 02:09:44 +01:00
pub struct NamedImport {
pub file_item_id: SourceFileItemId,
pub relative_range: TextRange,
2018-11-28 01:42:26 +01:00
}
impl NamedImport {
2019-01-01 21:21:16 +01:00
// FIXME: this is only here for one use-case in completion. Seems like a
// pretty gross special case.
2018-11-28 02:09:44 +01:00
pub fn range(&self, db: &impl HirDatabase, file_id: FileId) -> TextRange {
2018-11-28 01:42:26 +01:00
let source_item_id = SourceItemId {
2019-01-01 21:21:16 +01:00
file_id: file_id.into(),
item_id: Some(self.file_item_id),
2018-11-28 01:42:26 +01:00
};
let syntax = db.file_item(source_item_id);
let offset = syntax.borrowed().range().start();
self.relative_range + offset
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
enum ImportKind {
Glob,
Named(NamedImport),
}
/// Resolution is basically `DefId` atm, but it should account for stuff like
/// multiple namespaces, ambiguity and errors.
#[derive(Debug, Clone, PartialEq, Eq)]
2018-11-28 02:09:44 +01:00
pub struct Resolution {
2018-11-28 01:42:26 +01:00
/// None for unresolved
pub def_id: PerNs<DefId>,
2018-11-28 01:42:26 +01:00
/// ident by whitch this is imported into local scope.
2018-11-28 02:09:44 +01:00
pub import: Option<NamedImport>,
2018-11-28 01:42:26 +01: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 12:05:03 +01:00
self.take(Namespace::Types)
}
pub fn take_values(self) -> Option<T> {
2019-01-06 12:05:03 +01:00
self.take(Namespace::Values)
}
2018-11-28 01:42:26 +01: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 01:42:26 +01:00
impl InputModuleItems {
2019-01-01 19:17:52 +01:00
pub(crate) fn add_item(
&mut self,
2019-01-01 21:21:16 +01:00
file_id: HirFileId,
2018-11-28 01:42:26 +01:00
file_items: &SourceFileItems,
2019-01-01 19:17:52 +01:00
item: ast::ModuleItem,
) -> Option<()> {
2018-11-28 01:42:26 +01:00
match item {
2019-01-01 19:17:52 +01:00
ast::ModuleItem::StructDef(it) => {
2019-01-01 21:21:16 +01:00
self.items.push(ModuleItem::new(file_id, file_items, it)?)
2019-01-01 19:17:52 +01:00
}
ast::ModuleItem::EnumDef(it) => {
2019-01-01 21:21:16 +01:00
self.items.push(ModuleItem::new(file_id, file_items, it)?)
2019-01-01 19:17:52 +01:00
}
ast::ModuleItem::FnDef(it) => {
2019-01-01 21:21:16 +01:00
self.items.push(ModuleItem::new(file_id, file_items, it)?)
2019-01-01 19:17:52 +01:00
}
ast::ModuleItem::TraitDef(it) => {
2019-01-01 21:21:16 +01:00
self.items.push(ModuleItem::new(file_id, file_items, it)?)
2019-01-01 19:17:52 +01:00
}
ast::ModuleItem::TypeDef(it) => {
2019-01-01 21:21:16 +01:00
self.items.push(ModuleItem::new(file_id, file_items, it)?)
2019-01-01 19:17:52 +01:00
}
ast::ModuleItem::ImplBlock(_) => {
2018-11-28 01:42:26 +01:00
// impls don't define items
}
ast::ModuleItem::UseItem(it) => self.add_use_item(file_items, it),
ast::ModuleItem::ExternCrateItem(_) => {
// TODO
}
2019-01-01 19:17:52 +01:00
ast::ModuleItem::ConstDef(it) => {
2019-01-01 21:21:16 +01:00
self.items.push(ModuleItem::new(file_id, file_items, it)?)
2019-01-01 19:17:52 +01:00
}
ast::ModuleItem::StaticDef(it) => {
2019-01-01 21:21:16 +01:00
self.items.push(ModuleItem::new(file_id, file_items, it)?)
2019-01-01 19:17:52 +01:00
}
ast::ModuleItem::Module(it) => {
2019-01-01 21:21:16 +01:00
self.items.push(ModuleItem::new(file_id, file_items, it)?)
2019-01-01 19:17:52 +01:00
}
2018-11-28 01:42:26 +01:00
}
Some(())
}
fn add_use_item(&mut self, file_items: &SourceFileItems, item: ast::UseItem) {
2018-12-09 11:18:46 +01:00
let file_item_id = file_items.id_of_unchecked(item.syntax());
2018-11-28 01:42:26 +01:00
let start_offset = item.syntax().range().start();
Path::expand_use_item(item, |path, range| {
let kind = match range {
None => ImportKind::Glob,
Some(range) => ImportKind::Named(NamedImport {
file_item_id,
relative_range: range - start_offset,
}),
};
self.imports.push(Import { kind, path })
})
}
}
impl ModuleItem {
2019-01-01 19:17:52 +01:00
fn new<'a>(
2019-01-01 21:21:16 +01:00
file_id: HirFileId,
2019-01-01 19:17:52 +01:00
file_items: &SourceFileItems,
item: impl ast::NameOwner<'a>,
) -> Option<ModuleItem> {
2018-12-27 18:07:21 +01:00
let name = item.name()?.as_name();
2018-11-28 01:42:26 +01:00
let kind = item.syntax().kind();
let vis = Vis::Other;
2019-01-01 19:17:52 +01:00
let item_id = Some(file_items.id_of_unchecked(item.syntax()));
2019-01-01 21:21:16 +01:00
let id = SourceItemId { file_id, item_id };
2018-11-28 01:42:26 +01:00
let res = ModuleItem {
id,
name,
kind,
vis,
};
Some(res)
}
}
pub(crate) struct Resolver<'a, DB> {
2018-12-09 10:24:52 +01:00
db: &'a DB,
input: &'a FxHashMap<ModuleId, Arc<InputModuleItems>>,
source_root: SourceRootId,
module_tree: Arc<ModuleTree>,
result: ItemMap,
2018-11-28 01:42:26 +01:00
}
impl<'a, DB> Resolver<'a, DB>
where
DB: HirDatabase,
{
2018-12-09 10:24:52 +01:00
pub(crate) fn new(
db: &'a DB,
input: &'a FxHashMap<ModuleId, Arc<InputModuleItems>>,
source_root: SourceRootId,
module_tree: Arc<ModuleTree>,
) -> Resolver<'a, DB> {
Resolver {
2018-12-09 10:45:47 +01:00
db,
input,
2018-12-09 10:24:52 +01:00
source_root,
module_tree,
result: ItemMap::default(),
}
}
2018-11-28 01:42:26 +01:00
pub(crate) fn resolve(mut self) -> Cancelable<ItemMap> {
for (&module_id, items) in self.input.iter() {
2019-01-01 19:17:52 +01:00
self.populate_module(module_id, Arc::clone(items))?;
2018-11-28 01:42:26 +01:00
}
for &module_id in self.input.keys() {
self.db.check_canceled()?;
2018-12-09 10:45:47 +01:00
self.resolve_imports(module_id)?;
2018-11-28 01:42:26 +01:00
}
Ok(self.result)
}
2019-01-01 19:17:52 +01:00
fn populate_module(
&mut self,
module_id: ModuleId,
input: Arc<InputModuleItems>,
) -> Cancelable<()> {
2018-11-28 01:42:26 +01:00
let mut module_items = ModuleScope::default();
2018-12-09 11:49:54 +01:00
// Populate extern crates prelude
{
let root_id = module_id.crate_root(&self.module_tree);
2019-01-06 17:58:10 +01:00
let file_id = root_id.source(&self.module_tree).file_id;
2018-12-09 11:49:54 +01:00
let crate_graph = self.db.crate_graph();
2019-01-01 21:21:16 +01:00
if let Some(crate_id) = crate_graph.crate_id_for_crate_root(file_id.as_original_file())
{
2018-12-09 11:49:54 +01:00
let krate = Crate::new(crate_id);
2019-01-06 11:45:41 +01:00
for dep in krate.dependencies(self.db)? {
2018-12-09 11:49:54 +01:00
if let Some(module) = dep.krate.root_module(self.db)? {
2019-01-04 23:37:40 +01:00
let def_id = module.def_id;
2018-12-27 18:07:21 +01:00
self.add_module_item(
&mut module_items,
dep.name.clone(),
PerNs::types(def_id),
);
2018-12-09 11:49:54 +01:00
}
}
};
}
2018-11-28 01:42:26 +01:00
for import in input.imports.iter() {
if let Some(name) = import.path.segments.iter().last() {
if let ImportKind::Named(import) = import.kind {
module_items.items.insert(
name.clone(),
Resolution {
def_id: PerNs::none(),
2018-11-28 01:42:26 +01:00
import: Some(import),
},
);
}
}
}
// Populate explicitly declared items, except modules
2018-11-28 01:42:26 +01:00
for item in input.items.iter() {
if item.kind == MODULE {
continue;
}
// depending on the item kind, the location can define something in
// the values namespace, the types namespace, or both
let kind = DefKind::for_syntax_kind(item.kind);
let def_id = kind.map(|k| {
let def_loc = DefLoc {
kind: k,
source_root_id: self.source_root,
module_id,
2019-01-01 19:17:52 +01:00
source_item_id: item.id,
};
def_loc.id(self.db)
});
2018-11-28 01:42:26 +01:00
let resolution = Resolution {
def_id,
2018-11-28 01:42:26 +01:00
import: None,
};
module_items.items.insert(item.name.clone(), resolution);
}
2018-12-09 11:49:54 +01:00
// Populate modules
2018-12-04 21:01:53 +01:00
for (name, module_id) in module_id.children(&self.module_tree) {
2018-12-19 16:04:17 +01:00
let def_loc = DefLoc {
kind: DefKind::Module,
source_root_id: self.source_root,
module_id,
2019-01-06 17:58:10 +01:00
source_item_id: module_id.source(&self.module_tree),
2018-12-19 16:04:17 +01:00
};
let def_id = def_loc.id(self.db);
self.add_module_item(&mut module_items, name, PerNs::types(def_id));
2018-11-28 01:42:26 +01:00
}
self.result.per_module.insert(module_id, module_items);
2018-12-09 11:49:54 +01:00
Ok(())
}
2018-12-27 18:07:21 +01:00
fn add_module_item(&self, module_items: &mut ModuleScope, name: Name, def_id: PerNs<DefId>) {
2018-12-09 11:49:54 +01:00
let resolution = Resolution {
def_id,
2018-12-09 11:49:54 +01:00
import: None,
};
module_items.items.insert(name, resolution);
2018-11-28 01:42:26 +01:00
}
2018-12-09 10:45:47 +01:00
fn resolve_imports(&mut self, module_id: ModuleId) -> Cancelable<()> {
2018-11-28 01:42:26 +01:00
for import in self.input[&module_id].imports.iter() {
2018-12-09 10:45:47 +01:00
self.resolve_import(module_id, import)?;
2018-11-28 01:42:26 +01:00
}
2018-12-09 10:45:47 +01:00
Ok(())
2018-11-28 01:42:26 +01:00
}
2018-12-09 10:45:47 +01:00
fn resolve_import(&mut self, module_id: ModuleId, import: &Import) -> Cancelable<()> {
2018-11-28 01:42:26 +01:00
let ptr = match import.kind {
2018-12-09 10:45:47 +01:00
ImportKind::Glob => return Ok(()),
2018-11-28 01:42:26 +01:00
ImportKind::Named(ptr) => ptr,
};
2018-12-19 16:04:17 +01:00
let mut curr: ModuleId = match import.path.kind {
2018-12-09 11:49:54 +01:00
PathKind::Plain | PathKind::Self_ => module_id,
2018-11-28 01:42:26 +01:00
PathKind::Super => {
match module_id.parent(&self.module_tree) {
Some(it) => it,
// TODO: error
2018-12-09 10:45:47 +01:00
None => return Ok(()),
2018-11-28 01:42:26 +01:00
}
}
PathKind::Crate => module_id.crate_root(&self.module_tree),
};
2018-12-09 11:49:54 +01:00
for (i, name) in import.path.segments.iter().enumerate() {
2018-11-28 01:42:26 +01:00
let is_last = i == import.path.segments.len() - 1;
let def_id = match self.result.per_module[&curr].items.get(name) {
Some(res) if !res.def_id.is_none() => res.def_id,
_ => return Ok(()),
2018-11-28 01:42:26 +01:00
};
if !is_last {
let type_def_id = if let Some(d) = def_id.take(Namespace::Types) {
d
} else {
return Ok(());
};
curr = match type_def_id.loc(self.db) {
2018-12-04 21:01:53 +01:00
DefLoc {
kind: DefKind::Module,
2018-12-19 22:57:13 +01:00
module_id: target_module_id,
2018-12-19 16:04:17 +01:00
source_root_id,
2018-12-04 21:01:53 +01:00
..
2018-12-19 16:04:17 +01:00
} => {
if source_root_id == self.source_root {
2018-12-19 22:57:13 +01:00
target_module_id
2018-12-19 16:04:17 +01:00
} else {
2019-01-06 13:16:21 +01:00
let module = crate::code_model_api::Module::new(type_def_id);
2018-12-19 22:57:13 +01:00
let path = Path {
segments: import.path.segments[i + 1..].iter().cloned().collect(),
kind: PathKind::Crate,
};
let def_id = module.resolve_path(self.db, &path)?;
if !def_id.is_none() {
2018-12-19 22:57:13 +01:00
self.update(module_id, |items| {
let res = Resolution {
def_id: def_id,
2018-12-19 22:57:13 +01:00
import: Some(ptr),
};
items.items.insert(name.clone(), res);
})
}
2018-12-19 16:04:17 +01:00
return Ok(());
}
}
2018-12-09 10:45:47 +01:00
_ => return Ok(()),
2018-11-28 01:42:26 +01:00
}
} else {
self.update(module_id, |items| {
let res = Resolution {
def_id: def_id,
2018-11-28 01:42:26 +01:00
import: Some(ptr),
};
items.items.insert(name.clone(), res);
})
}
}
2018-12-09 10:45:47 +01:00
Ok(())
2018-11-28 01:42:26 +01:00
}
fn update(&mut self, module_id: ModuleId, f: impl FnOnce(&mut ModuleScope)) {
let module_items = self.result.per_module.get_mut(&module_id).unwrap();
f(module_items)
}
}
2018-11-28 14:19:01 +01:00
#[cfg(test)]
2018-12-09 10:48:55 +01:00
mod tests;