mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 13:51:31 +00:00
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.
This commit is contained in:
parent
828d60574f
commit
406280e52f
2 changed files with 121 additions and 125 deletions
|
@ -48,7 +48,7 @@ use crate::{
|
||||||
resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs},
|
resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs},
|
||||||
ty::infer::diagnostics::InferenceDiagnostic,
|
ty::infer::diagnostics::InferenceDiagnostic,
|
||||||
type_ref::{Mutability, TypeRef},
|
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,
|
StructField,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -508,7 +508,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
|
|
||||||
fn resolve_assoc_item(
|
fn resolve_assoc_item(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut def_or_ty: Either<TypeNs, Ty>,
|
// mut def_or_ty: Either<TypeNs, Ty>,
|
||||||
|
def: TypeNs,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
remaining_index: usize,
|
remaining_index: usize,
|
||||||
id: ExprOrPatId,
|
id: ExprOrPatId,
|
||||||
|
@ -516,62 +517,40 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
assert!(remaining_index < path.segments.len());
|
assert!(remaining_index < path.segments.len());
|
||||||
let krate = self.resolver.krate()?;
|
let krate = self.resolver.krate()?;
|
||||||
|
|
||||||
let mut ty = Ty::Unknown;
|
// 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.
|
||||||
|
|
||||||
// resolve intermediate segments
|
let resolved_segment = &path.segments[remaining_index - 1];
|
||||||
for (i, segment) in path.segments[remaining_index..].iter().enumerate() {
|
let remaining_segments = &path.segments[remaining_index..];
|
||||||
let is_last_segment = i == path.segments[remaining_index..].len() - 1;
|
let is_before_last = remaining_segments.len() == 1;
|
||||||
ty = match def_or_ty {
|
|
||||||
Either::A(def) => {
|
let (def, substs) = match (def, is_before_last) {
|
||||||
let typable: TypableDef = match def {
|
(TypeNs::Trait(_trait), true) => {
|
||||||
TypeNs::Adt(it) => it.into(),
|
// Associated item of trait, e.g. `Default::default`
|
||||||
TypeNs::TypeAlias(it) => it.into(),
|
// FIXME
|
||||||
TypeNs::BuiltinType(it) => it.into(),
|
|
||||||
// FIXME associated item of traits, generics, and Self
|
|
||||||
TypeNs::Trait(_) | TypeNs::GenericParam(_) | TypeNs::SelfType(_) => {
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
// FIXME: report error here
|
(def, _) => {
|
||||||
TypeNs::EnumVariant(_) => return None,
|
// 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. `<T
|
||||||
let ty = self.db.type_for_def(typable, Namespace::Types);
|
// as Iterator>::Item::default`)
|
||||||
|
let remaining_segments_for_ty = &remaining_segments[..remaining_segments.len() - 1];
|
||||||
// For example, this substs will take `Gen::*<u32>*::make`
|
let ty = Ty::from_partly_resolved_hir_path(
|
||||||
assert!(remaining_index > 0);
|
|
||||||
let substs = Ty::substs_from_path_segment(
|
|
||||||
self.db,
|
self.db,
|
||||||
&self.resolver,
|
&self.resolver,
|
||||||
&path.segments[remaining_index + i - 1],
|
def,
|
||||||
typable,
|
resolved_segment,
|
||||||
|
remaining_segments_for_ty,
|
||||||
);
|
);
|
||||||
ty.subst(&substs)
|
if let Ty::Unknown = ty {
|
||||||
}
|
return None;
|
||||||
Either::B(ty) => ty,
|
|
||||||
};
|
|
||||||
if is_last_segment {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to find an impl_item for the type which has a name matching
|
let segment =
|
||||||
// the current segment
|
remaining_segments.last().expect("there should be at least one segment here");
|
||||||
log::debug!("looking for path segment: {:?}", segment);
|
// Find impl
|
||||||
|
|
||||||
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,
|
|
||||||
|
|
||||||
// FIXME: Resolve associated types
|
|
||||||
crate::ImplItem::TypeAlias(_) => {
|
|
||||||
// Some(Either::A(TypeNs::TypeAlias(..)))
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let segment = path.segments.last().unwrap();
|
|
||||||
let def = ty.clone().iterate_impl_items(self.db, krate, |item| match item {
|
let def = ty.clone().iterate_impl_items(self.db, krate, |item| match item {
|
||||||
crate::ImplItem::Method(func) => {
|
crate::ImplItem::Method(func) => {
|
||||||
if segment.name == func.name(self.db) {
|
if segment.name == func.name(self.db) {
|
||||||
|
@ -582,7 +561,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::ImplItem::Const(konst) => {
|
crate::ImplItem::Const(konst) => {
|
||||||
if konst.name(self.db).map_or(false, |n| n == segment.name) {
|
if segment.name == konst.name(self.db) {
|
||||||
Some(ValueNs::Const(konst))
|
Some(ValueNs::Const(konst))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -590,6 +569,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
}
|
}
|
||||||
crate::ImplItem::TypeAlias(_) => None,
|
crate::ImplItem::TypeAlias(_) => None,
|
||||||
})?;
|
})?;
|
||||||
|
let self_types = self.find_self_types(&def, ty);
|
||||||
|
(def, self_types)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
self.write_assoc_resolution(
|
self.write_assoc_resolution(
|
||||||
id,
|
id,
|
||||||
match def {
|
match def {
|
||||||
|
@ -598,8 +582,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
let self_types = self.find_self_types(&def, ty);
|
Some((def, substs))
|
||||||
Some((def, self_types))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> {
|
fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> {
|
||||||
|
|
|
@ -86,23 +86,19 @@ impl Ty {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty {
|
pub(crate) fn from_partly_resolved_hir_path(
|
||||||
// Resolve the path (in type namespace)
|
db: &impl HirDatabase,
|
||||||
let (resolution, remaining_index) = match resolver.resolve_path_in_type_ns(db, path) {
|
resolver: &Resolver,
|
||||||
Some(it) => it,
|
resolution: TypeNs,
|
||||||
None => return Ty::Unknown,
|
resolved_segment: &PathSegment,
|
||||||
};
|
remaining_segments: &[PathSegment],
|
||||||
|
) -> Ty {
|
||||||
let ty = match resolution {
|
let ty = match resolution {
|
||||||
TypeNs::Trait(trait_) => {
|
TypeNs::Trait(trait_) => {
|
||||||
let segment = match remaining_index {
|
let trait_ref =
|
||||||
None => path.segments.last().expect("resolved path has at least one element"),
|
TraitRef::from_resolved_path(db, resolver, trait_, resolved_segment, None);
|
||||||
Some(i) => &path.segments[i - 1],
|
return if remaining_segments.len() == 1 {
|
||||||
};
|
let segment = &remaining_segments[0];
|
||||||
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
|
match trait_ref
|
||||||
.trait_
|
.trait_
|
||||||
.associated_type_by_name_including_super_traits(db, &segment.name)
|
.associated_type_by_name_including_super_traits(db, &segment.name)
|
||||||
|
@ -119,48 +115,65 @@ impl Ty {
|
||||||
Ty::Unknown
|
Ty::Unknown
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else if remaining_segments.len() > 1 {
|
||||||
// FIXME report error (ambiguous associated type)
|
// FIXME report error (ambiguous associated type)
|
||||||
Ty::Unknown
|
Ty::Unknown
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Ty::Dyn(Arc::new([GenericPredicate::Implemented(trait_ref)]))
|
Ty::Dyn(Arc::new([GenericPredicate::Implemented(trait_ref)]))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
TypeNs::GenericParam(idx) => {
|
TypeNs::GenericParam(idx) => {
|
||||||
// FIXME: maybe return name in resolution?
|
// FIXME: maybe return name in resolution?
|
||||||
let name = match remaining_index {
|
let name = resolved_segment.name.clone();
|
||||||
None => path
|
|
||||||
.as_ident()
|
|
||||||
.expect("generic param should be single-segment path")
|
|
||||||
.clone(),
|
|
||||||
Some(idx) => path.segments[idx - 1].name.clone(),
|
|
||||||
};
|
|
||||||
Ty::Param { idx, name }
|
Ty::Param { idx, name }
|
||||||
}
|
}
|
||||||
TypeNs::SelfType(impl_block) => impl_block.target_ty(db),
|
TypeNs::SelfType(impl_block) => impl_block.target_ty(db),
|
||||||
|
|
||||||
TypeNs::Adt(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, path, it.into()),
|
TypeNs::BuiltinType(it) => {
|
||||||
TypeNs::TypeAlias(it) => Ty::from_hir_path_inner(db, resolver, path, it.into()),
|
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
|
// FIXME: report error
|
||||||
TypeNs::EnumVariant(_) => return Ty::Unknown,
|
TypeNs::EnumVariant(_) => return Ty::Unknown,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(remaining_index) = remaining_index {
|
if remaining_segments.len() == 1 {
|
||||||
// resolve unselected assoc types
|
// resolve unselected assoc types
|
||||||
if remaining_index == path.segments.len() - 1 {
|
let segment = &remaining_segments[0];
|
||||||
let segment = &path.segments[remaining_index];
|
|
||||||
Ty::select_associated_type(db, resolver, ty, segment)
|
Ty::select_associated_type(db, resolver, ty, segment)
|
||||||
} else {
|
} else if remaining_segments.len() > 1 {
|
||||||
// FIXME report error (ambiguous associated type)
|
// FIXME report error (ambiguous associated type)
|
||||||
Ty::Unknown
|
Ty::Unknown
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
ty
|
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(
|
fn select_associated_type(
|
||||||
db: &impl HirDatabase,
|
db: &impl HirDatabase,
|
||||||
resolver: &Resolver,
|
resolver: &Resolver,
|
||||||
|
@ -190,11 +203,11 @@ impl Ty {
|
||||||
fn from_hir_path_inner(
|
fn from_hir_path_inner(
|
||||||
db: &impl HirDatabase,
|
db: &impl HirDatabase,
|
||||||
resolver: &Resolver,
|
resolver: &Resolver,
|
||||||
path: &Path,
|
segment: &PathSegment,
|
||||||
typable: TypableDef,
|
typable: TypableDef,
|
||||||
) -> Ty {
|
) -> Ty {
|
||||||
let ty = db.type_for_def(typable, Namespace::Types);
|
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)
|
ty.subst(&substs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue