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/ty/infer.rs | 100 ++++++++++++++++++++++++++---------------- crates/ra_hir/src/ty/lower.rs | 34 +++++++++----- 2 files changed, 85 insertions(+), 49 deletions(-) (limited to 'crates/ra_hir/src/ty') 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