2648: Rudimentary name resolution for local items r=matklad a=matklad



Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
bors[bot] 2019-12-22 21:42:54 +00:00 committed by GitHub
commit 60aa4d12f9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 163 additions and 65 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()
}
@ -70,18 +76,27 @@ impl ItemScope {
}
/// Get a name from current module scope, legacy macros are not included
pub(crate) fn get(&self, name: &Name, shadow: BuiltinShadowMode) -> Option<&PerNs> {
pub(crate) fn get(&self, name: &Name, shadow: BuiltinShadowMode) -> PerNs {
match shadow {
BuiltinShadowMode::Module => self.visible.get(name).or_else(|| BUILTIN_SCOPE.get(name)),
BuiltinShadowMode::Module => self
.visible
.get(name)
.or_else(|| BUILTIN_SCOPE.get(name))
.copied()
.unwrap_or_else(PerNs::none),
BuiltinShadowMode::Other => {
let item = self.visible.get(name);
let item = self.visible.get(name).copied();
if let Some(def) = item {
if let Some(ModuleDefId::ModuleId(_)) = def.take_types() {
return BUILTIN_SCOPE.get(name).or(item);
return BUILTIN_SCOPE
.get(name)
.copied()
.or(item)
.unwrap_or_else(PerNs::none);
}
}
item.or_else(|| BUILTIN_SCOPE.get(name))
item.or_else(|| BUILTIN_SCOPE.get(name).copied()).unwrap_or_else(PerNs::none)
}
}
}
@ -109,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

@ -180,13 +180,7 @@ impl CrateDefMap {
}
// Since it is a qualified path here, it should not contains legacy macros
match self[module.local_id].scope.get(&segment, prefer_module(i)) {
Some(def) => *def,
_ => {
log::debug!("path segment {:?} not found", segment);
return ResolvePathResult::empty(ReachedFixedPoint::No);
}
}
self[module.local_id].scope.get(&segment, prefer_module(i))
}
ModuleDefId::AdtId(AdtId::EnumId(e)) => {
// enum variant
@ -243,7 +237,7 @@ impl CrateDefMap {
// - std prelude
let from_legacy_macro =
self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros);
let from_scope = self[module].scope.get(name, shadow).copied().unwrap_or_else(PerNs::none);
let from_scope = self[module].scope.get(name, shadow);
let from_extern_prelude =
self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
let from_prelude = self.resolve_in_prelude(db, name, shadow);
@ -256,8 +250,7 @@ impl CrateDefMap {
name: &Name,
shadow: BuiltinShadowMode,
) -> PerNs {
let from_crate_root =
self[self.root].scope.get(name, shadow).copied().unwrap_or_else(PerNs::none);
let from_crate_root = self[self.root].scope.get(name, shadow);
let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
from_crate_root.or(from_extern_prelude)
@ -278,7 +271,7 @@ impl CrateDefMap {
keep = db.crate_def_map(prelude.krate);
&keep
};
def_map[prelude.local_id].scope.get(name, shadow).copied().unwrap_or_else(PerNs::none)
def_map[prelude.local_id].scope.get(name, shadow)
} else {
PerNs::none()
}

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,7 +188,20 @@ impl Resolver {
&path,
BuiltinShadowMode::Other,
);
let res = match module_def.take_types()? {
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));
}
}
}
}
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),
@ -193,12 +215,9 @@ impl Resolver {
| ModuleDefId::StaticId(_)
| ModuleDefId::ModuleId(_) => return None,
};
return Some((res, idx));
Some(res)
}
}
}
None
}
pub fn resolve_path_in_type_ns_fully(
&self,
@ -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()",
},
]
"###
)
}
}