aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-12-22 21:42:54 +0000
committerGitHub <[email protected]>2019-12-22 21:42:54 +0000
commit60aa4d12f95477565d5b01f122d2c9dd845015b4 (patch)
tree86f6d29653ba7e548f2a321b2ecdb20e7dc366f4
parent78f7683b9a1c6192b4828ceedb14ed498b241263 (diff)
parente424545c0f5cbaf135c52764169ea20df7d07d35 (diff)
Merge #2648
2648: Rudimentary name resolution for local items r=matklad a=matklad Co-authored-by: Aleksey Kladov <[email protected]>
-rw-r--r--crates/ra_hir_def/src/body/lower.rs32
-rw-r--r--crates/ra_hir_def/src/item_scope.rs27
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs2
-rw-r--r--crates/ra_hir_def/src/nameres/path_resolution.rs15
-rw-r--r--crates/ra_hir_def/src/resolver.rs103
-rw-r--r--crates/ra_hir_ty/src/tests/simple.rs12
-rw-r--r--crates/ra_ide/src/completion/complete_scope.rs37
7 files changed, 163 insertions, 65 deletions
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index 754924050..5323af097 100644
--- a/crates/ra_hir_def/src/body/lower.rs
+++ b/crates/ra_hir_def/src/body/lower.rs
@@ -494,45 +494,57 @@ where
494 fn collect_block_items(&mut self, block: &ast::Block) { 494 fn collect_block_items(&mut self, block: &ast::Block) {
495 let container = ContainerId::DefWithBodyId(self.def); 495 let container = ContainerId::DefWithBodyId(self.def);
496 for item in block.items() { 496 for item in block.items() {
497 let def: ModuleDefId = match item { 497 let (def, name): (ModuleDefId, Option<ast::Name>) = match item {
498 ast::ModuleItem::FnDef(def) => { 498 ast::ModuleItem::FnDef(def) => {
499 let ast_id = self.expander.ast_id(&def); 499 let ast_id = self.expander.ast_id(&def);
500 FunctionLoc { container: container.into(), ast_id }.intern(self.db).into() 500 (
501 FunctionLoc { container: container.into(), ast_id }.intern(self.db).into(),
502 def.name(),
503 )
501 } 504 }
502 ast::ModuleItem::TypeAliasDef(def) => { 505 ast::ModuleItem::TypeAliasDef(def) => {
503 let ast_id = self.expander.ast_id(&def); 506 let ast_id = self.expander.ast_id(&def);
504 TypeAliasLoc { container: container.into(), ast_id }.intern(self.db).into() 507 (
508 TypeAliasLoc { container: container.into(), ast_id }.intern(self.db).into(),
509 def.name(),
510 )
505 } 511 }
506 ast::ModuleItem::ConstDef(def) => { 512 ast::ModuleItem::ConstDef(def) => {
507 let ast_id = self.expander.ast_id(&def); 513 let ast_id = self.expander.ast_id(&def);
508 ConstLoc { container: container.into(), ast_id }.intern(self.db).into() 514 (
515 ConstLoc { container: container.into(), ast_id }.intern(self.db).into(),
516 def.name(),
517 )
509 } 518 }
510 ast::ModuleItem::StaticDef(def) => { 519 ast::ModuleItem::StaticDef(def) => {
511 let ast_id = self.expander.ast_id(&def); 520 let ast_id = self.expander.ast_id(&def);
512 StaticLoc { container, ast_id }.intern(self.db).into() 521 (StaticLoc { container, ast_id }.intern(self.db).into(), def.name())
513 } 522 }
514 ast::ModuleItem::StructDef(def) => { 523 ast::ModuleItem::StructDef(def) => {
515 let ast_id = self.expander.ast_id(&def); 524 let ast_id = self.expander.ast_id(&def);
516 StructLoc { container, ast_id }.intern(self.db).into() 525 (StructLoc { container, ast_id }.intern(self.db).into(), def.name())
517 } 526 }
518 ast::ModuleItem::EnumDef(def) => { 527 ast::ModuleItem::EnumDef(def) => {
519 let ast_id = self.expander.ast_id(&def); 528 let ast_id = self.expander.ast_id(&def);
520 EnumLoc { container, ast_id }.intern(self.db).into() 529 (EnumLoc { container, ast_id }.intern(self.db).into(), def.name())
521 } 530 }
522 ast::ModuleItem::UnionDef(def) => { 531 ast::ModuleItem::UnionDef(def) => {
523 let ast_id = self.expander.ast_id(&def); 532 let ast_id = self.expander.ast_id(&def);
524 UnionLoc { container, ast_id }.intern(self.db).into() 533 (UnionLoc { container, ast_id }.intern(self.db).into(), def.name())
525 } 534 }
526 ast::ModuleItem::TraitDef(def) => { 535 ast::ModuleItem::TraitDef(def) => {
527 let ast_id = self.expander.ast_id(&def); 536 let ast_id = self.expander.ast_id(&def);
528 TraitLoc { container, ast_id }.intern(self.db).into() 537 (TraitLoc { container, ast_id }.intern(self.db).into(), def.name())
529 } 538 }
530 ast::ModuleItem::ImplBlock(_) 539 ast::ModuleItem::ImplBlock(_)
531 | ast::ModuleItem::UseItem(_) 540 | ast::ModuleItem::UseItem(_)
532 | ast::ModuleItem::ExternCrateItem(_) 541 | ast::ModuleItem::ExternCrateItem(_)
533 | ast::ModuleItem::Module(_) => continue, 542 | ast::ModuleItem::Module(_) => continue,
534 }; 543 };
535 self.body.item_scope.define_def(def) 544 self.body.item_scope.define_def(def);
545 if let Some(name) = name {
546 self.body.item_scope.push_res(name.as_name(), def.into());
547 }
536 } 548 }
537 } 549 }
538 550
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs
index f1adc3b58..b0288ee8d 100644
--- a/crates/ra_hir_def/src/item_scope.rs
+++ b/crates/ra_hir_def/src/item_scope.rs
@@ -51,6 +51,12 @@ impl ItemScope {
51 self.visible.iter().chain(BUILTIN_SCOPE.iter()).map(|(n, def)| (n, *def)) 51 self.visible.iter().chain(BUILTIN_SCOPE.iter()).map(|(n, def)| (n, *def))
52 } 52 }
53 53
54 pub fn entries_without_primitives<'a>(
55 &'a self,
56 ) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
57 self.visible.iter().map(|(n, def)| (n, *def))
58 }
59
54 pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ { 60 pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
55 self.defs.iter().copied() 61 self.defs.iter().copied()
56 } 62 }
@@ -70,18 +76,27 @@ impl ItemScope {
70 } 76 }
71 77
72 /// Get a name from current module scope, legacy macros are not included 78 /// Get a name from current module scope, legacy macros are not included
73 pub(crate) fn get(&self, name: &Name, shadow: BuiltinShadowMode) -> Option<&PerNs> { 79 pub(crate) fn get(&self, name: &Name, shadow: BuiltinShadowMode) -> PerNs {
74 match shadow { 80 match shadow {
75 BuiltinShadowMode::Module => self.visible.get(name).or_else(|| BUILTIN_SCOPE.get(name)), 81 BuiltinShadowMode::Module => self
82 .visible
83 .get(name)
84 .or_else(|| BUILTIN_SCOPE.get(name))
85 .copied()
86 .unwrap_or_else(PerNs::none),
76 BuiltinShadowMode::Other => { 87 BuiltinShadowMode::Other => {
77 let item = self.visible.get(name); 88 let item = self.visible.get(name).copied();
78 if let Some(def) = item { 89 if let Some(def) = item {
79 if let Some(ModuleDefId::ModuleId(_)) = def.take_types() { 90 if let Some(ModuleDefId::ModuleId(_)) = def.take_types() {
80 return BUILTIN_SCOPE.get(name).or(item); 91 return BUILTIN_SCOPE
92 .get(name)
93 .copied()
94 .or(item)
95 .unwrap_or_else(PerNs::none);
81 } 96 }
82 } 97 }
83 98
84 item.or_else(|| BUILTIN_SCOPE.get(name)) 99 item.or_else(|| BUILTIN_SCOPE.get(name).copied()).unwrap_or_else(PerNs::none)
85 } 100 }
86 } 101 }
87 } 102 }
@@ -109,7 +124,7 @@ impl ItemScope {
109 self.legacy_macros.insert(name, mac); 124 self.legacy_macros.insert(name, mac);
110 } 125 }
111 126
112 pub(crate) fn push_res(&mut self, name: Name, def: &PerNs) -> bool { 127 pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool {
113 let mut changed = false; 128 let mut changed = false;
114 let existing = self.visible.entry(name.clone()).or_default(); 129 let existing = self.visible.entry(name.clone()).or_default();
115 130
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index 4f1fd4801..b9f40d3dd 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -446,7 +446,7 @@ where
446 let scope = &mut self.def_map.modules[module_id].scope; 446 let scope = &mut self.def_map.modules[module_id].scope;
447 let mut changed = false; 447 let mut changed = false;
448 for (name, res) in resolutions { 448 for (name, res) in resolutions {
449 changed |= scope.push_res(name.clone(), res); 449 changed |= scope.push_res(name.clone(), *res);
450 } 450 }
451 451
452 if !changed { 452 if !changed {
diff --git a/crates/ra_hir_def/src/nameres/path_resolution.rs b/crates/ra_hir_def/src/nameres/path_resolution.rs
index 378d49455..695014c7b 100644
--- a/crates/ra_hir_def/src/nameres/path_resolution.rs
+++ b/crates/ra_hir_def/src/nameres/path_resolution.rs
@@ -180,13 +180,7 @@ impl CrateDefMap {
180 } 180 }
181 181
182 // Since it is a qualified path here, it should not contains legacy macros 182 // Since it is a qualified path here, it should not contains legacy macros
183 match self[module.local_id].scope.get(&segment, prefer_module(i)) { 183 self[module.local_id].scope.get(&segment, prefer_module(i))
184 Some(def) => *def,
185 _ => {
186 log::debug!("path segment {:?} not found", segment);
187 return ResolvePathResult::empty(ReachedFixedPoint::No);
188 }
189 }
190 } 184 }
191 ModuleDefId::AdtId(AdtId::EnumId(e)) => { 185 ModuleDefId::AdtId(AdtId::EnumId(e)) => {
192 // enum variant 186 // enum variant
@@ -243,7 +237,7 @@ impl CrateDefMap {
243 // - std prelude 237 // - std prelude
244 let from_legacy_macro = 238 let from_legacy_macro =
245 self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros); 239 self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros);
246 let from_scope = self[module].scope.get(name, shadow).copied().unwrap_or_else(PerNs::none); 240 let from_scope = self[module].scope.get(name, shadow);
247 let from_extern_prelude = 241 let from_extern_prelude =
248 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); 242 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
249 let from_prelude = self.resolve_in_prelude(db, name, shadow); 243 let from_prelude = self.resolve_in_prelude(db, name, shadow);
@@ -256,8 +250,7 @@ impl CrateDefMap {
256 name: &Name, 250 name: &Name,
257 shadow: BuiltinShadowMode, 251 shadow: BuiltinShadowMode,
258 ) -> PerNs { 252 ) -> PerNs {
259 let from_crate_root = 253 let from_crate_root = self[self.root].scope.get(name, shadow);
260 self[self.root].scope.get(name, shadow).copied().unwrap_or_else(PerNs::none);
261 let from_extern_prelude = self.resolve_name_in_extern_prelude(name); 254 let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
262 255
263 from_crate_root.or(from_extern_prelude) 256 from_crate_root.or(from_extern_prelude)
@@ -278,7 +271,7 @@ impl CrateDefMap {
278 keep = db.crate_def_map(prelude.krate); 271 keep = db.crate_def_map(prelude.krate);
279 &keep 272 &keep
280 }; 273 };
281 def_map[prelude.local_id].scope.get(name, shadow).copied().unwrap_or_else(PerNs::none) 274 def_map[prelude.local_id].scope.get(name, shadow)
282 } else { 275 } else {
283 PerNs::none() 276 PerNs::none()
284 } 277 }
diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs
index e70049617..cf3c33d78 100644
--- a/crates/ra_hir_def/src/resolver.rs
+++ b/crates/ra_hir_def/src/resolver.rs
@@ -10,6 +10,7 @@ use rustc_hash::FxHashSet;
10 10
11use crate::{ 11use crate::{
12 body::scope::{ExprScopes, ScopeId}, 12 body::scope::{ExprScopes, ScopeId},
13 body::Body,
13 builtin_type::BuiltinType, 14 builtin_type::BuiltinType,
14 db::DefDatabase, 15 db::DefDatabase,
15 expr::{ExprId, PatId}, 16 expr::{ExprId, PatId},
@@ -55,6 +56,8 @@ enum Scope {
55 AdtScope(AdtId), 56 AdtScope(AdtId),
56 /// Local bindings 57 /// Local bindings
57 ExprScope(ExprScope), 58 ExprScope(ExprScope),
59 /// Temporary hack to support local items.
60 LocalItemsScope(Arc<Body>),
58} 61}
59 62
60#[derive(Debug, Clone, PartialEq, Eq, Hash)] 63#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -149,7 +152,13 @@ impl Resolver {
149 for scope in self.scopes.iter().rev() { 152 for scope in self.scopes.iter().rev() {
150 match scope { 153 match scope {
151 Scope::ExprScope(_) => continue, 154 Scope::ExprScope(_) => continue,
152 Scope::GenericParams { .. } | Scope::ImplBlockScope(_) if skip_to_mod => continue, 155 Scope::GenericParams { .. }
156 | Scope::ImplBlockScope(_)
157 | Scope::LocalItemsScope(_)
158 if skip_to_mod =>
159 {
160 continue
161 }
153 162
154 Scope::GenericParams { params, def } => { 163 Scope::GenericParams { params, def } => {
155 if let Some(local_id) = params.find_by_name(first_name) { 164 if let Some(local_id) = params.find_by_name(first_name) {
@@ -179,25 +188,35 @@ impl Resolver {
179 &path, 188 &path,
180 BuiltinShadowMode::Other, 189 BuiltinShadowMode::Other,
181 ); 190 );
182 let res = match module_def.take_types()? { 191 let res = to_type_ns(module_def)?;
183 ModuleDefId::AdtId(it) => TypeNs::AdtId(it),
184 ModuleDefId::EnumVariantId(it) => TypeNs::EnumVariantId(it),
185
186 ModuleDefId::TypeAliasId(it) => TypeNs::TypeAliasId(it),
187 ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it),
188
189 ModuleDefId::TraitId(it) => TypeNs::TraitId(it),
190
191 ModuleDefId::FunctionId(_)
192 | ModuleDefId::ConstId(_)
193 | ModuleDefId::StaticId(_)
194 | ModuleDefId::ModuleId(_) => return None,
195 };
196 return Some((res, idx)); 192 return Some((res, idx));
197 } 193 }
194 Scope::LocalItemsScope(body) => {
195 let def = body.item_scope.get(first_name, BuiltinShadowMode::Other);
196 if let Some(res) = to_type_ns(def) {
197 return Some((res, None));
198 }
199 }
198 } 200 }
199 } 201 }
200 None 202 return None;
203 fn to_type_ns(per_ns: PerNs) -> Option<TypeNs> {
204 let res = match per_ns.take_types()? {
205 ModuleDefId::AdtId(it) => TypeNs::AdtId(it),
206 ModuleDefId::EnumVariantId(it) => TypeNs::EnumVariantId(it),
207
208 ModuleDefId::TypeAliasId(it) => TypeNs::TypeAliasId(it),
209 ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it),
210
211 ModuleDefId::TraitId(it) => TypeNs::TraitId(it),
212
213 ModuleDefId::FunctionId(_)
214 | ModuleDefId::ConstId(_)
215 | ModuleDefId::StaticId(_)
216 | ModuleDefId::ModuleId(_) => return None,
217 };
218 Some(res)
219 }
201 } 220 }
202 221
203 pub fn resolve_path_in_type_ns_fully( 222 pub fn resolve_path_in_type_ns_fully(
@@ -227,6 +246,7 @@ impl Resolver {
227 | Scope::ExprScope(_) 246 | Scope::ExprScope(_)
228 | Scope::GenericParams { .. } 247 | Scope::GenericParams { .. }
229 | Scope::ImplBlockScope(_) 248 | Scope::ImplBlockScope(_)
249 | Scope::LocalItemsScope(_)
230 if skip_to_mod => 250 if skip_to_mod =>
231 { 251 {
232 continue 252 continue
@@ -276,20 +296,7 @@ impl Resolver {
276 ); 296 );
277 return match idx { 297 return match idx {
278 None => { 298 None => {
279 let value = match module_def.take_values()? { 299 let value = to_value_ns(module_def)?;
280 ModuleDefId::FunctionId(it) => ValueNs::FunctionId(it),
281 ModuleDefId::AdtId(AdtId::StructId(it)) => ValueNs::StructId(it),
282 ModuleDefId::EnumVariantId(it) => ValueNs::EnumVariantId(it),
283 ModuleDefId::ConstId(it) => ValueNs::ConstId(it),
284 ModuleDefId::StaticId(it) => ValueNs::StaticId(it),
285
286 ModuleDefId::AdtId(AdtId::EnumId(_))
287 | ModuleDefId::AdtId(AdtId::UnionId(_))
288 | ModuleDefId::TraitId(_)
289 | ModuleDefId::TypeAliasId(_)
290 | ModuleDefId::BuiltinType(_)
291 | ModuleDefId::ModuleId(_) => return None,
292 };
293 Some(ResolveValueResult::ValueNs(value)) 300 Some(ResolveValueResult::ValueNs(value))
294 } 301 }
295 Some(idx) => { 302 Some(idx) => {
@@ -309,9 +316,33 @@ impl Resolver {
309 } 316 }
310 }; 317 };
311 } 318 }
319 Scope::LocalItemsScope(body) => {
320 let def = body.item_scope.get(first_name, BuiltinShadowMode::Other);
321 if let Some(res) = to_value_ns(def) {
322 return Some(ResolveValueResult::ValueNs(res));
323 }
324 }
312 } 325 }
313 } 326 }
314 None 327 return None;
328
329 fn to_value_ns(per_ns: PerNs) -> Option<ValueNs> {
330 let res = match per_ns.take_values()? {
331 ModuleDefId::FunctionId(it) => ValueNs::FunctionId(it),
332 ModuleDefId::AdtId(AdtId::StructId(it)) => ValueNs::StructId(it),
333 ModuleDefId::EnumVariantId(it) => ValueNs::EnumVariantId(it),
334 ModuleDefId::ConstId(it) => ValueNs::ConstId(it),
335 ModuleDefId::StaticId(it) => ValueNs::StaticId(it),
336
337 ModuleDefId::AdtId(AdtId::EnumId(_))
338 | ModuleDefId::AdtId(AdtId::UnionId(_))
339 | ModuleDefId::TraitId(_)
340 | ModuleDefId::TypeAliasId(_)
341 | ModuleDefId::BuiltinType(_)
342 | ModuleDefId::ModuleId(_) => return None,
343 };
344 Some(res)
345 }
315 } 346 }
316 347
317 pub fn resolve_path_in_value_ns_fully( 348 pub fn resolve_path_in_value_ns_fully(
@@ -429,6 +460,11 @@ impl Scope {
429 }); 460 });
430 } 461 }
431 } 462 }
463 Scope::LocalItemsScope(body) => {
464 body.item_scope.entries_without_primitives().for_each(|(name, def)| {
465 f(name.clone(), ScopeDef::PerNs(def));
466 })
467 }
432 Scope::GenericParams { params, def } => { 468 Scope::GenericParams { params, def } => {
433 for (local_id, param) in params.types.iter() { 469 for (local_id, param) in params.types.iter() {
434 f( 470 f(
@@ -464,6 +500,7 @@ pub fn resolver_for_scope(
464 scope_id: Option<ScopeId>, 500 scope_id: Option<ScopeId>,
465) -> Resolver { 501) -> Resolver {
466 let mut r = owner.resolver(db); 502 let mut r = owner.resolver(db);
503 r = r.push_local_items_scope(db.body(owner));
467 let scopes = db.expr_scopes(owner); 504 let scopes = db.expr_scopes(owner);
468 let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>(); 505 let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>();
469 for scope in scope_chain.into_iter().rev() { 506 for scope in scope_chain.into_iter().rev() {
@@ -499,6 +536,10 @@ impl Resolver {
499 self.push_scope(Scope::ModuleScope(ModuleItemMap { crate_def_map, module_id })) 536 self.push_scope(Scope::ModuleScope(ModuleItemMap { crate_def_map, module_id }))
500 } 537 }
501 538
539 fn push_local_items_scope(self, body: Arc<Body>) -> Resolver {
540 self.push_scope(Scope::LocalItemsScope(body))
541 }
542
502 fn push_expr_scope( 543 fn push_expr_scope(
503 self, 544 self,
504 owner: DefWithBodyId, 545 owner: DefWithBodyId,
diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs
index 6fe647a5e..3e5e163e3 100644
--- a/crates/ra_hir_ty/src/tests/simple.rs
+++ b/crates/ra_hir_ty/src/tests/simple.rs
@@ -1512,8 +1512,8 @@ fn test() {
1512 [49; 50) '0': u32 1512 [49; 50) '0': u32
1513 [80; 83) '101': u32 1513 [80; 83) '101': u32
1514 [95; 213) '{ ...NST; }': () 1514 [95; 213) '{ ...NST; }': ()
1515 [138; 139) 'x': {unknown} 1515 [138; 139) 'x': u32
1516 [142; 153) 'LOCAL_CONST': {unknown} 1516 [142; 153) 'LOCAL_CONST': u32
1517 [163; 164) 'z': u32 1517 [163; 164) 'z': u32
1518 [167; 179) 'GLOBAL_CONST': u32 1518 [167; 179) 'GLOBAL_CONST': u32
1519 [189; 191) 'id': u32 1519 [189; 191) 'id': u32
@@ -1541,10 +1541,10 @@ fn test() {
1541 [29; 32) '101': u32 1541 [29; 32) '101': u32
1542 [70; 73) '101': u32 1542 [70; 73) '101': u32
1543 [85; 280) '{ ...MUT; }': () 1543 [85; 280) '{ ...MUT; }': ()
1544 [173; 174) 'x': {unknown} 1544 [173; 174) 'x': u32
1545 [177; 189) 'LOCAL_STATIC': {unknown} 1545 [177; 189) 'LOCAL_STATIC': u32
1546 [199; 200) 'y': {unknown} 1546 [199; 200) 'y': u32
1547 [203; 219) 'LOCAL_...IC_MUT': {unknown} 1547 [203; 219) 'LOCAL_...IC_MUT': u32
1548 [229; 230) 'z': u32 1548 [229; 230) 'z': u32
1549 [233; 246) 'GLOBAL_STATIC': u32 1549 [233; 246) 'GLOBAL_STATIC': u32
1550 [256; 257) 'w': u32 1550 [256; 257) 'w': u32
diff --git a/crates/ra_ide/src/completion/complete_scope.rs b/crates/ra_ide/src/completion/complete_scope.rs
index d5739b58a..458d7525e 100644
--- a/crates/ra_ide/src/completion/complete_scope.rs
+++ b/crates/ra_ide/src/completion/complete_scope.rs
@@ -873,4 +873,41 @@ mod tests {
873 "### 873 "###
874 ); 874 );
875 } 875 }
876
877 #[test]
878 fn completes_local_item() {
879 assert_debug_snapshot!(
880 do_reference_completion(
881 "
882 //- /main.rs
883 fn main() {
884 return f<|>;
885 fn frobnicate() {}
886 }
887 "
888 ),
889 @r###"
890 [
891 CompletionItem {
892 label: "frobnicate()",
893 source_range: [23; 24),
894 delete: [23; 24),
895 insert: "frobnicate()$0",
896 kind: Function,
897 lookup: "frobnicate",
898 detail: "fn frobnicate()",
899 },
900 CompletionItem {
901 label: "main()",
902 source_range: [23; 24),
903 delete: [23; 24),
904 insert: "main()$0",
905 kind: Function,
906 lookup: "main",
907 detail: "fn main()",
908 },
909 ]
910 "###
911 )
912 }
876} 913}