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.
This commit is contained in:
Ville Penttinen 2019-02-22 10:15:23 +02:00
parent 39679d499f
commit 247d1c17b3
5 changed files with 38 additions and 36 deletions

View file

@ -88,7 +88,7 @@ impl ImplBlock {
if let Some(TypeRef::Path(path)) = self.target_trait_ref(db) { if let Some(TypeRef::Path(path)) = self.target_trait_ref(db) {
let resolver = self.resolver(db); let resolver = self.resolver(db);
if let Some(Resolution::Def(ModuleDef::Trait(tr))) = if let Some(Resolution::Def(ModuleDef::Trait(tr))) =
resolver.resolve_path(db, &path).into_per_ns().take_types() resolver.resolve_path(db, &path).take_types()
{ {
return Some(tr); return Some(tr);
} }

View file

@ -33,7 +33,7 @@ pub(crate) struct ExprScope {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct PathResult { pub(crate) struct PathResult {
/// The actual path resolution /// The actual path resolution
resolution: PerNs<Resolution>, resolution: PerNs<Resolution>,
/// The first index in the path that we /// The first index in the path that we
@ -45,7 +45,7 @@ pub struct PathResult {
impl PathResult { impl PathResult {
/// Returns the remaining index in the result /// Returns the remaining index in the result
/// returns None if the path was fully resolved /// returns None if the path was fully resolved
pub fn remaining_index(&self) -> Option<usize> { pub(crate) fn remaining_index(&self) -> Option<usize> {
if self.remaining_index > 0 { if self.remaining_index > 0 {
Some(self.remaining_index) Some(self.remaining_index)
} else { } else {
@ -55,8 +55,8 @@ impl PathResult {
/// Consumes `PathResult` and returns the contained `PerNs<Resolution>` /// Consumes `PathResult` and returns the contained `PerNs<Resolution>`
/// if the path was fully resolved, meaning we have no remaining items /// if the path was fully resolved, meaning we have no remaining items
pub fn into_per_ns(self) -> PerNs<Resolution> { pub(crate) fn into_fully_resolved(self) -> PerNs<Resolution> {
if self.remaining_index().is_none() { if self.is_fully_resolved() {
self.resolution self.resolution
} else { } else {
PerNs::none() PerNs::none()
@ -65,23 +65,17 @@ impl PathResult {
/// Consumes `PathResult` and returns the resolution and the /// Consumes `PathResult` and returns the resolution and the
/// remaining_index as a tuple. /// remaining_index as a tuple.
pub fn into_inner(self) -> (PerNs<Resolution>, Option<usize>) { pub(crate) fn into_inner(self) -> (PerNs<Resolution>, Option<usize>) {
let index = self.remaining_index(); let index = self.remaining_index();
(self.resolution, index) (self.resolution, index)
} }
/// Path is fully resolved when `remaining_index` is none /// Path is fully resolved when `remaining_index` is none
/// and the resolution contains anything /// 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() !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 { fn empty() -> PathResult {
PathResult { resolution: PerNs::none(), remaining_index: 0 } PathResult { resolution: PerNs::none(), remaining_index: 0 }
} }
@ -134,7 +128,9 @@ impl Resolver {
resolution 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() { if let Some(name) = path.as_ident() {
PathResult::from_resolution(self.resolve_name(db, name)) PathResult::from_resolution(self.resolve_name(db, name))
} else if path.is_self() { } 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<Resolution> {
// 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<Name, PerNs<Resolution>> { pub fn all_names(&self, db: &impl HirDatabase) -> FxHashMap<Name, PerNs<Resolution>> {
let mut names = FxHashMap::default(); let mut names = FxHashMap::default();
for scope in self.scopes.iter().rev() { for scope in self.scopes.iter().rev() {

View file

@ -370,7 +370,7 @@ impl Ty {
} }
// Resolve the path (in type namespace) // Resolve the path (in type namespace)
let resolution = resolver.resolve_path(db, path).into_per_ns().take_types(); let resolution = resolver.resolve_path(db, path).take_types();
let def = match resolution { let def = match resolution {
Some(Resolution::Def(def)) => def, Some(Resolution::Def(def)) => def,
@ -1172,7 +1172,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
} }
fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path) -> Option<Ty> { fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path) -> Option<Ty> {
let resolved = resolver.resolve_path(self.db, &path); let resolved = resolver.resolve_path_segments(self.db, &path);
let (def, remaining_index) = resolved.into_inner(); let (def, remaining_index) = resolved.into_inner();
@ -1244,24 +1244,23 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
None => return (Ty::Unknown, None), None => return (Ty::Unknown, None),
}; };
let resolver = &self.resolver; let resolver = &self.resolver;
let typable: Option<TypableDef> = let typable: Option<TypableDef> = match resolver.resolve_path(self.db, &path).take_types() {
match resolver.resolve_path(self.db, &path).into_per_ns().take_types() { Some(Resolution::Def(def)) => def.into(),
Some(Resolution::Def(def)) => def.into(), Some(Resolution::LocalBinding(..)) => {
Some(Resolution::LocalBinding(..)) => { // this cannot happen
// this cannot happen log::error!("path resolved to local binding in type ns");
log::error!("path resolved to local binding in type ns"); return (Ty::Unknown, None);
return (Ty::Unknown, None); }
} Some(Resolution::GenericParam(..)) => {
Some(Resolution::GenericParam(..)) => { // generic params can't be used in struct literals
// generic params can't be used in struct literals return (Ty::Unknown, None);
return (Ty::Unknown, None); }
} Some(Resolution::SelfType(..)) => {
Some(Resolution::SelfType(..)) => { // TODO this is allowed in an impl for a struct, handle this
// TODO this is allowed in an impl for a struct, handle this return (Ty::Unknown, None);
return (Ty::Unknown, None); }
} None => return (Ty::Unknown, None),
None => return (Ty::Unknown, None), };
};
let def = match typable { let def = match typable {
None => return (Ty::Unknown, None), None => return (Ty::Unknown, None),
Some(it) => it, Some(it) => it,

View file

@ -10,7 +10,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
Some(path) => path.clone(), Some(path) => path.clone(),
_ => return, _ => return,
}; };
let def = match ctx.resolver.resolve_path(ctx.db, &path).into_per_ns().take_types() { let def = match ctx.resolver.resolve_path(ctx.db, &path).take_types() {
Some(Resolution::Def(def)) => def, Some(Resolution::Def(def)) => def,
_ => return, _ => return,
}; };

View file

@ -79,7 +79,7 @@ pub(crate) fn reference_definition(
if let Some(path) = if let Some(path) =
name_ref.syntax().ancestors().find_map(ast::Path::cast).and_then(hir::Path::from_ast) name_ref.syntax().ancestors().find_map(ast::Path::cast).and_then(hir::Path::from_ast)
{ {
let resolved = resolver.resolve_path(db, &path).into_per_ns(); let resolved = resolver.resolve_path(db, &path);
match resolved.clone().take_types().or_else(|| resolved.take_values()) { match resolved.clone().take_types().or_else(|| resolved.take_values()) {
Some(Resolution::Def(def)) => return Exact(NavigationTarget::from_def(db, def)), Some(Resolution::Def(def)) => return Exact(NavigationTarget::from_def(db, def)),
Some(Resolution::LocalBinding(pat)) => { Some(Resolution::LocalBinding(pat)) => {