aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/nameres.rs
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-02-22 19:58:22 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-02-22 19:58:22 +0000
commit3d8a0982a12f3aa4b8c193a841f864b15c3cb66e (patch)
treee20ae00628cc28417e22621f583ba6988677ffcd /crates/ra_hir/src/nameres.rs
parentbb665a70627cbc2f4fb930fefb04899941b6afa6 (diff)
parent247d1c17b385ff8a8c1dda2e899495146b643b98 (diff)
Merge #866
866: Implement basic support for Associated Methods r=flodiebold a=vipentti This is my attempt at learning to understand how the type inference works by adding basic support for associated methods. Currently it does not resolve associated types or constants. The basic idea is that `Resolver::resolve_path` returns a new `PathResult` type, which has two variants, `FullyResolved` and `PartiallyResolved`, fully resolved matches the previous behavior, where as `PartiallyResolved` contains the `PerNs<Resolution` in addition to a `segment_index` which contains the index of the segment which we failed to resolve. This index can then be used to continue inference in `infer_path_expr` using the `Type` we managed to resolve. This changes some of the previous apis, so looking for feedback and suggestions. This should enable fixing #832 Co-authored-by: Ville Penttinen <[email protected]>
Diffstat (limited to 'crates/ra_hir/src/nameres.rs')
-rw-r--r--crates/ra_hir/src/nameres.rs77
1 files changed, 58 insertions, 19 deletions
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index bd920bfea..8067b8415 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -297,7 +297,14 @@ where
297 ); 297 );
298 (res, if res.is_none() { ReachedFixedPoint::No } else { ReachedFixedPoint::Yes }) 298 (res, if res.is_none() { ReachedFixedPoint::No } else { ReachedFixedPoint::Yes })
299 } else { 299 } else {
300 self.result.resolve_path_fp(self.db, ResolveMode::Import, original_module, &import.path) 300 let res = self.result.resolve_path_fp(
301 self.db,
302 ResolveMode::Import,
303 original_module,
304 &import.path,
305 );
306
307 (res.resolved_def, res.reached_fixedpoint)
301 }; 308 };
302 309
303 if reached_fixedpoint != ReachedFixedPoint::Yes { 310 if reached_fixedpoint != ReachedFixedPoint::Yes {
@@ -435,6 +442,27 @@ where
435 } 442 }
436} 443}
437 444
445#[derive(Debug, Clone)]
446struct ResolvePathResult {
447 resolved_def: PerNs<ModuleDef>,
448 segment_index: Option<usize>,
449 reached_fixedpoint: ReachedFixedPoint,
450}
451
452impl ResolvePathResult {
453 fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
454 ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None)
455 }
456
457 fn with(
458 resolved_def: PerNs<ModuleDef>,
459 reached_fixedpoint: ReachedFixedPoint,
460 segment_index: Option<usize>,
461 ) -> ResolvePathResult {
462 ResolvePathResult { resolved_def, reached_fixedpoint, segment_index }
463 }
464}
465
438#[derive(Debug, Clone, Copy, PartialEq, Eq)] 466#[derive(Debug, Clone, Copy, PartialEq, Eq)]
439enum ResolveMode { 467enum ResolveMode {
440 Import, 468 Import,
@@ -468,8 +496,9 @@ impl ItemMap {
468 db: &impl PersistentHirDatabase, 496 db: &impl PersistentHirDatabase,
469 original_module: Module, 497 original_module: Module,
470 path: &Path, 498 path: &Path,
471 ) -> PerNs<ModuleDef> { 499 ) -> (PerNs<ModuleDef>, Option<usize>) {
472 self.resolve_path_fp(db, ResolveMode::Other, original_module, path).0 500 let res = self.resolve_path_fp(db, ResolveMode::Other, original_module, path);
501 (res.resolved_def, res.segment_index)
473 } 502 }
474 503
475 fn resolve_in_prelude( 504 fn resolve_in_prelude(
@@ -534,7 +563,7 @@ impl ItemMap {
534 mode: ResolveMode, 563 mode: ResolveMode,
535 original_module: Module, 564 original_module: Module,
536 path: &Path, 565 path: &Path,
537 ) -> (PerNs<ModuleDef>, ReachedFixedPoint) { 566 ) -> ResolvePathResult {
538 let mut segments = path.segments.iter().enumerate(); 567 let mut segments = path.segments.iter().enumerate();
539 let mut curr_per_ns: PerNs<ModuleDef> = match path.kind { 568 let mut curr_per_ns: PerNs<ModuleDef> = match path.kind {
540 PathKind::Crate => PerNs::types(original_module.crate_root(db).into()), 569 PathKind::Crate => PerNs::types(original_module.crate_root(db).into()),
@@ -549,7 +578,7 @@ impl ItemMap {
549 { 578 {
550 let segment = match segments.next() { 579 let segment = match segments.next() {
551 Some((_, segment)) => segment, 580 Some((_, segment)) => segment,
552 None => return (PerNs::none(), ReachedFixedPoint::Yes), 581 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
553 }; 582 };
554 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); 583 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
555 self.resolve_name_in_crate_root_or_extern_prelude( 584 self.resolve_name_in_crate_root_or_extern_prelude(
@@ -561,7 +590,7 @@ impl ItemMap {
561 PathKind::Plain => { 590 PathKind::Plain => {
562 let segment = match segments.next() { 591 let segment = match segments.next() {
563 Some((_, segment)) => segment, 592 Some((_, segment)) => segment,
564 None => return (PerNs::none(), ReachedFixedPoint::Yes), 593 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
565 }; 594 };
566 log::debug!("resolving {:?} in module", segment); 595 log::debug!("resolving {:?} in module", segment);
567 self.resolve_name_in_module(db, original_module, &segment.name) 596 self.resolve_name_in_module(db, original_module, &segment.name)
@@ -571,20 +600,20 @@ impl ItemMap {
571 PerNs::types(p.into()) 600 PerNs::types(p.into())
572 } else { 601 } else {
573 log::debug!("super path in root module"); 602 log::debug!("super path in root module");
574 return (PerNs::none(), ReachedFixedPoint::Yes); 603 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
575 } 604 }
576 } 605 }
577 PathKind::Abs => { 606 PathKind::Abs => {
578 // 2018-style absolute path -- only extern prelude 607 // 2018-style absolute path -- only extern prelude
579 let segment = match segments.next() { 608 let segment = match segments.next() {
580 Some((_, segment)) => segment, 609 Some((_, segment)) => segment,
581 None => return (PerNs::none(), ReachedFixedPoint::Yes), 610 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
582 }; 611 };
583 if let Some(def) = self.extern_prelude.get(&segment.name) { 612 if let Some(def) = self.extern_prelude.get(&segment.name) {
584 log::debug!("absolute path {:?} resolved to crate {:?}", path, def); 613 log::debug!("absolute path {:?} resolved to crate {:?}", path, def);
585 PerNs::types(*def) 614 PerNs::types(*def)
586 } else { 615 } else {
587 return (PerNs::none(), ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude 616 return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
588 } 617 }
589 } 618 }
590 }; 619 };
@@ -598,7 +627,7 @@ impl ItemMap {
598 // (don't break here because `curr_per_ns` might contain 627 // (don't break here because `curr_per_ns` might contain
599 // something in the value namespace, and it would be wrong 628 // something in the value namespace, and it would be wrong
600 // to return that) 629 // to return that)
601 return (PerNs::none(), ReachedFixedPoint::No); 630 return ResolvePathResult::empty(ReachedFixedPoint::No);
602 } 631 }
603 }; 632 };
604 // resolve segment in curr 633 // resolve segment in curr
@@ -612,15 +641,15 @@ impl ItemMap {
612 }; 641 };
613 log::debug!("resolving {:?} in other crate", path); 642 log::debug!("resolving {:?} in other crate", path);
614 let item_map = db.item_map(module.krate); 643 let item_map = db.item_map(module.krate);
615 let def = item_map.resolve_path(db, *module, &path); 644 let (def, s) = item_map.resolve_path(db, *module, &path);
616 return (def, ReachedFixedPoint::Yes); 645 return ResolvePathResult::with(def, ReachedFixedPoint::Yes, s);
617 } 646 }
618 647
619 match self[module.module_id].items.get(&segment.name) { 648 match self[module.module_id].items.get(&segment.name) {
620 Some(res) if !res.def.is_none() => res.def, 649 Some(res) if !res.def.is_none() => res.def,
621 _ => { 650 _ => {
622 log::debug!("path segment {:?} not found", segment.name); 651 log::debug!("path segment {:?} not found", segment.name);
623 return (PerNs::none(), ReachedFixedPoint::No); 652 return ResolvePathResult::empty(ReachedFixedPoint::No);
624 } 653 }
625 } 654 }
626 } 655 }
@@ -629,23 +658,33 @@ impl ItemMap {
629 tested_by!(item_map_enum_importing); 658 tested_by!(item_map_enum_importing);
630 match e.variant(db, &segment.name) { 659 match e.variant(db, &segment.name) {
631 Some(variant) => PerNs::both(variant.into(), variant.into()), 660 Some(variant) => PerNs::both(variant.into(), variant.into()),
632 None => PerNs::none(), 661 None => {
662 return ResolvePathResult::with(
663 PerNs::types((*e).into()),
664 ReachedFixedPoint::Yes,
665 Some(i),
666 );
667 }
633 } 668 }
634 } 669 }
635 _ => { 670 s => {
636 // could be an inherent method call in UFCS form 671 // could be an inherent method call in UFCS form
637 // (`Struct::method`), or some other kind of associated 672 // (`Struct::method`), or some other kind of associated item
638 // item... Which we currently don't handle (TODO)
639 log::debug!( 673 log::debug!(
640 "path segment {:?} resolved to non-module {:?}, but is not last", 674 "path segment {:?} resolved to non-module {:?}, but is not last",
641 segment.name, 675 segment.name,
642 curr, 676 curr,
643 ); 677 );
644 return (PerNs::none(), ReachedFixedPoint::Yes); 678
679 return ResolvePathResult::with(
680 PerNs::types((*s).into()),
681 ReachedFixedPoint::Yes,
682 Some(i),
683 );
645 } 684 }
646 }; 685 };
647 } 686 }
648 (curr_per_ns, ReachedFixedPoint::Yes) 687 ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None)
649 } 688 }
650} 689}
651 690