From 406280e52f20e25af609d947efbed8b352ca1249 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 15 Sep 2019 12:50:57 +0200 Subject: Refactor associated item resolution more When resolving an associated item in value namespace, use the `Ty` lowering code for the segments before the last instead of replicating it. --- crates/ra_hir/src/ty/infer.rs | 125 ++++++++++++++++++------------------------ crates/ra_hir/src/ty/lower.rs | 119 ++++++++++++++++++++++------------------ 2 files changed, 120 insertions(+), 124 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 6aaf61c0e..f33479dc4 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -48,7 +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, ImplItem, Name, Path, + Adt, AssocItem, ConstData, DefWithBody, Either, FnData, Function, HasBody, Name, Path, StructField, }; @@ -508,7 +508,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { fn resolve_assoc_item( &mut self, - mut def_or_ty: Either, + // mut def_or_ty: Either, + def: TypeNs, path: &Path, remaining_index: usize, id: ExprOrPatId, @@ -516,80 +517,63 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { assert!(remaining_index < path.segments.len()); let krate = self.resolver.krate()?; - let mut ty = Ty::Unknown; - - // resolve intermediate segments - for (i, segment) in path.segments[remaining_index..].iter().enumerate() { - let is_last_segment = i == path.segments[remaining_index..].len() - 1; - ty = match def_or_ty { - Either::A(def) => { - let typable: TypableDef = match def { - TypeNs::Adt(it) => it.into(), - TypeNs::TypeAlias(it) => it.into(), - TypeNs::BuiltinType(it) => it.into(), - // FIXME associated item of traits, generics, and Self - TypeNs::Trait(_) | TypeNs::GenericParam(_) | TypeNs::SelfType(_) => { - return None; - } - // FIXME: report error here - TypeNs::EnumVariant(_) => return None, - }; - - let ty = self.db.type_for_def(typable, Namespace::Types); - - // For example, this substs will take `Gen::**::make` - assert!(remaining_index > 0); - let substs = Ty::substs_from_path_segment( - self.db, - &self.resolver, - &path.segments[remaining_index + i - 1], - typable, - ); - ty.subst(&substs) - } - Either::B(ty) => ty, - }; - if is_last_segment { - break; - } + // 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. - // Attempt to find an impl_item for the type which has a name matching - // the current segment - log::debug!("looking for path segment: {:?}", segment); + let resolved_segment = &path.segments[remaining_index - 1]; + let remaining_segments = &path.segments[remaining_index..]; + let is_before_last = remaining_segments.len() == 1; - let ty = mem::replace(&mut ty, Ty::Unknown); - def_or_ty = ty.iterate_impl_items(self.db, krate, |item| { - match item { - crate::ImplItem::Method(_) | crate::ImplItem::Const(_) => None, + let (def, substs) = match (def, is_before_last) { + (TypeNs::Trait(_trait), true) => { + // Associated item of trait, e.g. `Default::default` + // FIXME + return None; + } + (def, _) => { + // Either we already have a type (e.g. `Vec::new`), or we have a + // trait but it's not the last segment, so the next segment + // should resolve to an associated type of that trait (e.g. `::Item::default`) + let remaining_segments_for_ty = &remaining_segments[..remaining_segments.len() - 1]; + let ty = Ty::from_partly_resolved_hir_path( + self.db, + &self.resolver, + def, + resolved_segment, + remaining_segments_for_ty, + ); + if let Ty::Unknown = ty { + return None; + } - // FIXME: Resolve associated types - crate::ImplItem::TypeAlias(_) => { - // Some(Either::A(TypeNs::TypeAlias(..))) - None + 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 + } } - } - })?; - } - let segment = path.segments.last().unwrap(); - 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) } + }; - 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, - })?; self.write_assoc_resolution( id, match def { @@ -598,8 +582,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { _ => unreachable!(), }, ); - let self_types = self.find_self_types(&def, ty); - Some((def, self_types)) + Some((def, substs)) } fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option { diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 62e4ed0f4..e29b68f1a 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs @@ -86,81 +86,94 @@ impl Ty { } } - pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty { - // Resolve the path (in type namespace) - let (resolution, remaining_index) = match resolver.resolve_path_in_type_ns(db, path) { - Some(it) => it, - None => return Ty::Unknown, - }; - + pub(crate) fn from_partly_resolved_hir_path( + db: &impl HirDatabase, + resolver: &Resolver, + resolution: TypeNs, + resolved_segment: &PathSegment, + remaining_segments: &[PathSegment], + ) -> Ty { let ty = match resolution { TypeNs::Trait(trait_) => { - let segment = match remaining_index { - None => path.segments.last().expect("resolved path has at least one element"), - Some(i) => &path.segments[i - 1], - }; - let trait_ref = TraitRef::from_resolved_path(db, resolver, trait_, segment, None); - return if let Some(remaining_index) = remaining_index { - if remaining_index == path.segments.len() - 1 { - let segment = &path.segments[remaining_index]; - match trait_ref - .trait_ - .associated_type_by_name_including_super_traits(db, &segment.name) - { - Some(associated_ty) => { - // FIXME handle type parameters on the segment - Ty::Projection(ProjectionTy { - associated_ty, - parameters: trait_ref.substs, - }) - } - None => { - // associated type not found (FIXME: report error) - Ty::Unknown - } + let trait_ref = + TraitRef::from_resolved_path(db, resolver, trait_, resolved_segment, None); + return if remaining_segments.len() == 1 { + let segment = &remaining_segments[0]; + match trait_ref + .trait_ + .associated_type_by_name_including_super_traits(db, &segment.name) + { + Some(associated_ty) => { + // FIXME handle type parameters on the segment + Ty::Projection(ProjectionTy { + associated_ty, + parameters: trait_ref.substs, + }) + } + None => { + // associated type not found (FIXME: report error) + Ty::Unknown } - } else { - // FIXME report error (ambiguous associated type) - Ty::Unknown } + } else if remaining_segments.len() > 1 { + // FIXME report error (ambiguous associated type) + Ty::Unknown } else { Ty::Dyn(Arc::new([GenericPredicate::Implemented(trait_ref)])) }; } TypeNs::GenericParam(idx) => { // FIXME: maybe return name in resolution? - let name = match remaining_index { - None => path - .as_ident() - .expect("generic param should be single-segment path") - .clone(), - Some(idx) => path.segments[idx - 1].name.clone(), - }; + let name = resolved_segment.name.clone(); Ty::Param { idx, name } } TypeNs::SelfType(impl_block) => impl_block.target_ty(db), - TypeNs::Adt(it) => Ty::from_hir_path_inner(db, resolver, path, it.into()), - TypeNs::BuiltinType(it) => Ty::from_hir_path_inner(db, resolver, path, it.into()), - TypeNs::TypeAlias(it) => Ty::from_hir_path_inner(db, resolver, path, it.into()), + TypeNs::Adt(it) => Ty::from_hir_path_inner(db, resolver, resolved_segment, it.into()), + TypeNs::BuiltinType(it) => { + Ty::from_hir_path_inner(db, resolver, resolved_segment, it.into()) + } + TypeNs::TypeAlias(it) => { + Ty::from_hir_path_inner(db, resolver, resolved_segment, it.into()) + } // FIXME: report error TypeNs::EnumVariant(_) => return Ty::Unknown, }; - if let Some(remaining_index) = remaining_index { + if remaining_segments.len() == 1 { // resolve unselected assoc types - if remaining_index == path.segments.len() - 1 { - let segment = &path.segments[remaining_index]; - Ty::select_associated_type(db, resolver, ty, segment) - } else { - // FIXME report error (ambiguous associated type) - Ty::Unknown - } + 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_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty { + // Resolve the path (in type namespace) + let (resolution, remaining_index) = match resolver.resolve_path_in_type_ns(db, path) { + Some(it) => it, + None => return Ty::Unknown, + }; + let (resolved_segment, remaining_segments) = match remaining_index { + None => ( + path.segments.last().expect("resolved path has at least one element"), + &[] as &[PathSegment], + ), + Some(i) => (&path.segments[i - 1], &path.segments[i..]), + }; + Ty::from_partly_resolved_hir_path( + db, + resolver, + resolution, + resolved_segment, + remaining_segments, + ) + } + fn select_associated_type( db: &impl HirDatabase, resolver: &Resolver, @@ -190,11 +203,11 @@ impl Ty { fn from_hir_path_inner( db: &impl HirDatabase, resolver: &Resolver, - path: &Path, + segment: &PathSegment, typable: TypableDef, ) -> Ty { let ty = db.type_for_def(typable, Namespace::Types); - let substs = Ty::substs_from_path(db, resolver, path, typable); + let substs = Ty::substs_from_path_segment(db, resolver, segment, typable); ty.subst(&substs) } -- cgit v1.2.3