aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/resolve.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/resolve.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/resolve.rs')
-rw-r--r--crates/ra_hir/src/resolve.rs89
1 files changed, 83 insertions, 6 deletions
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs
index 91a531801..57e7d0b9a 100644
--- a/crates/ra_hir/src/resolve.rs
+++ b/crates/ra_hir/src/resolve.rs
@@ -33,6 +33,67 @@ pub(crate) struct ExprScope {
33} 33}
34 34
35#[derive(Debug, Clone)] 35#[derive(Debug, Clone)]
36pub(crate) struct PathResult {
37 /// The actual path resolution
38 resolution: PerNs<Resolution>,
39 /// The first index in the path that we
40 /// were unable to resolve.
41 /// When path is fully resolved, this is 0.
42 remaining_index: usize,
43}
44
45impl PathResult {
46 /// Returns the remaining index in the result
47 /// returns None if the path was fully resolved
48 pub(crate) fn remaining_index(&self) -> Option<usize> {
49 if self.remaining_index > 0 {
50 Some(self.remaining_index)
51 } else {
52 None
53 }
54 }
55
56 /// Consumes `PathResult` and returns the contained `PerNs<Resolution>`
57 /// if the path was fully resolved, meaning we have no remaining items
58 pub(crate) fn into_fully_resolved(self) -> PerNs<Resolution> {
59 if self.is_fully_resolved() {
60 self.resolution
61 } else {
62 PerNs::none()
63 }
64 }
65
66 /// Consumes `PathResult` and returns the resolution and the
67 /// remaining_index as a tuple.
68 pub(crate) fn into_inner(self) -> (PerNs<Resolution>, Option<usize>) {
69 let index = self.remaining_index();
70 (self.resolution, index)
71 }
72
73 /// Path is fully resolved when `remaining_index` is none
74 /// and the resolution contains anything
75 pub(crate) fn is_fully_resolved(&self) -> bool {
76 !self.resolution.is_none() && self.remaining_index().is_none()
77 }
78
79 fn empty() -> PathResult {
80 PathResult { resolution: PerNs::none(), remaining_index: 0 }
81 }
82
83 fn from_resolution(res: PerNs<Resolution>) -> PathResult {
84 PathResult::from_resolution_with_index(res, 0)
85 }
86
87 fn from_resolution_with_index(res: PerNs<Resolution>, remaining_index: usize) -> PathResult {
88 if res.is_none() {
89 PathResult::empty()
90 } else {
91 PathResult { resolution: res, remaining_index }
92 }
93 }
94}
95
96#[derive(Debug, Clone)]
36pub(crate) enum Scope { 97pub(crate) enum Scope {
37 /// All the items and imported names of a module 98 /// All the items and imported names of a module
38 ModuleScope(ModuleItemMap), 99 ModuleScope(ModuleItemMap),
@@ -67,21 +128,37 @@ impl Resolver {
67 resolution 128 resolution
68 } 129 }
69 130
70 pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs<Resolution> { 131 /// Returns the resolved path segments
132 /// Which may be fully resolved, empty or partially resolved.
133 pub(crate) fn resolve_path_segments(&self, db: &impl HirDatabase, path: &Path) -> PathResult {
71 if let Some(name) = path.as_ident() { 134 if let Some(name) = path.as_ident() {
72 self.resolve_name(db, name) 135 PathResult::from_resolution(self.resolve_name(db, name))
73 } else if path.is_self() { 136 } else if path.is_self() {
74 self.resolve_name(db, &Name::self_param()) 137 PathResult::from_resolution(self.resolve_name(db, &Name::self_param()))
75 } else { 138 } else {
76 let (item_map, module) = match self.module() { 139 let (item_map, module) = match self.module() {
77 Some(m) => m, 140 Some(m) => m,
78 _ => return PerNs::none(), 141 _ => return PathResult::empty(),
79 }; 142 };
80 let module_res = item_map.resolve_path(db, module, path); 143 let (module_res, segment_index) = item_map.resolve_path(db, module, path);
81 module_res.map(Resolution::Def) 144
145 let def = module_res.map(Resolution::Def);
146
147 if let Some(index) = segment_index {
148 PathResult::from_resolution_with_index(def, index)
149 } else {
150 PathResult::from_resolution(def)
151 }
82 } 152 }
83 } 153 }
84 154
155 /// Returns the fully resolved path if we were able to resolve it.
156 /// otherwise returns `PerNs::none`
157 pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs<Resolution> {
158 // into_fully_resolved() returns the fully resolved path or PerNs::none() otherwise
159 self.resolve_path_segments(db, path).into_fully_resolved()
160 }
161
85 pub fn all_names(&self, db: &impl HirDatabase) -> FxHashMap<Name, PerNs<Resolution>> { 162 pub fn all_names(&self, db: &impl HirDatabase) -> FxHashMap<Name, PerNs<Resolution>> {
86 let mut names = FxHashMap::default(); 163 let mut names = FxHashMap::default();
87 for scope in self.scopes.iter().rev() { 164 for scope in self.scopes.iter().rev() {