diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-22 19:58:22 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-22 19:58:22 +0000 |
commit | 3d8a0982a12f3aa4b8c193a841f864b15c3cb66e (patch) | |
tree | e20ae00628cc28417e22621f583ba6988677ffcd /crates/ra_hir/src/nameres.rs | |
parent | bb665a70627cbc2f4fb930fefb04899941b6afa6 (diff) | |
parent | 247d1c17b385ff8a8c1dda2e899495146b643b98 (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.rs | 77 |
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)] | ||
446 | struct ResolvePathResult { | ||
447 | resolved_def: PerNs<ModuleDef>, | ||
448 | segment_index: Option<usize>, | ||
449 | reached_fixedpoint: ReachedFixedPoint, | ||
450 | } | ||
451 | |||
452 | impl 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)] |
439 | enum ResolveMode { | 467 | enum 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 | ||