diff options
author | Florian Diebold <[email protected]> | 2019-09-25 20:41:17 +0100 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-09-25 20:41:17 +0100 |
commit | c35ef5013c3223986ae5111a3720ef8e85c80efc (patch) | |
tree | 807f32992732a74c591f6a8c85aff354ebea09c6 | |
parent | 5704485063bad82e651c8e68f4fa2d333bfdf152 (diff) |
Resolve trait associated items
E.g. `Default::default` or `<Foo as Default>::default`.
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 10 | ||||
-rw-r--r-- | crates/ra_hir/src/generics.rs | 15 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer/path.rs | 55 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 15 |
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. |
1057 | impl_froms!(AssocItem: Function, Const, TypeAlias); | 1057 | impl_froms!(AssocItem: Function, Const, TypeAlias); |
1058 | |||
1059 | impl 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)] |
49 | pub enum GenericDef { | 48 | pub 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 | } |
59 | impl_froms!( | 60 | impl_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 | ||
68 | impl GenericParams { | 70 | impl 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 | ||
3 | use super::{ExprOrPatId, InferenceContext}; | 3 | use super::{ExprOrPatId, InferenceContext, TraitRef}; |
4 | use crate::{ | 4 | use 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 | ); |