From fe1dfd2b20b256b99f40f6f6421f7c7e12c23e41 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Mon, 16 Sep 2019 21:38:27 +0200 Subject: Refactor some more Type-relative paths (`::foo`) also need to work in type context, for example `::Item` is legal. So rather than returning the type ref from the resolver function, just check it before. --- crates/ra_hir/src/path.rs | 7 +++ crates/ra_hir/src/resolve.rs | 16 +++---- crates/ra_hir/src/ty/infer.rs | 100 ++++++++++++++++++++++++++---------------- crates/ra_hir/src/ty/lower.rs | 34 +++++++++----- 4 files changed, 100 insertions(+), 57 deletions(-) diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs index a61161b63..39d1b7e46 100644 --- a/crates/ra_hir/src/path.rs +++ b/crates/ra_hir/src/path.rs @@ -190,6 +190,13 @@ impl Path { pub fn expand_macro_expr(&self) -> Option { self.as_ident().and_then(|name| Some(name.clone())) } + + pub fn is_type_relative(&self) -> bool { + match self.kind { + PathKind::Type(_) => true, + _ => false, + } + } } impl GenericArgs { diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 7f4c78859..a23c8792a 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs @@ -15,7 +15,6 @@ use crate::{ name::{Name, SELF_PARAM, SELF_TYPE}, nameres::{CrateDefMap, CrateModuleId, PerNs}, path::{Path, PathKind}, - type_ref::TypeRef, Adt, BuiltinType, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, Static, Struct, Trait, TypeAlias, }; @@ -65,10 +64,9 @@ pub enum TypeNs { } #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum ResolveValueResult<'a> { +pub enum ResolveValueResult { ValueNs(ValueNs), Partial(TypeNs, usize), - TypeRef(&'a TypeRef), } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -131,6 +129,9 @@ impl Resolver { db: &impl HirDatabase, path: &Path, ) -> Option<(TypeNs, Option)> { + if path.is_type_relative() { + return None; + } let first_name = &path.segments.first()?.name; let skip_to_mod = path.kind != PathKind::Plain; for scope in self.scopes.iter().rev() { @@ -189,11 +190,10 @@ impl Resolver { &self, db: &impl HirDatabase, path: &'p Path, - ) -> Option> { - if let PathKind::Type(type_ref) = &path.kind { - return Some(ResolveValueResult::TypeRef(type_ref)); + ) -> Option { + if path.is_type_relative() { + return None; } - let n_segments = path.segments.len(); let tmp = SELF_PARAM; let first_name = if path.is_self() { &tmp } else { &path.segments.first()?.name }; @@ -284,7 +284,7 @@ impl Resolver { ) -> Option { match self.resolve_path_in_value_ns(db, path)? { ResolveValueResult::ValueNs(it) => Some(it), - ResolveValueResult::Partial(..) | ResolveValueResult::TypeRef(_) => None, + ResolveValueResult::Partial(..) => None, } } diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index f33479dc4..181be0fcc 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -48,8 +48,7 @@ use crate::{ resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs}, ty::infer::diagnostics::InferenceDiagnostic, type_ref::{Mutability, TypeRef}, - Adt, AssocItem, ConstData, DefWithBody, Either, FnData, Function, HasBody, Name, Path, - StructField, + Adt, AssocItem, ConstData, DefWithBody, FnData, Function, HasBody, Name, Path, StructField, }; mod unify; @@ -468,16 +467,27 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path, id: ExprOrPatId) -> Option { - let value_or_partial = resolver.resolve_path_in_value_ns(self.db, &path)?; - - let (value, self_subst) = match value_or_partial { - ResolveValueResult::ValueNs(it) => (it, None), - ResolveValueResult::Partial(def, remaining_index) => { - self.resolve_assoc_item(Either::A(def), path, remaining_index, id)? + let (value, self_subst) = if let crate::PathKind::Type(type_ref) = &path.kind { + if path.segments.is_empty() { + // This can't actually happen syntax-wise + return None; } - ResolveValueResult::TypeRef(type_ref) => { - let ty = self.make_ty(type_ref); - self.resolve_assoc_item(Either::B(ty), path, 0, id)? + let ty = self.make_ty(type_ref); + let remaining_segments_for_ty = &path.segments[..path.segments.len() - 1]; + let ty = Ty::from_type_relative_path(self.db, resolver, ty, remaining_segments_for_ty); + self.resolve_ty_assoc_item( + ty, + path.segments.last().expect("path had at least one segment"), + id, + )? + } else { + let value_or_partial = resolver.resolve_path_in_value_ns(self.db, &path)?; + + match value_or_partial { + ResolveValueResult::ValueNs(it) => (it, None), + ResolveValueResult::Partial(def, remaining_index) => { + self.resolve_assoc_item(def, path, remaining_index, id)? + } } }; @@ -508,15 +518,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { fn resolve_assoc_item( &mut self, - // mut def_or_ty: Either, def: TypeNs, path: &Path, remaining_index: usize, id: ExprOrPatId, ) -> Option<(ValueNs, Option)> { assert!(remaining_index < path.segments.len()); - let krate = self.resolver.krate()?; - // there may be more intermediate segments between the resolved one and // the end. Only the last segment needs to be resolved to a value; from // the segments before that, we need to get either a type or a trait ref. @@ -525,11 +532,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let remaining_segments = &path.segments[remaining_index..]; let is_before_last = remaining_segments.len() == 1; - let (def, substs) = match (def, is_before_last) { + match (def, is_before_last) { (TypeNs::Trait(_trait), true) => { - // Associated item of trait, e.g. `Default::default` - // FIXME - return None; + // FIXME Associated item of trait, e.g. `Default::default` + None } (def, _) => { // Either we already have a type (e.g. `Vec::new`), or we have a @@ -550,29 +556,45 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let segment = remaining_segments.last().expect("there should be at least one segment here"); - // Find impl - let def = ty.clone().iterate_impl_items(self.db, krate, |item| match item { - crate::ImplItem::Method(func) => { - if segment.name == func.name(self.db) { - Some(ValueNs::Function(func)) - } else { - None - } - } - crate::ImplItem::Const(konst) => { - if segment.name == konst.name(self.db) { - Some(ValueNs::Const(konst)) - } else { - None - } - } - crate::ImplItem::TypeAlias(_) => None, - })?; - let self_types = self.find_self_types(&def, ty); - (def, self_types) + self.resolve_ty_assoc_item(ty, segment, id) } - }; + } + } + + fn resolve_ty_assoc_item( + &mut self, + ty: Ty, + segment: &crate::path::PathSegment, + id: ExprOrPatId, + ) -> Option<(ValueNs, Option)> { + if let Ty::Unknown = ty { + return None; + } + + let krate = self.resolver.krate()?; + + // Find impl + // FIXME: consider trait candidates + let def = ty.clone().iterate_impl_items(self.db, krate, |item| match item { + crate::ImplItem::Method(func) => { + if segment.name == func.name(self.db) { + Some(ValueNs::Function(func)) + } else { + None + } + } + + crate::ImplItem::Const(konst) => { + if konst.name(self.db).map_or(false, |n| n == segment.name) { + Some(ValueNs::Const(konst)) + } else { + None + } + } + crate::ImplItem::TypeAlias(_) => None, + })?; + let substs = self.find_self_types(&def, ty); self.write_assoc_resolution( id, diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index e29b68f1a..e6cd5d0be 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs @@ -86,6 +86,24 @@ impl Ty { } } + pub(crate) fn from_type_relative_path( + db: &impl HirDatabase, + resolver: &Resolver, + ty: Ty, + remaining_segments: &[PathSegment], + ) -> Ty { + if remaining_segments.len() == 1 { + // resolve unselected assoc types + let segment = &remaining_segments[0]; + Ty::select_associated_type(db, resolver, ty, segment) + } else if remaining_segments.len() > 1 { + // FIXME report error (ambiguous associated type) + Ty::Unknown + } else { + ty + } + } + pub(crate) fn from_partly_resolved_hir_path( db: &impl HirDatabase, resolver: &Resolver, @@ -140,20 +158,16 @@ impl Ty { TypeNs::EnumVariant(_) => return Ty::Unknown, }; - if remaining_segments.len() == 1 { - // resolve unselected assoc types - let segment = &remaining_segments[0]; - Ty::select_associated_type(db, resolver, ty, segment) - } else if remaining_segments.len() > 1 { - // FIXME report error (ambiguous associated type) - Ty::Unknown - } else { - ty - } + Ty::from_type_relative_path(db, resolver, ty, remaining_segments) } pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty { // Resolve the path (in type namespace) + if let crate::PathKind::Type(type_ref) = &path.kind { + let ty = Ty::from_hir(db, resolver, &type_ref); + let remaining_segments = &path.segments[..]; + return Ty::from_type_relative_path(db, resolver, ty, remaining_segments); + } let (resolution, remaining_index) = match resolver.resolve_path_in_type_ns(db, path) { Some(it) => it, None => return Ty::Unknown, -- cgit v1.2.3