(Some(path), Some(module)) => (path.clone(), module),
_ => return Ok(()),
};
- let def_id = match module.resolve_path(ctx.db, path)? {
+ let def_id = match module.resolve_path(ctx.db, path)?.take_types() {
Some(it) => it,
None => return Ok(()),
};
use crate::db;
+use hir::PerNs;
+
/// `CompletionItem` describes a single completion variant in the editor pop-up.
/// It is basically a POD with various properties. To construct a
/// `CompletionItem`, use `new` method and the `Builder` struct.
Keyword,
Module,
Function,
+ Struct,
+ Enum,
Binding,
}
db: &db::RootDatabase,
resolution: &hir::Resolution,
) -> Builder {
- if let Some(def_id) = resolution.def_id {
- if let Ok(def) = def_id.resolve(db) {
- let kind = match def {
- hir::Def::Module(..) => CompletionItemKind::Module,
- hir::Def::Function(..) => CompletionItemKind::Function,
- _ => return self,
- };
- self.kind = Some(kind);
- }
- }
+ let resolved = resolution.def_id.and_then(|d| d.resolve(db).ok());
+ let kind = match resolved {
+ PerNs {
+ types: Some(hir::Def::Module(..)),
+ ..
+ } => CompletionItemKind::Module,
+ PerNs {
+ types: Some(hir::Def::Struct(..)),
+ ..
+ } => CompletionItemKind::Struct,
+ PerNs {
+ types: Some(hir::Def::Enum(..)),
+ ..
+ } => CompletionItemKind::Enum,
+ PerNs {
+ values: Some(hir::Def::Function(..)),
+ ..
+ } => CompletionItemKind::Function,
+ _ => return self,
+ };
+ self.kind = Some(kind);
self
}
}
fn submodules() for hir::db::SubmodulesQuery;
fn infer() for hir::db::InferQuery;
fn type_for_def() for hir::db::TypeForDefQuery;
- fn struct_data() for db::StructDataQuery;
- fn enum_data() for db::EnumDataQuery;
+ fn struct_data() for hir::db::StructDataQuery;
+ fn enum_data() for hir::db::EnumDataQuery;
}
}
}
pub use self::{
path::{Path, PathKind},
krate::Crate,
- module::{Module, ModuleId, Problem, nameres::ItemMap, ModuleScope, Resolution},
+ module::{Module, ModuleId, Problem, nameres::{ItemMap, PerNs, Namespace}, ModuleScope, Resolution},
function::{Function, FnScopes},
adt::{Struct, Enum},
};
Struct,
Enum,
Item,
+
+ StructCtor,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
}
impl DefKind {
- pub(crate) fn for_syntax_kind(kind: SyntaxKind) -> Option<DefKind> {
+ pub(crate) fn for_syntax_kind(kind: SyntaxKind) -> PerNs<DefKind> {
match kind {
- SyntaxKind::FN_DEF => Some(DefKind::Function),
- SyntaxKind::MODULE => Some(DefKind::Module),
+ SyntaxKind::FN_DEF => PerNs::values(DefKind::Function),
+ SyntaxKind::MODULE => PerNs::types(DefKind::Module),
+ SyntaxKind::STRUCT_DEF => PerNs::both(DefKind::Struct, DefKind::StructCtor),
+ SyntaxKind::ENUM_DEF => PerNs::types(DefKind::Enum),
// These define items, but don't have their own DefKinds yet:
- SyntaxKind::STRUCT_DEF => Some(DefKind::Struct),
- SyntaxKind::ENUM_DEF => Some(DefKind::Enum),
- SyntaxKind::TRAIT_DEF => Some(DefKind::Item),
- SyntaxKind::TYPE_DEF => Some(DefKind::Item),
- SyntaxKind::CONST_DEF => Some(DefKind::Item),
- SyntaxKind::STATIC_DEF => Some(DefKind::Item),
- _ => None,
+ SyntaxKind::TRAIT_DEF => PerNs::types(DefKind::Item),
+ SyntaxKind::TYPE_DEF => PerNs::types(DefKind::Item),
+ SyntaxKind::CONST_DEF => PerNs::values(DefKind::Item),
+ SyntaxKind::STATIC_DEF => PerNs::values(DefKind::Item),
+ _ => PerNs::none(),
}
}
}
let enum_def = Enum::new(self);
Def::Enum(enum_def)
}
+ DefKind::StructCtor => Def::Item,
DefKind::Item => Def::Item,
};
Ok(res)
arena::{Arena, Id},
};
-pub use self::nameres::{ModuleScope, Resolution};
+pub use self::nameres::{ModuleScope, Resolution, Namespace, PerNs};
/// `Module` is API entry point to get all the information
/// about a particular module.
Ok(res)
}
- pub fn resolve_path(&self, db: &impl HirDatabase, path: Path) -> Cancelable<Option<DefId>> {
- let mut curr = match path.kind {
- PathKind::Crate => self.crate_root(),
- PathKind::Self_ | PathKind::Plain => self.clone(),
- PathKind::Super => ctry!(self.parent()),
- }
- .def_id(db);
+ pub fn resolve_path(&self, db: &impl HirDatabase, path: Path) -> Cancelable<PerNs<DefId>> {
+ let mut curr_per_ns = PerNs::types(
+ match path.kind {
+ PathKind::Crate => self.crate_root(),
+ PathKind::Self_ | PathKind::Plain => self.clone(),
+ PathKind::Super => {
+ if let Some(p) = self.parent() {
+ p
+ } else {
+ return Ok(PerNs::none());
+ }
+ }
+ }
+ .def_id(db),
+ );
let segments = path.segments;
for name in segments.iter() {
+ let curr = if let Some(r) = curr_per_ns.as_ref().take(Namespace::Types) {
+ r
+ } else {
+ return Ok(PerNs::none());
+ };
let module = match curr.loc(db) {
DefLoc {
kind: DefKind::Module,
module_id,
..
} => Module::new(db, source_root_id, module_id)?,
- _ => return Ok(None),
+ // TODO here would be the place to handle enum variants...
+ _ => return Ok(PerNs::none()),
};
let scope = module.scope(db)?;
- curr = ctry!(ctry!(scope.get(&name)).def_id);
+ curr_per_ns = if let Some(r) = scope.get(&name) {
+ r.def_id
+ } else {
+ return Ok(PerNs::none());
+ };
}
- Ok(Some(curr))
+ Ok(curr_per_ns)
}
pub fn problems(&self, db: &impl HirDatabase) -> Vec<(SyntaxNode, Problem)> {
}
}
-/// Phisically, rust source is organized as a set of files, but logically it is
+/// Physically, rust source is organized as a set of files, but logically it is
/// organized as a tree of modules. Usually, a single file corresponds to a
/// single module, but it is not nessary the case.
///
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Resolution {
/// None for unresolved
- pub def_id: Option<DefId>,
+ pub def_id: PerNs<DefId>,
/// ident by whitch this is imported into local scope.
pub import: Option<NamedImport>,
}
-// #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
-// enum Namespace {
-// Types,
-// Values,
-// }
+#[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> {
+ self.types
+ }
+
+ pub fn take_values(self) -> Option<T> {
+ self.values
+ }
-// #[derive(Debug)]
-// struct PerNs<T> {
-// types: Option<T>,
-// values: Option<T>,
-// }
+ 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),
+ }
+ }
+}
impl InputModuleItems {
pub(crate) fn new<'a>(
for dep in krate.dependencies(self.db) {
if let Some(module) = dep.krate.root_module(self.db)? {
let def_id = module.def_id(self.db);
- self.add_module_item(&mut module_items, dep.name, def_id);
+ self.add_module_item(&mut module_items, dep.name, PerNs::types(def_id));
}
}
};
module_items.items.insert(
name.clone(),
Resolution {
- def_id: None,
+ def_id: PerNs::none(),
import: Some(import),
},
);
if item.kind == MODULE {
continue;
}
- let def_loc = DefLoc {
- kind: DefKind::for_syntax_kind(item.kind).unwrap_or(DefKind::Item),
- source_root_id: self.source_root,
- module_id,
- source_item_id: SourceItemId {
- file_id,
- item_id: Some(item.id),
- },
- };
- let def_id = def_loc.id(self.db);
+ // 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,
+ source_item_id: SourceItemId {
+ file_id,
+ item_id: Some(item.id),
+ },
+ };
+ def_loc.id(self.db)
+ });
let resolution = Resolution {
- def_id: Some(def_id),
+ def_id,
import: None,
};
module_items.items.insert(item.name.clone(), resolution);
source_item_id: module_id.source(&self.module_tree).0,
};
let def_id = def_loc.id(self.db);
- self.add_module_item(&mut module_items, name, def_id);
+ self.add_module_item(&mut module_items, name, PerNs::types(def_id));
}
self.result.per_module.insert(module_id, module_items);
Ok(())
}
- fn add_module_item(&self, module_items: &mut ModuleScope, name: SmolStr, def_id: DefId) {
+ fn add_module_item(&self, module_items: &mut ModuleScope, name: SmolStr, def_id: PerNs<DefId>) {
let resolution = Resolution {
- def_id: Some(def_id),
+ def_id,
import: None,
};
module_items.items.insert(name, resolution);
let is_last = i == import.path.segments.len() - 1;
let def_id = match self.result.per_module[&curr].items.get(name) {
- None => return Ok(()),
- Some(res) => match res.def_id {
- Some(it) => it,
- None => return Ok(()),
- },
+ Some(res) if !res.def_id.is_none() => res.def_id,
+ _ => return Ok(()),
};
if !is_last {
- curr = match def_id.loc(self.db) {
+ 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) {
DefLoc {
kind: DefKind::Module,
module_id: target_module_id,
segments: import.path.segments[i + 1..].iter().cloned().collect(),
kind: PathKind::Crate,
};
- if let Some(def_id) = module.resolve_path(self.db, path)? {
+ let def_id = module.resolve_path(self.db, path)?;
+ if !def_id.is_none() {
self.update(module_id, |items| {
let res = Resolution {
- def_id: Some(def_id),
+ def_id: def_id,
import: Some(ptr),
};
items.items.insert(name.clone(), res);
} else {
self.update(module_id, |items| {
let res = Resolution {
- def_id: Some(def_id),
+ def_id: def_id,
import: Some(ptr),
};
items.items.insert(name.clone(), res);
);
let name = SmolStr::from("Baz");
let resolution = &item_map.per_module[&module_id].items[&name];
- assert!(resolution.def_id.is_some());
+ assert!(resolution.def_id.take_types().is_some());
}
#[test]
);
let name = SmolStr::from("Baz");
let resolution = &item_map.per_module[&module_id].items[&name];
- assert!(resolution.def_id.is_some());
+ assert!(resolution.def_id.take_types().is_some());
}
#[test]
let name = SmolStr::from("Baz");
let resolution = &item_map.per_module[&module_id].items[&name];
- assert!(resolution.def_id.is_some());
+ assert!(resolution.def_id.take_types().is_some());
}
#[test]
SyntaxNodeRef
};
-use crate::{Def, DefId, FnScopes, Module, Function, Path, db::HirDatabase};
+use crate::{
+ Def, DefId, FnScopes, Module, Function,
+ Path, db::HirDatabase,
+ module::nameres::Namespace
+};
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum Ty {
}
// Resolve in module (in type namespace)
- let resolved = if let Some(r) = module.resolve_path(db, path)? {
- r
- } else {
- return Ok(Ty::Unknown);
- };
+ let resolved =
+ if let Some(r) = module.resolve_path(db, path)?.take(Namespace::Types) {
+ r
+ } else {
+ return Ok(Ty::Unknown);
+ };
let ty = db.type_for_def(resolved)?;
ty
}
};
// resolve in module
- let resolved = ctry!(self.module.resolve_path(self.db, path)?);
+ let resolved = ctry!(self
+ .module
+ .resolve_path(self.db, path)?
+ .take(Namespace::Values));
let ty = self.db.type_for_def(resolved)?;
// TODO we will need to add type variables for type parameters etc. here
Ok(Some(ty))
[86; 90) 'C(1)': [unknown]
[72; 153) '{ ...a.c; }': ()
-[86; 87) 'C': C
+[86; 87) 'C': [unknown]
[107; 108) 'a': A
[114; 132) 'A { b:... C() }': [unknown]
[138; 141) 'a.b': [unknown]
[147; 150) 'a.c': [unknown]
-[96; 97) 'B': B
+[96; 97) 'B': [unknown]
[88; 89) '1': [unknown]
[82; 83) 'c': [unknown]
CompletionItemKind::Snippet => Snippet,
CompletionItemKind::Module => Module,
CompletionItemKind::Function => Function,
+ CompletionItemKind::Struct => Struct,
+ CompletionItemKind::Enum => Enum,
CompletionItemKind::Binding => Variable,
}
}