diff options
author | Ville Penttinen <[email protected]> | 2019-02-21 10:04:14 +0000 |
---|---|---|
committer | Ville Penttinen <[email protected]> | 2019-02-21 10:25:55 +0000 |
commit | 816971ebc9207c5fb5779d448613dd171c27f398 (patch) | |
tree | fe49d209a852bb1b4a51eea9d40449dcf2845209 /crates/ra_hir/src/nameres.rs | |
parent | c84561bb624280b84eb2fe6c6b2a6b9fe3f1dbf7 (diff) |
Implement basic support for Associated Methods and Constants
This is done in `infer_path_expr`. When `Resolver::resolve_path` returns
`PartiallyResolved`, we use the returned `Resolution` together with the given
`segment_index` to check if we can find something matching the segment at
segment_index in the impls for that particular type.
Diffstat (limited to 'crates/ra_hir/src/nameres.rs')
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 78 |
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)] | ||
450 | pub struct ResolvePathResult { | ||
451 | pub(crate) module: PerNs<ModuleDef>, | ||
452 | pub(crate) segment_index: Option<usize>, | ||
453 | reached_fixedpoint: ReachedFixedPoint, | ||
454 | } | ||
455 | |||
456 | impl 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)] |
439 | enum ResolveMode { | 471 | enum 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 | ||