aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-09-25 20:41:17 +0100
committerFlorian Diebold <[email protected]>2019-09-25 20:41:17 +0100
commitc35ef5013c3223986ae5111a3720ef8e85c80efc (patch)
tree807f32992732a74c591f6a8c85aff354ebea09c6 /crates/ra_hir
parent5704485063bad82e651c8e68f4fa2d333bfdf152 (diff)
Resolve trait associated items
E.g. `Default::default` or `<Foo as Default>::default`.
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/src/code_model.rs10
-rw-r--r--crates/ra_hir/src/generics.rs15
-rw-r--r--crates/ra_hir/src/ty/infer/path.rs55
-rw-r--r--crates/ra_hir/src/ty/lower.rs2
-rw-r--r--crates/ra_hir/src/ty/tests.rs15
5 files changed, 78 insertions, 19 deletions
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 {
1055// require not implementing From, and instead having some checked way of 1055// require not implementing From, and instead having some checked way of
1056// casting them, and somehow making the constructors private, which would be annoying. 1056// casting them, and somehow making the constructors private, which would be annoying.
1057impl_froms!(AssocItem: Function, Const, TypeAlias); 1057impl_froms!(AssocItem: Function, Const, TypeAlias);
1058
1059impl From<AssocItem> for crate::generics::GenericDef {
1060 fn from(item: AssocItem) -> Self {
1061 match item {
1062 AssocItem::Function(f) => f.into(),
1063 AssocItem::Const(c) => c.into(),
1064 AssocItem::TypeAlias(t) => t.into(),
1065 }
1066 }
1067}
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::{
12 name::SELF_TYPE, 12 name::SELF_TYPE,
13 path::Path, 13 path::Path,
14 type_ref::{TypeBound, TypeRef}, 14 type_ref::{TypeBound, TypeRef},
15 Adt, AsName, Container, Enum, EnumVariant, Function, HasSource, ImplBlock, Name, Struct, Trait, 15 Adt, AsName, Const, Container, Enum, EnumVariant, Function, HasSource, ImplBlock, Name, Struct,
16 TypeAlias, Union, 16 Trait, TypeAlias, Union,
17}; 17};
18 18
19/// Data about a generic parameter (to a function, struct, impl, ...). 19/// Data about a generic parameter (to a function, struct, impl, ...).
@@ -44,7 +44,6 @@ pub struct WherePredicate {
44 pub(crate) bound: TypeBound, 44 pub(crate) bound: TypeBound,
45} 45}
46 46
47// FIXME: consts can have type parameters from their parents (i.e. associated consts of traits)
48#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] 47#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
49pub enum GenericDef { 48pub enum GenericDef {
50 Function(Function), 49 Function(Function),
@@ -55,6 +54,8 @@ pub enum GenericDef {
55 // enum variants cannot have generics themselves, but their parent enums 54 // enum variants cannot have generics themselves, but their parent enums
56 // can, and this makes some code easier to write 55 // can, and this makes some code easier to write
57 EnumVariant(EnumVariant), 56 EnumVariant(EnumVariant),
57 // consts can have type parameters from their parents (i.e. associated consts of traits)
58 Const(Const),
58} 59}
59impl_froms!( 60impl_froms!(
60 GenericDef: Function, 61 GenericDef: Function,
@@ -62,7 +63,8 @@ impl_froms!(
62 Trait, 63 Trait,
63 TypeAlias, 64 TypeAlias,
64 ImplBlock, 65 ImplBlock,
65 EnumVariant 66 EnumVariant,
67 Const
66); 68);
67 69
68impl GenericParams { 70impl GenericParams {
@@ -75,7 +77,7 @@ impl GenericParams {
75 GenericDef::TypeAlias(it) => it.container(db).map(GenericDef::from), 77 GenericDef::TypeAlias(it) => it.container(db).map(GenericDef::from),
76 GenericDef::EnumVariant(it) => Some(it.parent_enum(db).into()), 78 GenericDef::EnumVariant(it) => Some(it.parent_enum(db).into()),
77 GenericDef::Adt(_) | GenericDef::Trait(_) => None, 79 GenericDef::Adt(_) | GenericDef::Trait(_) => None,
78 GenericDef::ImplBlock(_) => None, 80 GenericDef::ImplBlock(_) | GenericDef::Const(_) => None,
79 }; 81 };
80 let mut generics = GenericParams { 82 let mut generics = GenericParams {
81 def, 83 def,
@@ -104,7 +106,7 @@ impl GenericParams {
104 // type-parameter, but rather is a type-alias for impl's target 106 // type-parameter, but rather is a type-alias for impl's target
105 // type, so this is handled by the resolver. 107 // type, so this is handled by the resolver.
106 GenericDef::ImplBlock(it) => generics.fill(&it.source(db).ast, start), 108 GenericDef::ImplBlock(it) => generics.fill(&it.source(db).ast, start),
107 GenericDef::EnumVariant(_) => {} 109 GenericDef::EnumVariant(_) | GenericDef::Const(_) => {}
108 } 110 }
109 111
110 Arc::new(generics) 112 Arc::new(generics)
@@ -198,6 +200,7 @@ impl GenericDef {
198 GenericDef::TypeAlias(inner) => inner.resolver(db), 200 GenericDef::TypeAlias(inner) => inner.resolver(db),
199 GenericDef::ImplBlock(inner) => inner.resolver(db), 201 GenericDef::ImplBlock(inner) => inner.resolver(db),
200 GenericDef::EnumVariant(inner) => inner.parent_enum(db).resolver(db), 202 GenericDef::EnumVariant(inner) => inner.parent_enum(db).resolver(db),
203 GenericDef::Const(inner) => inner.resolver(db),
201 } 204 }
202 } 205 }
203} 206}
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 @@
1//! Path expression resolution. 1//! Path expression resolution.
2 2
3use super::{ExprOrPatId, InferenceContext}; 3use super::{ExprOrPatId, InferenceContext, TraitRef};
4use crate::{ 4use crate::{
5 db::HirDatabase, 5 db::HirDatabase,
6 resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs}, 6 resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs},
@@ -91,9 +91,17 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
91 let is_before_last = remaining_segments.len() == 1; 91 let is_before_last = remaining_segments.len() == 1;
92 92
93 match (def, is_before_last) { 93 match (def, is_before_last) {
94 (TypeNs::Trait(_trait), true) => { 94 (TypeNs::Trait(trait_), true) => {
95 // FIXME Associated item of trait, e.g. `Default::default` 95 let segment =
96 None 96 remaining_segments.last().expect("there should be at least one segment here");
97 let trait_ref = TraitRef::from_resolved_path(
98 self.db,
99 &self.resolver,
100 trait_,
101 resolved_segment,
102 None,
103 );
104 self.resolve_trait_assoc_item(trait_ref, segment, id)
97 } 105 }
98 (def, _) => { 106 (def, _) => {
99 // Either we already have a type (e.g. `Vec::new`), or we have a 107 // 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> {
120 } 128 }
121 } 129 }
122 130
131 fn resolve_trait_assoc_item(
132 &mut self,
133 trait_ref: TraitRef,
134 segment: &crate::path::PathSegment,
135 id: ExprOrPatId,
136 ) -> Option<(ValueNs, Option<Substs>)> {
137 let trait_ = trait_ref.trait_;
138 let item = trait_.items(self.db).iter().copied().find_map(|item| match item {
139 AssocItem::Function(func) => {
140 if segment.name == func.name(self.db) {
141 Some(AssocItem::Function(func))
142 } else {
143 None
144 }
145 }
146
147 AssocItem::Const(konst) => {
148 if konst.name(self.db).map_or(false, |n| n == segment.name) {
149 Some(AssocItem::Const(konst))
150 } else {
151 None
152 }
153 }
154 AssocItem::TypeAlias(_) => None,
155 })?;
156 let def = match item {
157 AssocItem::Function(f) => ValueNs::Function(f),
158 AssocItem::Const(c) => ValueNs::Const(c),
159 AssocItem::TypeAlias(_) => unreachable!(),
160 };
161 let generics = item.generic_params(self.db);
162 let mut substs = Vec::with_capacity(generics.count_params_including_parent());
163 substs.extend(trait_ref.substs.iter().cloned());
164 substs.extend(std::iter::repeat(Ty::Unknown).take(generics.params.len()));
165
166 self.write_assoc_resolution(id, item);
167 Some((def, Some(substs.into())))
168 }
169
123 fn resolve_ty_assoc_item( 170 fn resolve_ty_assoc_item(
124 &mut self, 171 &mut self,
125 ty: Ty, 172 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 {
386 Some(TraitRef::from_resolved_path(db, resolver, resolved, segment, explicit_self_ty)) 386 Some(TraitRef::from_resolved_path(db, resolver, resolved, segment, explicit_self_ty))
387 } 387 }
388 388
389 fn from_resolved_path( 389 pub(super) fn from_resolved_path(
390 db: &impl HirDatabase, 390 db: &impl HirDatabase,
391 resolver: &Resolver, 391 resolver: &Resolver,
392 resolved: Trait, 392 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() {
2535} 2535}
2536"#), 2536"#),
2537 @r###" 2537 @r###"
2538
2539 [87; 193) '{ ...t(); }': () 2538 [87; 193) '{ ...t(); }': ()
2540 [97; 99) 's1': S 2539 [97; 99) 's1': S
2541 [105; 121) 'Defaul...efault': {unknown} 2540 [105; 121) 'Defaul...efault': fn default<S>() -> Self
2542 [105; 123) 'Defaul...ault()': S 2541 [105; 123) 'Defaul...ault()': S
2543 [133; 135) 's2': {unknown} 2542 [133; 135) 's2': {unknown}
2544 [138; 148) 'S::default': {unknown} 2543 [138; 148) 'S::default': {unknown}
2545 [138; 150) 'S::default()': {unknown} 2544 [138; 150) 'S::default()': {unknown}
2546 [160; 162) 's3': {unknown} 2545 [160; 162) 's3': S
2547 [165; 188) '<S as ...efault': {unknown} 2546 [165; 188) '<S as ...efault': fn default<S>() -> Self
2548 [165; 190) '<S as ...ault()': {unknown} 2547 [165; 190) '<S as ...ault()': S
2549 "### 2548 "###
2550 ); 2549 );
2551} 2550}
@@ -2674,9 +2673,9 @@ fn test() {
2674 [148; 149) 'y': u64 2673 [148; 149) 'y': u64
2675 [157; 158) 'S': S 2674 [157; 158) 'S': S
2676 [157; 165) 'S.into()': u64 2675 [157; 165) 'S.into()': u64
2677 [175; 176) 'z': {unknown} 2676 [175; 176) 'z': u64
2678 [179; 196) 'Into::...::into': {unknown} 2677 [179; 196) 'Into::...::into': fn into<S, u64>(Self) -> T
2679 [179; 199) 'Into::...nto(S)': {unknown} 2678 [179; 199) 'Into::...nto(S)': u64
2680 [197; 198) 'S': S 2679 [197; 198) 'S': S
2681 "### 2680 "###
2682 ); 2681 );