mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 06:11:35 +00:00
Do name resolution by namespace (types/values)
This commit is contained in:
parent
b5b68f2094
commit
4ff1618520
10 changed files with 212 additions and 84 deletions
|
@ -8,7 +8,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) -> C
|
||||||
(Some(path), Some(module)) => (path.clone(), module),
|
(Some(path), Some(module)) => (path.clone(), module),
|
||||||
_ => return Ok(()),
|
_ => 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,
|
Some(it) => it,
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
use crate::db;
|
use crate::db;
|
||||||
|
|
||||||
|
use hir::PerNs;
|
||||||
|
|
||||||
/// `CompletionItem` describes a single completion variant in the editor pop-up.
|
/// `CompletionItem` describes a single completion variant in the editor pop-up.
|
||||||
/// It is basically a POD with various properties. To construct a
|
/// It is basically a POD with various properties. To construct a
|
||||||
/// `CompletionItem`, use `new` method and the `Builder` struct.
|
/// `CompletionItem`, use `new` method and the `Builder` struct.
|
||||||
|
@ -25,6 +27,8 @@ pub enum CompletionItemKind {
|
||||||
Keyword,
|
Keyword,
|
||||||
Module,
|
Module,
|
||||||
Function,
|
Function,
|
||||||
|
Struct,
|
||||||
|
Enum,
|
||||||
Binding,
|
Binding,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,16 +121,27 @@ impl Builder {
|
||||||
db: &db::RootDatabase,
|
db: &db::RootDatabase,
|
||||||
resolution: &hir::Resolution,
|
resolution: &hir::Resolution,
|
||||||
) -> Builder {
|
) -> Builder {
|
||||||
if let Some(def_id) = resolution.def_id {
|
let resolved = resolution.def_id.and_then(|d| d.resolve(db).ok());
|
||||||
if let Ok(def) = def_id.resolve(db) {
|
let kind = match resolved {
|
||||||
let kind = match def {
|
PerNs {
|
||||||
hir::Def::Module(..) => CompletionItemKind::Module,
|
types: Some(hir::Def::Module(..)),
|
||||||
hir::Def::Function(..) => CompletionItemKind::Function,
|
..
|
||||||
|
} => 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,
|
_ => return self,
|
||||||
};
|
};
|
||||||
self.kind = Some(kind);
|
self.kind = Some(kind);
|
||||||
}
|
|
||||||
}
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,8 +95,8 @@ salsa::database_storage! {
|
||||||
fn submodules() for hir::db::SubmodulesQuery;
|
fn submodules() for hir::db::SubmodulesQuery;
|
||||||
fn infer() for hir::db::InferQuery;
|
fn infer() for hir::db::InferQuery;
|
||||||
fn type_for_def() for hir::db::TypeForDefQuery;
|
fn type_for_def() for hir::db::TypeForDefQuery;
|
||||||
fn struct_data() for db::StructDataQuery;
|
fn struct_data() for hir::db::StructDataQuery;
|
||||||
fn enum_data() for db::EnumDataQuery;
|
fn enum_data() for hir::db::EnumDataQuery;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ use crate::{
|
||||||
pub use self::{
|
pub use self::{
|
||||||
path::{Path, PathKind},
|
path::{Path, PathKind},
|
||||||
krate::Crate,
|
krate::Crate,
|
||||||
module::{Module, ModuleId, Problem, nameres::ItemMap, ModuleScope, Resolution},
|
module::{Module, ModuleId, Problem, nameres::{ItemMap, PerNs, Namespace}, ModuleScope, Resolution},
|
||||||
function::{Function, FnScopes},
|
function::{Function, FnScopes},
|
||||||
adt::{Struct, Enum},
|
adt::{Struct, Enum},
|
||||||
};
|
};
|
||||||
|
@ -61,6 +61,8 @@ pub(crate) enum DefKind {
|
||||||
Struct,
|
Struct,
|
||||||
Enum,
|
Enum,
|
||||||
Item,
|
Item,
|
||||||
|
|
||||||
|
StructCtor,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
@ -72,18 +74,18 @@ pub struct DefLoc {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DefKind {
|
impl DefKind {
|
||||||
pub(crate) fn for_syntax_kind(kind: SyntaxKind) -> Option<DefKind> {
|
pub(crate) fn for_syntax_kind(kind: SyntaxKind) -> PerNs<DefKind> {
|
||||||
match kind {
|
match kind {
|
||||||
SyntaxKind::FN_DEF => Some(DefKind::Function),
|
SyntaxKind::FN_DEF => PerNs::values(DefKind::Function),
|
||||||
SyntaxKind::MODULE => Some(DefKind::Module),
|
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:
|
// These define items, but don't have their own DefKinds yet:
|
||||||
SyntaxKind::STRUCT_DEF => Some(DefKind::Struct),
|
SyntaxKind::TRAIT_DEF => PerNs::types(DefKind::Item),
|
||||||
SyntaxKind::ENUM_DEF => Some(DefKind::Enum),
|
SyntaxKind::TYPE_DEF => PerNs::types(DefKind::Item),
|
||||||
SyntaxKind::TRAIT_DEF => Some(DefKind::Item),
|
SyntaxKind::CONST_DEF => PerNs::values(DefKind::Item),
|
||||||
SyntaxKind::TYPE_DEF => Some(DefKind::Item),
|
SyntaxKind::STATIC_DEF => PerNs::values(DefKind::Item),
|
||||||
SyntaxKind::CONST_DEF => Some(DefKind::Item),
|
_ => PerNs::none(),
|
||||||
SyntaxKind::STATIC_DEF => Some(DefKind::Item),
|
|
||||||
_ => None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,6 +130,7 @@ impl DefId {
|
||||||
let enum_def = Enum::new(self);
|
let enum_def = Enum::new(self);
|
||||||
Def::Enum(enum_def)
|
Def::Enum(enum_def)
|
||||||
}
|
}
|
||||||
|
DefKind::StructCtor => Def::Item,
|
||||||
DefKind::Item => Def::Item,
|
DefKind::Item => Def::Item,
|
||||||
};
|
};
|
||||||
Ok(res)
|
Ok(res)
|
||||||
|
|
|
@ -17,7 +17,7 @@ use crate::{
|
||||||
arena::{Arena, Id},
|
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
|
/// `Module` is API entry point to get all the information
|
||||||
/// about a particular module.
|
/// about a particular module.
|
||||||
|
@ -115,16 +115,29 @@ impl Module {
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_path(&self, db: &impl HirDatabase, path: Path) -> Cancelable<Option<DefId>> {
|
pub fn resolve_path(&self, db: &impl HirDatabase, path: Path) -> Cancelable<PerNs<DefId>> {
|
||||||
let mut curr = match path.kind {
|
let mut curr_per_ns = PerNs::types(
|
||||||
|
match path.kind {
|
||||||
PathKind::Crate => self.crate_root(),
|
PathKind::Crate => self.crate_root(),
|
||||||
PathKind::Self_ | PathKind::Plain => self.clone(),
|
PathKind::Self_ | PathKind::Plain => self.clone(),
|
||||||
PathKind::Super => ctry!(self.parent()),
|
PathKind::Super => {
|
||||||
|
if let Some(p) = self.parent() {
|
||||||
|
p
|
||||||
|
} else {
|
||||||
|
return Ok(PerNs::none());
|
||||||
}
|
}
|
||||||
.def_id(db);
|
}
|
||||||
|
}
|
||||||
|
.def_id(db),
|
||||||
|
);
|
||||||
|
|
||||||
let segments = path.segments;
|
let segments = path.segments;
|
||||||
for name in segments.iter() {
|
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) {
|
let module = match curr.loc(db) {
|
||||||
DefLoc {
|
DefLoc {
|
||||||
kind: DefKind::Module,
|
kind: DefKind::Module,
|
||||||
|
@ -132,12 +145,17 @@ impl Module {
|
||||||
module_id,
|
module_id,
|
||||||
..
|
..
|
||||||
} => Module::new(db, source_root_id, 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)?;
|
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)> {
|
pub fn problems(&self, db: &impl HirDatabase) -> Vec<(SyntaxNode, Problem)> {
|
||||||
|
@ -145,7 +163,7 @@ impl Module {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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
|
/// organized as a tree of modules. Usually, a single file corresponds to a
|
||||||
/// single module, but it is not nessary the case.
|
/// single module, but it is not nessary the case.
|
||||||
///
|
///
|
||||||
|
|
|
@ -118,22 +118,96 @@ enum ImportKind {
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Resolution {
|
pub struct Resolution {
|
||||||
/// None for unresolved
|
/// None for unresolved
|
||||||
pub def_id: Option<DefId>,
|
pub def_id: PerNs<DefId>,
|
||||||
/// ident by whitch this is imported into local scope.
|
/// ident by whitch this is imported into local scope.
|
||||||
pub import: Option<NamedImport>,
|
pub import: Option<NamedImport>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
// enum Namespace {
|
pub enum Namespace {
|
||||||
// Types,
|
Types,
|
||||||
// Values,
|
Values,
|
||||||
// }
|
}
|
||||||
|
|
||||||
// #[derive(Debug)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
// struct PerNs<T> {
|
pub struct PerNs<T> {
|
||||||
// types: Option<T>,
|
pub types: Option<T>,
|
||||||
// values: 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
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
impl InputModuleItems {
|
||||||
pub(crate) fn new<'a>(
|
pub(crate) fn new<'a>(
|
||||||
|
@ -254,7 +328,7 @@ where
|
||||||
for dep in krate.dependencies(self.db) {
|
for dep in krate.dependencies(self.db) {
|
||||||
if let Some(module) = dep.krate.root_module(self.db)? {
|
if let Some(module) = dep.krate.root_module(self.db)? {
|
||||||
let def_id = module.def_id(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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -265,7 +339,7 @@ where
|
||||||
module_items.items.insert(
|
module_items.items.insert(
|
||||||
name.clone(),
|
name.clone(),
|
||||||
Resolution {
|
Resolution {
|
||||||
def_id: None,
|
def_id: PerNs::none(),
|
||||||
import: Some(import),
|
import: Some(import),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -277,8 +351,12 @@ where
|
||||||
if item.kind == MODULE {
|
if item.kind == MODULE {
|
||||||
continue;
|
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 {
|
let def_loc = DefLoc {
|
||||||
kind: DefKind::for_syntax_kind(item.kind).unwrap_or(DefKind::Item),
|
kind: k,
|
||||||
source_root_id: self.source_root,
|
source_root_id: self.source_root,
|
||||||
module_id,
|
module_id,
|
||||||
source_item_id: SourceItemId {
|
source_item_id: SourceItemId {
|
||||||
|
@ -286,9 +364,10 @@ where
|
||||||
item_id: Some(item.id),
|
item_id: Some(item.id),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let def_id = def_loc.id(self.db);
|
def_loc.id(self.db)
|
||||||
|
});
|
||||||
let resolution = Resolution {
|
let resolution = Resolution {
|
||||||
def_id: Some(def_id),
|
def_id,
|
||||||
import: None,
|
import: None,
|
||||||
};
|
};
|
||||||
module_items.items.insert(item.name.clone(), resolution);
|
module_items.items.insert(item.name.clone(), resolution);
|
||||||
|
@ -303,16 +382,16 @@ where
|
||||||
source_item_id: module_id.source(&self.module_tree).0,
|
source_item_id: module_id.source(&self.module_tree).0,
|
||||||
};
|
};
|
||||||
let def_id = def_loc.id(self.db);
|
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);
|
self.result.per_module.insert(module_id, module_items);
|
||||||
Ok(())
|
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 {
|
let resolution = Resolution {
|
||||||
def_id: Some(def_id),
|
def_id,
|
||||||
import: None,
|
import: None,
|
||||||
};
|
};
|
||||||
module_items.items.insert(name, resolution);
|
module_items.items.insert(name, resolution);
|
||||||
|
@ -347,15 +426,17 @@ where
|
||||||
let is_last = i == import.path.segments.len() - 1;
|
let is_last = i == import.path.segments.len() - 1;
|
||||||
|
|
||||||
let def_id = match self.result.per_module[&curr].items.get(name) {
|
let def_id = match self.result.per_module[&curr].items.get(name) {
|
||||||
None => return Ok(()),
|
Some(res) if !res.def_id.is_none() => res.def_id,
|
||||||
Some(res) => match res.def_id {
|
_ => return Ok(()),
|
||||||
Some(it) => it,
|
|
||||||
None => return Ok(()),
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if !is_last {
|
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 {
|
DefLoc {
|
||||||
kind: DefKind::Module,
|
kind: DefKind::Module,
|
||||||
module_id: target_module_id,
|
module_id: target_module_id,
|
||||||
|
@ -370,10 +451,11 @@ where
|
||||||
segments: import.path.segments[i + 1..].iter().cloned().collect(),
|
segments: import.path.segments[i + 1..].iter().cloned().collect(),
|
||||||
kind: PathKind::Crate,
|
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| {
|
self.update(module_id, |items| {
|
||||||
let res = Resolution {
|
let res = Resolution {
|
||||||
def_id: Some(def_id),
|
def_id: def_id,
|
||||||
import: Some(ptr),
|
import: Some(ptr),
|
||||||
};
|
};
|
||||||
items.items.insert(name.clone(), res);
|
items.items.insert(name.clone(), res);
|
||||||
|
@ -387,7 +469,7 @@ where
|
||||||
} else {
|
} else {
|
||||||
self.update(module_id, |items| {
|
self.update(module_id, |items| {
|
||||||
let res = Resolution {
|
let res = Resolution {
|
||||||
def_id: Some(def_id),
|
def_id: def_id,
|
||||||
import: Some(ptr),
|
import: Some(ptr),
|
||||||
};
|
};
|
||||||
items.items.insert(name.clone(), res);
|
items.items.insert(name.clone(), res);
|
||||||
|
|
|
@ -40,7 +40,7 @@ fn item_map_smoke_test() {
|
||||||
);
|
);
|
||||||
let name = SmolStr::from("Baz");
|
let name = SmolStr::from("Baz");
|
||||||
let resolution = &item_map.per_module[&module_id].items[&name];
|
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]
|
#[test]
|
||||||
|
@ -59,7 +59,7 @@ fn test_self() {
|
||||||
);
|
);
|
||||||
let name = SmolStr::from("Baz");
|
let name = SmolStr::from("Baz");
|
||||||
let resolution = &item_map.per_module[&module_id].items[&name];
|
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]
|
#[test]
|
||||||
|
@ -92,7 +92,7 @@ fn item_map_across_crates() {
|
||||||
|
|
||||||
let name = SmolStr::from("Baz");
|
let name = SmolStr::from("Baz");
|
||||||
let resolution = &item_map.per_module[&module_id].items[&name];
|
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]
|
#[test]
|
||||||
|
|
|
@ -15,7 +15,11 @@ use ra_syntax::{
|
||||||
SyntaxNodeRef
|
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)]
|
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||||
pub enum Ty {
|
pub enum Ty {
|
||||||
|
@ -149,7 +153,8 @@ impl Ty {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve in module (in type namespace)
|
// Resolve in module (in type namespace)
|
||||||
let resolved = if let Some(r) = module.resolve_path(db, path)? {
|
let resolved =
|
||||||
|
if let Some(r) = module.resolve_path(db, path)?.take(Namespace::Types) {
|
||||||
r
|
r
|
||||||
} else {
|
} else {
|
||||||
return Ok(Ty::Unknown);
|
return Ok(Ty::Unknown);
|
||||||
|
@ -325,7 +330,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// resolve in module
|
// 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)?;
|
let ty = self.db.type_for_def(resolved)?;
|
||||||
// TODO we will need to add type variables for type parameters etc. here
|
// TODO we will need to add type variables for type parameters etc. here
|
||||||
Ok(Some(ty))
|
Ok(Some(ty))
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
[86; 90) 'C(1)': [unknown]
|
[86; 90) 'C(1)': [unknown]
|
||||||
[72; 153) '{ ...a.c; }': ()
|
[72; 153) '{ ...a.c; }': ()
|
||||||
[86; 87) 'C': C
|
[86; 87) 'C': [unknown]
|
||||||
[107; 108) 'a': A
|
[107; 108) 'a': A
|
||||||
[114; 132) 'A { b:... C() }': [unknown]
|
[114; 132) 'A { b:... C() }': [unknown]
|
||||||
[138; 141) 'a.b': [unknown]
|
[138; 141) 'a.b': [unknown]
|
||||||
[147; 150) 'a.c': [unknown]
|
[147; 150) 'a.c': [unknown]
|
||||||
[96; 97) 'B': B
|
[96; 97) 'B': [unknown]
|
||||||
[88; 89) '1': [unknown]
|
[88; 89) '1': [unknown]
|
||||||
[82; 83) 'c': [unknown]
|
[82; 83) 'c': [unknown]
|
||||||
|
|
|
@ -55,6 +55,8 @@ impl Conv for CompletionItemKind {
|
||||||
CompletionItemKind::Snippet => Snippet,
|
CompletionItemKind::Snippet => Snippet,
|
||||||
CompletionItemKind::Module => Module,
|
CompletionItemKind::Module => Module,
|
||||||
CompletionItemKind::Function => Function,
|
CompletionItemKind::Function => Function,
|
||||||
|
CompletionItemKind::Struct => Struct,
|
||||||
|
CompletionItemKind::Enum => Enum,
|
||||||
CompletionItemKind::Binding => Variable,
|
CompletionItemKind::Binding => Variable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue