From c35ef5013c3223986ae5111a3720ef8e85c80efc Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Wed, 25 Sep 2019 21:41:17 +0200 Subject: Resolve trait associated items E.g. `Default::default` or `::default`. --- crates/ra_hir/src/code_model.rs | 10 +++++++ crates/ra_hir/src/generics.rs | 15 ++++++----- crates/ra_hir/src/ty/infer/path.rs | 55 +++++++++++++++++++++++++++++++++++--- crates/ra_hir/src/ty/lower.rs | 2 +- crates/ra_hir/src/ty/tests.rs | 15 +++++------ 5 files changed, 78 insertions(+), 19 deletions(-) (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 9fecba63d..20413cb3d 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -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 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(), + } + } +} diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs index ccb777492..6865d34ba 100644 --- a/crates/ra_hir/src/generics.rs +++ b/crates/ra_hir/src/generics.rs @@ -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), } } } diff --git a/crates/ra_hir/src/ty/infer/path.rs b/crates/ra_hir/src/ty/infer/path.rs index 54aae4f0c..feb7481b2 100644 --- a/crates/ra_hir/src/ty/infer/path.rs +++ b/crates/ra_hir/src/ty/infer/path.rs @@ -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)> { + 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, diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 8d71abc95..dd503d771 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs @@ -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, diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 2872cd27b..f4f63ca93 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -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() -> 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) '() -> Self + [165; 190) '(Self) -> T + [179; 199) 'Into::...nto(S)': u64 [197; 198) 'S': S "### ); -- cgit v1.2.3