mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
Merge #2648
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:
commit
60aa4d12f9
7 changed files with 163 additions and 65 deletions
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()",
|
||||
},
|
||||
]
|
||||
"###
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue