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/resolve.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/resolve.rs')
-rw-r--r-- | crates/ra_hir/src/resolve.rs | 89 |
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)] |
36 | pub(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 | |||
45 | impl 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)] | ||
36 | pub(crate) enum Scope { | 97 | pub(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() { |