Rudimentary name resolution for local items

This commit is contained in:
Aleksey Kladov 2019-12-22 20:12:23 +01:00
parent 7c405c0156
commit e424545c0f
6 changed files with 145 additions and 49 deletions

View file

@ -494,45 +494,57 @@ where
fn collect_block_items(&mut self, block: &ast::Block) {
let container = ContainerId::DefWithBodyId(self.def);
for item in block.items() {
let def: ModuleDefId = match item {
let (def, name): (ModuleDefId, Option<ast::Name>) = match item {
ast::ModuleItem::FnDef(def) => {
let ast_id = self.expander.ast_id(&def);
FunctionLoc { container: container.into(), ast_id }.intern(self.db).into()
(
FunctionLoc { container: container.into(), ast_id }.intern(self.db).into(),
def.name(),
)
}
ast::ModuleItem::TypeAliasDef(def) => {
let ast_id = self.expander.ast_id(&def);
TypeAliasLoc { container: container.into(), ast_id }.intern(self.db).into()
(
TypeAliasLoc { container: container.into(), ast_id }.intern(self.db).into(),
def.name(),
)
}
ast::ModuleItem::ConstDef(def) => {
let ast_id = self.expander.ast_id(&def);
ConstLoc { container: container.into(), ast_id }.intern(self.db).into()
(
ConstLoc { container: container.into(), ast_id }.intern(self.db).into(),
def.name(),
)
}
ast::ModuleItem::StaticDef(def) => {
let ast_id = self.expander.ast_id(&def);
StaticLoc { container, ast_id }.intern(self.db).into()
(StaticLoc { container, ast_id }.intern(self.db).into(), def.name())
}
ast::ModuleItem::StructDef(def) => {
let ast_id = self.expander.ast_id(&def);
StructLoc { container, ast_id }.intern(self.db).into()
(StructLoc { container, ast_id }.intern(self.db).into(), def.name())
}
ast::ModuleItem::EnumDef(def) => {
let ast_id = self.expander.ast_id(&def);
EnumLoc { container, ast_id }.intern(self.db).into()
(EnumLoc { container, ast_id }.intern(self.db).into(), def.name())
}
ast::ModuleItem::UnionDef(def) => {
let ast_id = self.expander.ast_id(&def);
UnionLoc { container, ast_id }.intern(self.db).into()
(UnionLoc { container, ast_id }.intern(self.db).into(), def.name())
}
ast::ModuleItem::TraitDef(def) => {
let ast_id = self.expander.ast_id(&def);
TraitLoc { container, ast_id }.intern(self.db).into()
(TraitLoc { container, ast_id }.intern(self.db).into(), def.name())
}
ast::ModuleItem::ImplBlock(_)
| ast::ModuleItem::UseItem(_)
| ast::ModuleItem::ExternCrateItem(_)
| ast::ModuleItem::Module(_) => continue,
};
self.body.item_scope.define_def(def)
self.body.item_scope.define_def(def);
if let Some(name) = name {
self.body.item_scope.push_res(name.as_name(), def.into());
}
}
}

View file

@ -51,6 +51,12 @@ impl ItemScope {
self.visible.iter().chain(BUILTIN_SCOPE.iter()).map(|(n, def)| (n, *def))
}
pub fn entries_without_primitives<'a>(
&'a self,
) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
self.visible.iter().map(|(n, def)| (n, *def))
}
pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
self.defs.iter().copied()
}
@ -118,7 +124,7 @@ impl ItemScope {
self.legacy_macros.insert(name, mac);
}
pub(crate) fn push_res(&mut self, name: Name, def: &PerNs) -> bool {
pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool {
let mut changed = false;
let existing = self.visible.entry(name.clone()).or_default();

View file

@ -446,7 +446,7 @@ where
let scope = &mut self.def_map.modules[module_id].scope;
let mut changed = false;
for (name, res) in resolutions {
changed |= scope.push_res(name.clone(), res);
changed |= scope.push_res(name.clone(), *res);
}
if !changed {

View file

@ -10,6 +10,7 @@ use rustc_hash::FxHashSet;
use crate::{
body::scope::{ExprScopes, ScopeId},
body::Body,
builtin_type::BuiltinType,
db::DefDatabase,
expr::{ExprId, PatId},
@ -55,6 +56,8 @@ enum Scope {
AdtScope(AdtId),
/// Local bindings
ExprScope(ExprScope),
/// Temporary hack to support local items.
LocalItemsScope(Arc<Body>),
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@ -149,7 +152,13 @@ impl Resolver {
for scope in self.scopes.iter().rev() {
match scope {
Scope::ExprScope(_) => continue,
Scope::GenericParams { .. } | Scope::ImplBlockScope(_) if skip_to_mod => continue,
Scope::GenericParams { .. }
| Scope::ImplBlockScope(_)
| Scope::LocalItemsScope(_)
if skip_to_mod =>
{
continue
}
Scope::GenericParams { params, def } => {
if let Some(local_id) = params.find_by_name(first_name) {
@ -179,25 +188,35 @@ impl Resolver {
&path,
BuiltinShadowMode::Other,
);
let res = match module_def.take_types()? {
ModuleDefId::AdtId(it) => TypeNs::AdtId(it),
ModuleDefId::EnumVariantId(it) => TypeNs::EnumVariantId(it),
ModuleDefId::TypeAliasId(it) => TypeNs::TypeAliasId(it),
ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it),
ModuleDefId::TraitId(it) => TypeNs::TraitId(it),
ModuleDefId::FunctionId(_)
| ModuleDefId::ConstId(_)
| ModuleDefId::StaticId(_)
| ModuleDefId::ModuleId(_) => return None,
};
let res = to_type_ns(module_def)?;
return Some((res, idx));
}
Scope::LocalItemsScope(body) => {
let def = body.item_scope.get(first_name, BuiltinShadowMode::Other);
if let Some(res) = to_type_ns(def) {
return Some((res, None));
}
}
}
}
None
return None;
fn to_type_ns(per_ns: PerNs) -> Option<TypeNs> {
let res = match per_ns.take_types()? {
ModuleDefId::AdtId(it) => TypeNs::AdtId(it),
ModuleDefId::EnumVariantId(it) => TypeNs::EnumVariantId(it),
ModuleDefId::TypeAliasId(it) => TypeNs::TypeAliasId(it),
ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it),
ModuleDefId::TraitId(it) => TypeNs::TraitId(it),
ModuleDefId::FunctionId(_)
| ModuleDefId::ConstId(_)
| ModuleDefId::StaticId(_)
| ModuleDefId::ModuleId(_) => return None,
};
Some(res)
}
}
pub fn resolve_path_in_type_ns_fully(
@ -227,6 +246,7 @@ impl Resolver {
| Scope::ExprScope(_)
| Scope::GenericParams { .. }
| Scope::ImplBlockScope(_)
| Scope::LocalItemsScope(_)
if skip_to_mod =>
{
continue
@ -276,20 +296,7 @@ impl Resolver {
);
return match idx {
None => {
let value = match module_def.take_values()? {
ModuleDefId::FunctionId(it) => ValueNs::FunctionId(it),
ModuleDefId::AdtId(AdtId::StructId(it)) => ValueNs::StructId(it),
ModuleDefId::EnumVariantId(it) => ValueNs::EnumVariantId(it),
ModuleDefId::ConstId(it) => ValueNs::ConstId(it),
ModuleDefId::StaticId(it) => ValueNs::StaticId(it),
ModuleDefId::AdtId(AdtId::EnumId(_))
| ModuleDefId::AdtId(AdtId::UnionId(_))
| ModuleDefId::TraitId(_)
| ModuleDefId::TypeAliasId(_)
| ModuleDefId::BuiltinType(_)
| ModuleDefId::ModuleId(_) => return None,
};
let value = to_value_ns(module_def)?;
Some(ResolveValueResult::ValueNs(value))
}
Some(idx) => {
@ -309,9 +316,33 @@ impl Resolver {
}
};
}
Scope::LocalItemsScope(body) => {
let def = body.item_scope.get(first_name, BuiltinShadowMode::Other);
if let Some(res) = to_value_ns(def) {
return Some(ResolveValueResult::ValueNs(res));
}
}
}
}
None
return None;
fn to_value_ns(per_ns: PerNs) -> Option<ValueNs> {
let res = match per_ns.take_values()? {
ModuleDefId::FunctionId(it) => ValueNs::FunctionId(it),
ModuleDefId::AdtId(AdtId::StructId(it)) => ValueNs::StructId(it),
ModuleDefId::EnumVariantId(it) => ValueNs::EnumVariantId(it),
ModuleDefId::ConstId(it) => ValueNs::ConstId(it),
ModuleDefId::StaticId(it) => ValueNs::StaticId(it),
ModuleDefId::AdtId(AdtId::EnumId(_))
| ModuleDefId::AdtId(AdtId::UnionId(_))
| ModuleDefId::TraitId(_)
| ModuleDefId::TypeAliasId(_)
| ModuleDefId::BuiltinType(_)
| ModuleDefId::ModuleId(_) => return None,
};
Some(res)
}
}
pub fn resolve_path_in_value_ns_fully(
@ -429,6 +460,11 @@ impl Scope {
});
}
}
Scope::LocalItemsScope(body) => {
body.item_scope.entries_without_primitives().for_each(|(name, def)| {
f(name.clone(), ScopeDef::PerNs(def));
})
}
Scope::GenericParams { params, def } => {
for (local_id, param) in params.types.iter() {
f(
@ -464,6 +500,7 @@ pub fn resolver_for_scope(
scope_id: Option<ScopeId>,
) -> Resolver {
let mut r = owner.resolver(db);
r = r.push_local_items_scope(db.body(owner));
let scopes = db.expr_scopes(owner);
let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>();
for scope in scope_chain.into_iter().rev() {
@ -499,6 +536,10 @@ impl Resolver {
self.push_scope(Scope::ModuleScope(ModuleItemMap { crate_def_map, module_id }))
}
fn push_local_items_scope(self, body: Arc<Body>) -> Resolver {
self.push_scope(Scope::LocalItemsScope(body))
}
fn push_expr_scope(
self,
owner: DefWithBodyId,

View file

@ -1512,8 +1512,8 @@ fn test() {
[49; 50) '0': u32
[80; 83) '101': u32
[95; 213) '{ ...NST; }': ()
[138; 139) 'x': {unknown}
[142; 153) 'LOCAL_CONST': {unknown}
[138; 139) 'x': u32
[142; 153) 'LOCAL_CONST': u32
[163; 164) 'z': u32
[167; 179) 'GLOBAL_CONST': u32
[189; 191) 'id': u32
@ -1541,10 +1541,10 @@ fn test() {
[29; 32) '101': u32
[70; 73) '101': u32
[85; 280) '{ ...MUT; }': ()
[173; 174) 'x': {unknown}
[177; 189) 'LOCAL_STATIC': {unknown}
[199; 200) 'y': {unknown}
[203; 219) 'LOCAL_...IC_MUT': {unknown}
[173; 174) 'x': u32
[177; 189) 'LOCAL_STATIC': u32
[199; 200) 'y': u32
[203; 219) 'LOCAL_...IC_MUT': u32
[229; 230) 'z': u32
[233; 246) 'GLOBAL_STATIC': u32
[256; 257) 'w': u32

View file

@ -873,4 +873,41 @@ mod tests {
"###
);
}
#[test]
fn completes_local_item() {
assert_debug_snapshot!(
do_reference_completion(
"
//- /main.rs
fn main() {
return f<|>;
fn frobnicate() {}
}
"
),
@r###"
[
CompletionItem {
label: "frobnicate()",
source_range: [23; 24),
delete: [23; 24),
insert: "frobnicate()$0",
kind: Function,
lookup: "frobnicate",
detail: "fn frobnicate()",
},
CompletionItem {
label: "main()",
source_range: [23; 24),
delete: [23; 24),
insert: "main()$0",
kind: Function,
lookup: "main",
detail: "fn main()",
},
]
"###
)
}
}