aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/nameres.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/nameres.rs')
-rw-r--r--crates/ra_hir/src/nameres.rs115
1 files changed, 81 insertions, 34 deletions
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index 0290b3474..9b9212bfc 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -56,6 +56,7 @@ mod tests;
56use std::sync::Arc; 56use std::sync::Arc;
57 57
58use rustc_hash::{FxHashMap, FxHashSet}; 58use rustc_hash::{FxHashMap, FxHashSet};
59use either::Either;
59use ra_arena::{Arena, RawId, impl_arena_id}; 60use ra_arena::{Arena, RawId, impl_arena_id};
60use ra_db::{FileId, Edition}; 61use ra_db::{FileId, Edition};
61use test_utils::tested_by; 62use test_utils::tested_by;
@@ -63,7 +64,7 @@ use ra_syntax::ast;
63use ra_prof::profile; 64use ra_prof::profile;
64 65
65use crate::{ 66use crate::{
66 ModuleDef, Name, Crate, Module, 67 ModuleDef, Name, Crate, Module, MacroDef,
67 DefDatabase, Path, PathKind, HirFileId, Trait, 68 DefDatabase, Path, PathKind, HirFileId, Trait,
68 ids::MacroDefId, 69 ids::MacroDefId,
69 diagnostics::DiagnosticSink, 70 diagnostics::DiagnosticSink,
@@ -136,6 +137,7 @@ pub(crate) struct ModuleData {
136#[derive(Debug, Default, PartialEq, Eq, Clone)] 137#[derive(Debug, Default, PartialEq, Eq, Clone)]
137pub struct ModuleScope { 138pub struct ModuleScope {
138 items: FxHashMap<Name, Resolution>, 139 items: FxHashMap<Name, Resolution>,
140 macros: FxHashMap<Name, MacroDef>,
139} 141}
140 142
141impl ModuleScope { 143impl ModuleScope {
@@ -151,8 +153,17 @@ impl ModuleScope {
151 _ => None, 153 _ => None,
152 }) 154 })
153 } 155 }
156 fn get_item_or_macro(&self, name: &Name) -> Option<ItemOrMacro> {
157 match (self.items.get(name), self.macros.get(name)) {
158 (Some(item), _) if !item.def.is_none() => Some(Either::Left(item.def)),
159 (_, Some(macro_)) => Some(Either::Right(*macro_)),
160 _ => None,
161 }
162 }
154} 163}
155 164
165type ItemOrMacro = Either<PerNs<ModuleDef>, MacroDef>;
166
156#[derive(Debug, Clone, PartialEq, Eq, Default)] 167#[derive(Debug, Clone, PartialEq, Eq, Default)]
157pub struct Resolution { 168pub struct Resolution {
158 /// None for unresolved 169 /// None for unresolved
@@ -163,18 +174,18 @@ pub struct Resolution {
163 174
164#[derive(Debug, Clone)] 175#[derive(Debug, Clone)]
165struct ResolvePathResult { 176struct ResolvePathResult {
166 resolved_def: PerNs<ModuleDef>, 177 resolved_def: ItemOrMacro,
167 segment_index: Option<usize>, 178 segment_index: Option<usize>,
168 reached_fixedpoint: ReachedFixedPoint, 179 reached_fixedpoint: ReachedFixedPoint,
169} 180}
170 181
171impl ResolvePathResult { 182impl ResolvePathResult {
172 fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult { 183 fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
173 ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None) 184 ResolvePathResult::with(Either::Left(PerNs::none()), reached_fixedpoint, None)
174 } 185 }
175 186
176 fn with( 187 fn with(
177 resolved_def: PerNs<ModuleDef>, 188 resolved_def: ItemOrMacro,
178 reached_fixedpoint: ReachedFixedPoint, 189 reached_fixedpoint: ReachedFixedPoint,
179 segment_index: Option<usize>, 190 segment_index: Option<usize>,
180 ) -> ResolvePathResult { 191 ) -> ResolvePathResult {
@@ -194,6 +205,21 @@ enum ReachedFixedPoint {
194 No, 205 No,
195} 206}
196 207
208/// helper function for select item or macro to use
209fn or(left: ItemOrMacro, right: ItemOrMacro) -> ItemOrMacro {
210 match (left, right) {
211 (Either::Left(s), Either::Left(o)) => Either::Left(s.or(o)),
212 (Either::Right(s), _) => Either::Right(s),
213 (Either::Left(s), Either::Right(o)) => {
214 if !s.is_none() {
215 Either::Left(s)
216 } else {
217 Either::Right(o)
218 }
219 }
220 }
221}
222
197impl CrateDefMap { 223impl CrateDefMap {
198 pub(crate) fn crate_def_map_query(db: &impl DefDatabase, krate: Crate) -> Arc<CrateDefMap> { 224 pub(crate) fn crate_def_map_query(db: &impl DefDatabase, krate: Crate) -> Arc<CrateDefMap> {
199 let _p = profile("crate_def_map_query"); 225 let _p = profile("crate_def_map_query");
@@ -268,7 +294,17 @@ impl CrateDefMap {
268 original_module: CrateModuleId, 294 original_module: CrateModuleId,
269 path: &Path, 295 path: &Path,
270 ) -> (PerNs<ModuleDef>, Option<usize>) { 296 ) -> (PerNs<ModuleDef>, Option<usize>) {
271 let res = self.resolve_path_fp(db, ResolveMode::Other, original_module, path); 297 let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path);
298 (res.resolved_def.left().unwrap_or_else(PerNs::none), res.segment_index)
299 }
300
301 fn resolve_path_with_macro(
302 &self,
303 db: &impl DefDatabase,
304 original_module: CrateModuleId,
305 path: &Path,
306 ) -> (ItemOrMacro, Option<usize>) {
307 let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path);
272 (res.resolved_def, res.segment_index) 308 (res.resolved_def, res.segment_index)
273 } 309 }
274 310
@@ -278,7 +314,7 @@ impl CrateDefMap {
278 314
279 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change 315 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change
280 // the result. 316 // the result.
281 fn resolve_path_fp( 317 fn resolve_path_fp_with_macro(
282 &self, 318 &self,
283 db: &impl DefDatabase, 319 db: &impl DefDatabase,
284 mode: ResolveMode, 320 mode: ResolveMode,
@@ -286,13 +322,13 @@ impl CrateDefMap {
286 path: &Path, 322 path: &Path,
287 ) -> ResolvePathResult { 323 ) -> ResolvePathResult {
288 let mut segments = path.segments.iter().enumerate(); 324 let mut segments = path.segments.iter().enumerate();
289 let mut curr_per_ns: PerNs<ModuleDef> = match path.kind { 325 let mut curr_per_ns: ItemOrMacro = match path.kind {
290 PathKind::Crate => { 326 PathKind::Crate => Either::Left(PerNs::types(
291 PerNs::types(Module { krate: self.krate, module_id: self.root }.into()) 327 Module { krate: self.krate, module_id: self.root }.into(),
292 } 328 )),
293 PathKind::Self_ => { 329 PathKind::Self_ => Either::Left(PerNs::types(
294 PerNs::types(Module { krate: self.krate, module_id: original_module }.into()) 330 Module { krate: self.krate, module_id: original_module }.into(),
295 } 331 )),
296 // plain import or absolute path in 2015: crate-relative with 332 // plain import or absolute path in 2015: crate-relative with
297 // fallback to extern prelude (with the simplification in 333 // fallback to extern prelude (with the simplification in
298 // rust-lang/rust#57745) 334 // rust-lang/rust#57745)
@@ -314,11 +350,11 @@ impl CrateDefMap {
314 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), 350 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
315 }; 351 };
316 log::debug!("resolving {:?} in module", segment); 352 log::debug!("resolving {:?} in module", segment);
317 self.resolve_name_in_module(db, original_module, &segment.name) 353 self.resolve_name_in_module_with_macro(db, original_module, &segment.name)
318 } 354 }
319 PathKind::Super => { 355 PathKind::Super => {
320 if let Some(p) = self.modules[original_module].parent { 356 if let Some(p) = self.modules[original_module].parent {
321 PerNs::types(Module { krate: self.krate, module_id: p }.into()) 357 Either::Left(PerNs::types(Module { krate: self.krate, module_id: p }.into()))
322 } else { 358 } else {
323 log::debug!("super path in root module"); 359 log::debug!("super path in root module");
324 return ResolvePathResult::empty(ReachedFixedPoint::Yes); 360 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
@@ -332,7 +368,7 @@ impl CrateDefMap {
332 }; 368 };
333 if let Some(def) = self.extern_prelude.get(&segment.name) { 369 if let Some(def) = self.extern_prelude.get(&segment.name) {
334 log::debug!("absolute path {:?} resolved to crate {:?}", path, def); 370 log::debug!("absolute path {:?} resolved to crate {:?}", path, def);
335 PerNs::types(*def) 371 Either::Left(PerNs::types(*def))
336 } else { 372 } else {
337 return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude 373 return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
338 } 374 }
@@ -340,7 +376,7 @@ impl CrateDefMap {
340 }; 376 };
341 377
342 for (i, segment) in segments { 378 for (i, segment) in segments {
343 let curr = match curr_per_ns.as_ref().take_types() { 379 let curr = match curr_per_ns.as_ref().left().map_or(None, |m| m.as_ref().take_types()) {
344 Some(r) => r, 380 Some(r) => r,
345 None => { 381 None => {
346 // we still have path segments left, but the path so far 382 // we still have path segments left, but the path so far
@@ -362,7 +398,8 @@ impl CrateDefMap {
362 }; 398 };
363 log::debug!("resolving {:?} in other crate", path); 399 log::debug!("resolving {:?} in other crate", path);
364 let defp_map = db.crate_def_map(module.krate); 400 let defp_map = db.crate_def_map(module.krate);
365 let (def, s) = defp_map.resolve_path(db, module.module_id, &path); 401 let (def, s) =
402 defp_map.resolve_path_with_macro(db, module.module_id, &path);
366 return ResolvePathResult::with( 403 return ResolvePathResult::with(
367 def, 404 def,
368 ReachedFixedPoint::Yes, 405 ReachedFixedPoint::Yes,
@@ -370,8 +407,8 @@ impl CrateDefMap {
370 ); 407 );
371 } 408 }
372 409
373 match self[module.module_id].scope.items.get(&segment.name) { 410 match self[module.module_id].scope.get_item_or_macro(&segment.name) {
374 Some(res) if !res.def.is_none() => res.def, 411 Some(res) => res,
375 _ => { 412 _ => {
376 log::debug!("path segment {:?} not found", segment.name); 413 log::debug!("path segment {:?} not found", segment.name);
377 return ResolvePathResult::empty(ReachedFixedPoint::No); 414 return ResolvePathResult::empty(ReachedFixedPoint::No);
@@ -382,10 +419,10 @@ impl CrateDefMap {
382 // enum variant 419 // enum variant
383 tested_by!(can_import_enum_variant); 420 tested_by!(can_import_enum_variant);
384 match e.variant(db, &segment.name) { 421 match e.variant(db, &segment.name) {
385 Some(variant) => PerNs::both(variant.into(), variant.into()), 422 Some(variant) => Either::Left(PerNs::both(variant.into(), variant.into())),
386 None => { 423 None => {
387 return ResolvePathResult::with( 424 return ResolvePathResult::with(
388 PerNs::types((*e).into()), 425 Either::Left(PerNs::types((*e).into())),
389 ReachedFixedPoint::Yes, 426 ReachedFixedPoint::Yes,
390 Some(i), 427 Some(i),
391 ); 428 );
@@ -402,7 +439,7 @@ impl CrateDefMap {
402 ); 439 );
403 440
404 return ResolvePathResult::with( 441 return ResolvePathResult::with(
405 PerNs::types((*s).into()), 442 Either::Left(PerNs::types((*s).into())),
406 ReachedFixedPoint::Yes, 443 ReachedFixedPoint::Yes,
407 Some(i), 444 Some(i),
408 ); 445 );
@@ -412,12 +449,12 @@ impl CrateDefMap {
412 ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None) 449 ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None)
413 } 450 }
414 451
415 fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> { 452 fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> ItemOrMacro {
416 let from_crate_root = 453 let from_crate_root =
417 self[self.root].scope.items.get(name).map_or(PerNs::none(), |it| it.def); 454 self[self.root].scope.get_item_or_macro(name).unwrap_or(Either::Left(PerNs::none()));
418 let from_extern_prelude = self.resolve_name_in_extern_prelude(name); 455 let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
419 456
420 from_crate_root.or(from_extern_prelude) 457 or(from_crate_root, Either::Left(from_extern_prelude))
421 } 458 }
422 459
423 pub(crate) fn resolve_name_in_module( 460 pub(crate) fn resolve_name_in_module(
@@ -426,32 +463,42 @@ impl CrateDefMap {
426 module: CrateModuleId, 463 module: CrateModuleId,
427 name: &Name, 464 name: &Name,
428 ) -> PerNs<ModuleDef> { 465 ) -> PerNs<ModuleDef> {
466 self.resolve_name_in_module_with_macro(db, module, name).left().unwrap_or_else(PerNs::none)
467 }
468
469 fn resolve_name_in_module_with_macro(
470 &self,
471 db: &impl DefDatabase,
472 module: CrateModuleId,
473 name: &Name,
474 ) -> ItemOrMacro {
429 // Resolve in: 475 // Resolve in:
430 // - current module / scope 476 // - current module / scope
431 // - extern prelude 477 // - extern prelude
432 // - std prelude 478 // - std prelude
433 let from_scope = self[module].scope.items.get(name).map_or(PerNs::none(), |it| it.def); 479 let from_scope =
480 self[module].scope.get_item_or_macro(name).unwrap_or(Either::Left(PerNs::none()));;
434 let from_extern_prelude = 481 let from_extern_prelude =
435 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); 482 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
436 let from_prelude = self.resolve_in_prelude(db, name); 483 let from_prelude = self.resolve_in_prelude(db, name);
437 484
438 from_scope.or(from_extern_prelude).or(from_prelude) 485 or(from_scope, or(Either::Left(from_extern_prelude), from_prelude))
439 } 486 }
440 487
441 fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> { 488 fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> {
442 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)) 489 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it))
443 } 490 }
444 491
445 fn resolve_in_prelude(&self, db: &impl DefDatabase, name: &Name) -> PerNs<ModuleDef> { 492 fn resolve_in_prelude(&self, db: &impl DefDatabase, name: &Name) -> ItemOrMacro {
446 if let Some(prelude) = self.prelude { 493 if let Some(prelude) = self.prelude {
447 let resolution = if prelude.krate == self.krate { 494 let resolution = if prelude.krate == self.krate {
448 self[prelude.module_id].scope.items.get(name).cloned() 495 self[prelude.module_id].scope.get_item_or_macro(name)
449 } else { 496 } else {
450 db.crate_def_map(prelude.krate)[prelude.module_id].scope.items.get(name).cloned() 497 db.crate_def_map(prelude.krate)[prelude.module_id].scope.get_item_or_macro(name)
451 }; 498 };
452 resolution.map(|r| r.def).unwrap_or_else(PerNs::none) 499 resolution.unwrap_or(Either::Left(PerNs::none()))
453 } else { 500 } else {
454 PerNs::none() 501 Either::Left(PerNs::none())
455 } 502 }
456 } 503 }
457} 504}
@@ -463,7 +510,7 @@ mod diagnostics {
463 use crate::{ 510 use crate::{
464 AstId, DefDatabase, 511 AstId, DefDatabase,
465 nameres::CrateModuleId, 512 nameres::CrateModuleId,
466 diagnostics::{DiagnosticSink, UnresolvedModule}, 513 diagnostics::{DiagnosticSink, UnresolvedModule}
467}; 514};
468 515
469 #[derive(Debug, PartialEq, Eq)] 516 #[derive(Debug, PartialEq, Eq)]