From 816971ebc9207c5fb5779d448613dd171c27f398 Mon Sep 17 00:00:00 2001 From: Ville Penttinen Date: Thu, 21 Feb 2019 12:04:14 +0200 Subject: 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. --- crates/ra_hir/src/resolve.rs | 46 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) (limited to 'crates/ra_hir/src/resolve.rs') diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 91a531801..00b55eae9 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs @@ -32,6 +32,32 @@ pub(crate) struct ExprScope { scope_id: ScopeId, } +#[derive(Debug, Clone)] +pub enum PathResult { + /// Path was fully resolved + FullyResolved(PerNs), + /// Path was partially resolved, first element contains the resolution + /// second contains the index in the Path.segments which we were unable to resolve + PartiallyResolved(PerNs, usize), +} + +impl PathResult { + pub fn segment_index(&self) -> Option { + match self { + PathResult::FullyResolved(_) => None, + PathResult::PartiallyResolved(_, ref i) => Some(*i), + } + } + + /// Consumes `PathResult` and returns the contained `PerNs` + pub fn into_per_ns(self) -> PerNs { + match self { + PathResult::FullyResolved(def) => def, + PathResult::PartiallyResolved(def, _) => def, + } + } +} + #[derive(Debug, Clone)] pub(crate) enum Scope { /// All the items and imported names of a module @@ -67,18 +93,26 @@ impl Resolver { resolution } - pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs { + pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PathResult { + use self::PathResult::*; if let Some(name) = path.as_ident() { - self.resolve_name(db, name) + FullyResolved(self.resolve_name(db, name)) } else if path.is_self() { - self.resolve_name(db, &Name::self_param()) + FullyResolved(self.resolve_name(db, &Name::self_param())) } else { let (item_map, module) = match self.module() { Some(m) => m, - _ => return PerNs::none(), + _ => return FullyResolved(PerNs::none()), }; - let module_res = item_map.resolve_path(db, module, path); - module_res.map(Resolution::Def) + let (module_res, segment_index) = item_map.resolve_path(db, module, path); + + let def = module_res.map(Resolution::Def); + + if let Some(index) = segment_index { + PartiallyResolved(def, index) + } else { + FullyResolved(def) + } } } -- cgit v1.2.3 From 2e7bc905be156a007a4ee8f1a1bd1d73a1d19ade Mon Sep 17 00:00:00 2001 From: Ville Penttinen Date: Thu, 21 Feb 2019 23:57:07 +0200 Subject: Remove Const inference for now, refactor PathResult --- crates/ra_hir/src/resolve.rs | 78 +++++++++++++++++++++++++++++++++----------- 1 file changed, 59 insertions(+), 19 deletions(-) (limited to 'crates/ra_hir/src/resolve.rs') diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 00b55eae9..9f4d4ab42 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs @@ -33,27 +33,68 @@ pub(crate) struct ExprScope { } #[derive(Debug, Clone)] -pub enum PathResult { - /// Path was fully resolved - FullyResolved(PerNs), - /// Path was partially resolved, first element contains the resolution - /// second contains the index in the Path.segments which we were unable to resolve - PartiallyResolved(PerNs, usize), +pub struct PathResult { + /// The actual path resolution + resolution: PerNs, + /// The first index in the path that we + /// were unable to resolve. + /// When path is fully resolved, this is 0. + remaining_index: usize, } impl PathResult { - pub fn segment_index(&self) -> Option { - match self { - PathResult::FullyResolved(_) => None, - PathResult::PartiallyResolved(_, ref i) => Some(*i), + /// Returns the remaining index in the result + /// returns None if the path was fully resolved + pub fn remaining_index(&self) -> Option { + if self.remaining_index > 0 { + Some(self.remaining_index) + } else { + None } } /// Consumes `PathResult` and returns the contained `PerNs` + /// if the path was fully resolved, meaning we have no remaining items pub fn into_per_ns(self) -> PerNs { - match self { - PathResult::FullyResolved(def) => def, - PathResult::PartiallyResolved(def, _) => def, + if self.remaining_index().is_none() { + self.resolution + } else { + PerNs::none() + } + } + + /// Consumes `PathResult` and returns the resolution and the + /// remaining_index as a tuple. + pub fn into_inner(self) -> (PerNs, Option) { + let index = self.remaining_index(); + (self.resolution, index) + } + + /// Path is fully resolved when `remaining_index` is none + /// and the resolution contains anything + pub fn is_fully_resolved(&self) -> bool { + !self.resolution.is_none() && self.remaining_index().is_none() + } + + /// Empty path result is where the resolution is `none` + /// and the remaining index is 0 + pub fn is_empty(&self) -> bool { + self.resolution.is_none() && self.remaining_index().is_none() + } + + fn empty() -> PathResult { + PathResult { resolution: PerNs::none(), remaining_index: 0 } + } + + fn from_resolution(res: PerNs) -> PathResult { + PathResult::from_resolution_with_index(res, 0) + } + + fn from_resolution_with_index(res: PerNs, remaining_index: usize) -> PathResult { + if res.is_none() { + PathResult::empty() + } else { + PathResult { resolution: res, remaining_index } } } } @@ -94,24 +135,23 @@ impl Resolver { } pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PathResult { - use self::PathResult::*; if let Some(name) = path.as_ident() { - FullyResolved(self.resolve_name(db, name)) + PathResult::from_resolution(self.resolve_name(db, name)) } else if path.is_self() { - FullyResolved(self.resolve_name(db, &Name::self_param())) + PathResult::from_resolution(self.resolve_name(db, &Name::self_param())) } else { let (item_map, module) = match self.module() { Some(m) => m, - _ => return FullyResolved(PerNs::none()), + _ => return PathResult::empty(), }; let (module_res, segment_index) = item_map.resolve_path(db, module, path); let def = module_res.map(Resolution::Def); if let Some(index) = segment_index { - PartiallyResolved(def, index) + PathResult::from_resolution_with_index(def, index) } else { - FullyResolved(def) + PathResult::from_resolution(def) } } } -- cgit v1.2.3 From 247d1c17b385ff8a8c1dda2e899495146b643b98 Mon Sep 17 00:00:00 2001 From: Ville Penttinen Date: Fri, 22 Feb 2019 10:15:23 +0200 Subject: Change resolve_path to return the fully resolved path or PerNs::none This also adds new pub(crate) resolve_path_segments which returns the PathResult, which may or may not be fully resolved. PathResult is also now pub(crate) since it is an implementation detail. --- crates/ra_hir/src/resolve.rs | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) (limited to 'crates/ra_hir/src/resolve.rs') diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 9f4d4ab42..57e7d0b9a 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs @@ -33,7 +33,7 @@ pub(crate) struct ExprScope { } #[derive(Debug, Clone)] -pub struct PathResult { +pub(crate) struct PathResult { /// The actual path resolution resolution: PerNs, /// The first index in the path that we @@ -45,7 +45,7 @@ pub struct PathResult { impl PathResult { /// Returns the remaining index in the result /// returns None if the path was fully resolved - pub fn remaining_index(&self) -> Option { + pub(crate) fn remaining_index(&self) -> Option { if self.remaining_index > 0 { Some(self.remaining_index) } else { @@ -55,8 +55,8 @@ impl PathResult { /// Consumes `PathResult` and returns the contained `PerNs` /// if the path was fully resolved, meaning we have no remaining items - pub fn into_per_ns(self) -> PerNs { - if self.remaining_index().is_none() { + pub(crate) fn into_fully_resolved(self) -> PerNs { + if self.is_fully_resolved() { self.resolution } else { PerNs::none() @@ -65,23 +65,17 @@ impl PathResult { /// Consumes `PathResult` and returns the resolution and the /// remaining_index as a tuple. - pub fn into_inner(self) -> (PerNs, Option) { + pub(crate) fn into_inner(self) -> (PerNs, Option) { let index = self.remaining_index(); (self.resolution, index) } /// Path is fully resolved when `remaining_index` is none /// and the resolution contains anything - pub fn is_fully_resolved(&self) -> bool { + pub(crate) fn is_fully_resolved(&self) -> bool { !self.resolution.is_none() && self.remaining_index().is_none() } - /// Empty path result is where the resolution is `none` - /// and the remaining index is 0 - pub fn is_empty(&self) -> bool { - self.resolution.is_none() && self.remaining_index().is_none() - } - fn empty() -> PathResult { PathResult { resolution: PerNs::none(), remaining_index: 0 } } @@ -134,7 +128,9 @@ impl Resolver { resolution } - pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PathResult { + /// Returns the resolved path segments + /// Which may be fully resolved, empty or partially resolved. + pub(crate) fn resolve_path_segments(&self, db: &impl HirDatabase, path: &Path) -> PathResult { if let Some(name) = path.as_ident() { PathResult::from_resolution(self.resolve_name(db, name)) } else if path.is_self() { @@ -156,6 +152,13 @@ impl Resolver { } } + /// Returns the fully resolved path if we were able to resolve it. + /// otherwise returns `PerNs::none` + pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs { + // into_fully_resolved() returns the fully resolved path or PerNs::none() otherwise + self.resolve_path_segments(db, path).into_fully_resolved() + } + pub fn all_names(&self, db: &impl HirDatabase) -> FxHashMap> { let mut names = FxHashMap::default(); for scope in self.scopes.iter().rev() { -- cgit v1.2.3