mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-15 01:17:27 +00:00
Resolve trait associated items
E.g. `Default::default` or `<Foo as Default>::default`.
This commit is contained in:
parent
5704485063
commit
c35ef5013c
5 changed files with 78 additions and 19 deletions
|
@ -1055,3 +1055,13 @@ pub enum AssocItem {
|
|||
// require not implementing From, and instead having some checked way of
|
||||
// casting them, and somehow making the constructors private, which would be annoying.
|
||||
impl_froms!(AssocItem: Function, Const, TypeAlias);
|
||||
|
||||
impl From<AssocItem> for crate::generics::GenericDef {
|
||||
fn from(item: AssocItem) -> Self {
|
||||
match item {
|
||||
AssocItem::Function(f) => f.into(),
|
||||
AssocItem::Const(c) => c.into(),
|
||||
AssocItem::TypeAlias(t) => t.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,8 +12,8 @@ use crate::{
|
|||
name::SELF_TYPE,
|
||||
path::Path,
|
||||
type_ref::{TypeBound, TypeRef},
|
||||
Adt, AsName, Container, Enum, EnumVariant, Function, HasSource, ImplBlock, Name, Struct, Trait,
|
||||
TypeAlias, Union,
|
||||
Adt, AsName, Const, Container, Enum, EnumVariant, Function, HasSource, ImplBlock, Name, Struct,
|
||||
Trait, TypeAlias, Union,
|
||||
};
|
||||
|
||||
/// Data about a generic parameter (to a function, struct, impl, ...).
|
||||
|
@ -44,7 +44,6 @@ pub struct WherePredicate {
|
|||
pub(crate) bound: TypeBound,
|
||||
}
|
||||
|
||||
// FIXME: consts can have type parameters from their parents (i.e. associated consts of traits)
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||
pub enum GenericDef {
|
||||
Function(Function),
|
||||
|
@ -55,6 +54,8 @@ pub enum GenericDef {
|
|||
// enum variants cannot have generics themselves, but their parent enums
|
||||
// can, and this makes some code easier to write
|
||||
EnumVariant(EnumVariant),
|
||||
// consts can have type parameters from their parents (i.e. associated consts of traits)
|
||||
Const(Const),
|
||||
}
|
||||
impl_froms!(
|
||||
GenericDef: Function,
|
||||
|
@ -62,7 +63,8 @@ impl_froms!(
|
|||
Trait,
|
||||
TypeAlias,
|
||||
ImplBlock,
|
||||
EnumVariant
|
||||
EnumVariant,
|
||||
Const
|
||||
);
|
||||
|
||||
impl GenericParams {
|
||||
|
@ -75,7 +77,7 @@ impl GenericParams {
|
|||
GenericDef::TypeAlias(it) => it.container(db).map(GenericDef::from),
|
||||
GenericDef::EnumVariant(it) => Some(it.parent_enum(db).into()),
|
||||
GenericDef::Adt(_) | GenericDef::Trait(_) => None,
|
||||
GenericDef::ImplBlock(_) => None,
|
||||
GenericDef::ImplBlock(_) | GenericDef::Const(_) => None,
|
||||
};
|
||||
let mut generics = GenericParams {
|
||||
def,
|
||||
|
@ -104,7 +106,7 @@ impl GenericParams {
|
|||
// type-parameter, but rather is a type-alias for impl's target
|
||||
// type, so this is handled by the resolver.
|
||||
GenericDef::ImplBlock(it) => generics.fill(&it.source(db).ast, start),
|
||||
GenericDef::EnumVariant(_) => {}
|
||||
GenericDef::EnumVariant(_) | GenericDef::Const(_) => {}
|
||||
}
|
||||
|
||||
Arc::new(generics)
|
||||
|
@ -198,6 +200,7 @@ impl GenericDef {
|
|||
GenericDef::TypeAlias(inner) => inner.resolver(db),
|
||||
GenericDef::ImplBlock(inner) => inner.resolver(db),
|
||||
GenericDef::EnumVariant(inner) => inner.parent_enum(db).resolver(db),
|
||||
GenericDef::Const(inner) => inner.resolver(db),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! Path expression resolution.
|
||||
|
||||
use super::{ExprOrPatId, InferenceContext};
|
||||
use super::{ExprOrPatId, InferenceContext, TraitRef};
|
||||
use crate::{
|
||||
db::HirDatabase,
|
||||
resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs},
|
||||
|
@ -91,9 +91,17 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
let is_before_last = remaining_segments.len() == 1;
|
||||
|
||||
match (def, is_before_last) {
|
||||
(TypeNs::Trait(_trait), true) => {
|
||||
// FIXME Associated item of trait, e.g. `Default::default`
|
||||
None
|
||||
(TypeNs::Trait(trait_), true) => {
|
||||
let segment =
|
||||
remaining_segments.last().expect("there should be at least one segment here");
|
||||
let trait_ref = TraitRef::from_resolved_path(
|
||||
self.db,
|
||||
&self.resolver,
|
||||
trait_,
|
||||
resolved_segment,
|
||||
None,
|
||||
);
|
||||
self.resolve_trait_assoc_item(trait_ref, segment, id)
|
||||
}
|
||||
(def, _) => {
|
||||
// Either we already have a type (e.g. `Vec::new`), or we have a
|
||||
|
@ -120,6 +128,45 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
}
|
||||
}
|
||||
|
||||
fn resolve_trait_assoc_item(
|
||||
&mut self,
|
||||
trait_ref: TraitRef,
|
||||
segment: &crate::path::PathSegment,
|
||||
id: ExprOrPatId,
|
||||
) -> Option<(ValueNs, Option<Substs>)> {
|
||||
let trait_ = trait_ref.trait_;
|
||||
let item = trait_.items(self.db).iter().copied().find_map(|item| match item {
|
||||
AssocItem::Function(func) => {
|
||||
if segment.name == func.name(self.db) {
|
||||
Some(AssocItem::Function(func))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
AssocItem::Const(konst) => {
|
||||
if konst.name(self.db).map_or(false, |n| n == segment.name) {
|
||||
Some(AssocItem::Const(konst))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
AssocItem::TypeAlias(_) => None,
|
||||
})?;
|
||||
let def = match item {
|
||||
AssocItem::Function(f) => ValueNs::Function(f),
|
||||
AssocItem::Const(c) => ValueNs::Const(c),
|
||||
AssocItem::TypeAlias(_) => unreachable!(),
|
||||
};
|
||||
let generics = item.generic_params(self.db);
|
||||
let mut substs = Vec::with_capacity(generics.count_params_including_parent());
|
||||
substs.extend(trait_ref.substs.iter().cloned());
|
||||
substs.extend(std::iter::repeat(Ty::Unknown).take(generics.params.len()));
|
||||
|
||||
self.write_assoc_resolution(id, item);
|
||||
Some((def, Some(substs.into())))
|
||||
}
|
||||
|
||||
fn resolve_ty_assoc_item(
|
||||
&mut self,
|
||||
ty: Ty,
|
||||
|
|
|
@ -386,7 +386,7 @@ impl TraitRef {
|
|||
Some(TraitRef::from_resolved_path(db, resolver, resolved, segment, explicit_self_ty))
|
||||
}
|
||||
|
||||
fn from_resolved_path(
|
||||
pub(super) fn from_resolved_path(
|
||||
db: &impl HirDatabase,
|
||||
resolver: &Resolver,
|
||||
resolved: Trait,
|
||||
|
|
|
@ -2535,17 +2535,16 @@ fn test() {
|
|||
}
|
||||
"#),
|
||||
@r###"
|
||||
|
||||
[87; 193) '{ ...t(); }': ()
|
||||
[97; 99) 's1': S
|
||||
[105; 121) 'Defaul...efault': {unknown}
|
||||
[105; 121) 'Defaul...efault': fn default<S>() -> Self
|
||||
[105; 123) 'Defaul...ault()': S
|
||||
[133; 135) 's2': {unknown}
|
||||
[138; 148) 'S::default': {unknown}
|
||||
[138; 150) 'S::default()': {unknown}
|
||||
[160; 162) 's3': {unknown}
|
||||
[165; 188) '<S as ...efault': {unknown}
|
||||
[165; 190) '<S as ...ault()': {unknown}
|
||||
[160; 162) 's3': S
|
||||
[165; 188) '<S as ...efault': fn default<S>() -> Self
|
||||
[165; 190) '<S as ...ault()': S
|
||||
"###
|
||||
);
|
||||
}
|
||||
|
@ -2674,9 +2673,9 @@ fn test() {
|
|||
[148; 149) 'y': u64
|
||||
[157; 158) 'S': S
|
||||
[157; 165) 'S.into()': u64
|
||||
[175; 176) 'z': {unknown}
|
||||
[179; 196) 'Into::...::into': {unknown}
|
||||
[179; 199) 'Into::...nto(S)': {unknown}
|
||||
[175; 176) 'z': u64
|
||||
[179; 196) 'Into::...::into': fn into<S, u64>(Self) -> T
|
||||
[179; 199) 'Into::...nto(S)': u64
|
||||
[197; 198) 'S': S
|
||||
"###
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue