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.rs78
1 files changed, 62 insertions, 16 deletions
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index bd920bfea..b78a178c1 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -119,6 +119,10 @@ impl<T> PerNs<T> {
119 self.types.is_some() && self.values.is_some() 119 self.types.is_some() && self.values.is_some()
120 } 120 }
121 121
122 pub fn is_values(&self) -> bool {
123 self.values.is_some() && self.types.is_none()
124 }
125
122 pub fn take(self, namespace: Namespace) -> Option<T> { 126 pub fn take(self, namespace: Namespace) -> Option<T> {
123 match namespace { 127 match namespace {
124 Namespace::Types => self.types, 128 Namespace::Types => self.types,
@@ -297,7 +301,14 @@ where
297 ); 301 );
298 (res, if res.is_none() { ReachedFixedPoint::No } else { ReachedFixedPoint::Yes }) 302 (res, if res.is_none() { ReachedFixedPoint::No } else { ReachedFixedPoint::Yes })
299 } else { 303 } else {
300 self.result.resolve_path_fp(self.db, ResolveMode::Import, original_module, &import.path) 304 let res = self.result.resolve_path_fp(
305 self.db,
306 ResolveMode::Import,
307 original_module,
308 &import.path,
309 );
310
311 (res.module, res.reached_fixedpoint)
301 }; 312 };
302 313
303 if reached_fixedpoint != ReachedFixedPoint::Yes { 314 if reached_fixedpoint != ReachedFixedPoint::Yes {
@@ -435,6 +446,27 @@ where
435 } 446 }
436} 447}
437 448
449#[derive(Debug, Clone)]
450pub struct ResolvePathResult {
451 pub(crate) module: PerNs<ModuleDef>,
452 pub(crate) segment_index: Option<usize>,
453 reached_fixedpoint: ReachedFixedPoint,
454}
455
456impl ResolvePathResult {
457 fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
458 ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None)
459 }
460
461 fn with(
462 module: PerNs<ModuleDef>,
463 reached_fixedpoint: ReachedFixedPoint,
464 segment_index: Option<usize>,
465 ) -> ResolvePathResult {
466 ResolvePathResult { module, reached_fixedpoint, segment_index }
467 }
468}
469
438#[derive(Debug, Clone, Copy, PartialEq, Eq)] 470#[derive(Debug, Clone, Copy, PartialEq, Eq)]
439enum ResolveMode { 471enum ResolveMode {
440 Import, 472 Import,
@@ -468,8 +500,9 @@ impl ItemMap {
468 db: &impl PersistentHirDatabase, 500 db: &impl PersistentHirDatabase,
469 original_module: Module, 501 original_module: Module,
470 path: &Path, 502 path: &Path,
471 ) -> PerNs<ModuleDef> { 503 ) -> (PerNs<ModuleDef>, Option<usize>) {
472 self.resolve_path_fp(db, ResolveMode::Other, original_module, path).0 504 let res = self.resolve_path_fp(db, ResolveMode::Other, original_module, path);
505 (res.module, res.segment_index)
473 } 506 }
474 507
475 fn resolve_in_prelude( 508 fn resolve_in_prelude(
@@ -534,7 +567,7 @@ impl ItemMap {
534 mode: ResolveMode, 567 mode: ResolveMode,
535 original_module: Module, 568 original_module: Module,
536 path: &Path, 569 path: &Path,
537 ) -> (PerNs<ModuleDef>, ReachedFixedPoint) { 570 ) -> ResolvePathResult {
538 let mut segments = path.segments.iter().enumerate(); 571 let mut segments = path.segments.iter().enumerate();
539 let mut curr_per_ns: PerNs<ModuleDef> = match path.kind { 572 let mut curr_per_ns: PerNs<ModuleDef> = match path.kind {
540 PathKind::Crate => PerNs::types(original_module.crate_root(db).into()), 573 PathKind::Crate => PerNs::types(original_module.crate_root(db).into()),
@@ -549,7 +582,7 @@ impl ItemMap {
549 { 582 {
550 let segment = match segments.next() { 583 let segment = match segments.next() {
551 Some((_, segment)) => segment, 584 Some((_, segment)) => segment,
552 None => return (PerNs::none(), ReachedFixedPoint::Yes), 585 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
553 }; 586 };
554 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); 587 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
555 self.resolve_name_in_crate_root_or_extern_prelude( 588 self.resolve_name_in_crate_root_or_extern_prelude(
@@ -561,7 +594,7 @@ impl ItemMap {
561 PathKind::Plain => { 594 PathKind::Plain => {
562 let segment = match segments.next() { 595 let segment = match segments.next() {
563 Some((_, segment)) => segment, 596 Some((_, segment)) => segment,
564 None => return (PerNs::none(), ReachedFixedPoint::Yes), 597 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
565 }; 598 };
566 log::debug!("resolving {:?} in module", segment); 599 log::debug!("resolving {:?} in module", segment);
567 self.resolve_name_in_module(db, original_module, &segment.name) 600 self.resolve_name_in_module(db, original_module, &segment.name)
@@ -571,20 +604,20 @@ impl ItemMap {
571 PerNs::types(p.into()) 604 PerNs::types(p.into())
572 } else { 605 } else {
573 log::debug!("super path in root module"); 606 log::debug!("super path in root module");
574 return (PerNs::none(), ReachedFixedPoint::Yes); 607 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
575 } 608 }
576 } 609 }
577 PathKind::Abs => { 610 PathKind::Abs => {
578 // 2018-style absolute path -- only extern prelude 611 // 2018-style absolute path -- only extern prelude
579 let segment = match segments.next() { 612 let segment = match segments.next() {
580 Some((_, segment)) => segment, 613 Some((_, segment)) => segment,
581 None => return (PerNs::none(), ReachedFixedPoint::Yes), 614 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
582 }; 615 };
583 if let Some(def) = self.extern_prelude.get(&segment.name) { 616 if let Some(def) = self.extern_prelude.get(&segment.name) {
584 log::debug!("absolute path {:?} resolved to crate {:?}", path, def); 617 log::debug!("absolute path {:?} resolved to crate {:?}", path, def);
585 PerNs::types(*def) 618 PerNs::types(*def)
586 } else { 619 } else {
587 return (PerNs::none(), ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude 620 return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
588 } 621 }
589 } 622 }
590 }; 623 };
@@ -598,7 +631,7 @@ impl ItemMap {
598 // (don't break here because `curr_per_ns` might contain 631 // (don't break here because `curr_per_ns` might contain
599 // something in the value namespace, and it would be wrong 632 // something in the value namespace, and it would be wrong
600 // to return that) 633 // to return that)
601 return (PerNs::none(), ReachedFixedPoint::No); 634 return ResolvePathResult::empty(ReachedFixedPoint::No);
602 } 635 }
603 }; 636 };
604 // resolve segment in curr 637 // resolve segment in curr
@@ -612,15 +645,15 @@ impl ItemMap {
612 }; 645 };
613 log::debug!("resolving {:?} in other crate", path); 646 log::debug!("resolving {:?} in other crate", path);
614 let item_map = db.item_map(module.krate); 647 let item_map = db.item_map(module.krate);
615 let def = item_map.resolve_path(db, *module, &path); 648 let (def, s) = item_map.resolve_path(db, *module, &path);
616 return (def, ReachedFixedPoint::Yes); 649 return ResolvePathResult::with(def, ReachedFixedPoint::Yes, s);
617 } 650 }
618 651
619 match self[module.module_id].items.get(&segment.name) { 652 match self[module.module_id].items.get(&segment.name) {
620 Some(res) if !res.def.is_none() => res.def, 653 Some(res) if !res.def.is_none() => res.def,
621 _ => { 654 _ => {
622 log::debug!("path segment {:?} not found", segment.name); 655 log::debug!("path segment {:?} not found", segment.name);
623 return (PerNs::none(), ReachedFixedPoint::No); 656 return ResolvePathResult::empty(ReachedFixedPoint::No);
624 } 657 }
625 } 658 }
626 } 659 }
@@ -629,9 +662,22 @@ impl ItemMap {
629 tested_by!(item_map_enum_importing); 662 tested_by!(item_map_enum_importing);
630 match e.variant(db, &segment.name) { 663 match e.variant(db, &segment.name) {
631 Some(variant) => PerNs::both(variant.into(), variant.into()), 664 Some(variant) => PerNs::both(variant.into(), variant.into()),
632 None => PerNs::none(), 665 None => {
666 return ResolvePathResult::with(
667 PerNs::types((*e).into()),
668 ReachedFixedPoint::Yes,
669 Some(i),
670 );
671 }
633 } 672 }
634 } 673 }
674 ModuleDef::Struct(s) => {
675 return ResolvePathResult::with(
676 PerNs::types((*s).into()),
677 ReachedFixedPoint::Yes,
678 Some(i),
679 );
680 }
635 _ => { 681 _ => {
636 // could be an inherent method call in UFCS form 682 // could be an inherent method call in UFCS form
637 // (`Struct::method`), or some other kind of associated 683 // (`Struct::method`), or some other kind of associated
@@ -641,11 +687,11 @@ impl ItemMap {
641 segment.name, 687 segment.name,
642 curr, 688 curr,
643 ); 689 );
644 return (PerNs::none(), ReachedFixedPoint::Yes); 690 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
645 } 691 }
646 }; 692 };
647 } 693 }
648 (curr_per_ns, ReachedFixedPoint::Yes) 694 ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None)
649 } 695 }
650} 696}
651 697