diff options
author | Florian Diebold <[email protected]> | 2019-03-26 22:07:26 +0000 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-04-14 10:28:53 +0100 |
commit | 413c87f155ab6b389b1cc122b5739716acccb476 (patch) | |
tree | ece00ee4bb46d32ec2a3c4124a43e3634eacd007 /crates/ra_hir/src/ty | |
parent | 23b876bc3b00c53ce24b8a99b4f4bf190fc6300e (diff) |
Get substs for trait refs in impl blocks
Diffstat (limited to 'crates/ra_hir/src/ty')
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 95 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 6 |
2 files changed, 74 insertions, 27 deletions
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 003a89f0d..4523b3954 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -17,9 +17,9 @@ use crate::{ | |||
17 | resolve::{Resolver, Resolution}, | 17 | resolve::{Resolver, Resolution}, |
18 | path::{ PathSegment, GenericArg}, | 18 | path::{ PathSegment, GenericArg}, |
19 | generics::GenericParams, | 19 | generics::GenericParams, |
20 | adt::VariantDef, | 20 | adt::VariantDef, Trait |
21 | }; | 21 | }; |
22 | use super::{Ty, primitive, FnSig, Substs, TypeCtor}; | 22 | use super::{Ty, primitive, FnSig, Substs, TypeCtor, TraitRef}; |
23 | 23 | ||
24 | impl Ty { | 24 | impl Ty { |
25 | pub(crate) fn from_hir(db: &impl HirDatabase, resolver: &Resolver, type_ref: &TypeRef) -> Self { | 25 | pub(crate) fn from_hir(db: &impl HirDatabase, resolver: &Resolver, type_ref: &TypeRef) -> Self { |
@@ -115,7 +115,6 @@ impl Ty { | |||
115 | segment: &PathSegment, | 115 | segment: &PathSegment, |
116 | resolved: TypableDef, | 116 | resolved: TypableDef, |
117 | ) -> Substs { | 117 | ) -> Substs { |
118 | let mut substs = Vec::new(); | ||
119 | let def_generics = match resolved { | 118 | let def_generics = match resolved { |
120 | TypableDef::Function(func) => func.generic_params(db), | 119 | TypableDef::Function(func) => func.generic_params(db), |
121 | TypableDef::Struct(s) => s.generic_params(db), | 120 | TypableDef::Struct(s) => s.generic_params(db), |
@@ -124,28 +123,7 @@ impl Ty { | |||
124 | TypableDef::TypeAlias(t) => t.generic_params(db), | 123 | TypableDef::TypeAlias(t) => t.generic_params(db), |
125 | TypableDef::Const(_) | TypableDef::Static(_) => GenericParams::default().into(), | 124 | TypableDef::Const(_) | TypableDef::Static(_) => GenericParams::default().into(), |
126 | }; | 125 | }; |
127 | let parent_param_count = def_generics.count_parent_params(); | 126 | substs_from_path_segment(db, resolver, segment, &def_generics, false) |
128 | substs.extend((0..parent_param_count).map(|_| Ty::Unknown)); | ||
129 | if let Some(generic_args) = &segment.args_and_bindings { | ||
130 | // if args are provided, it should be all of them, but we can't rely on that | ||
131 | let param_count = def_generics.params.len(); | ||
132 | for arg in generic_args.args.iter().take(param_count) { | ||
133 | match arg { | ||
134 | GenericArg::Type(type_ref) => { | ||
135 | let ty = Ty::from_hir(db, resolver, type_ref); | ||
136 | substs.push(ty); | ||
137 | } | ||
138 | } | ||
139 | } | ||
140 | } | ||
141 | // add placeholders for args that were not provided | ||
142 | // FIXME: handle defaults | ||
143 | let supplied_params = substs.len(); | ||
144 | for _ in supplied_params..def_generics.count_params_including_parent() { | ||
145 | substs.push(Ty::Unknown); | ||
146 | } | ||
147 | assert_eq!(substs.len(), def_generics.count_params_including_parent()); | ||
148 | Substs(substs.into()) | ||
149 | } | 127 | } |
150 | 128 | ||
151 | /// Collect generic arguments from a path into a `Substs`. See also | 129 | /// Collect generic arguments from a path into a `Substs`. See also |
@@ -185,6 +163,73 @@ impl Ty { | |||
185 | } | 163 | } |
186 | } | 164 | } |
187 | 165 | ||
166 | pub(super) fn substs_from_path_segment( | ||
167 | db: &impl HirDatabase, | ||
168 | resolver: &Resolver, | ||
169 | segment: &PathSegment, | ||
170 | def_generics: &GenericParams, | ||
171 | add_self_param: bool, | ||
172 | ) -> Substs { | ||
173 | let mut substs = Vec::new(); | ||
174 | let parent_param_count = def_generics.count_parent_params(); | ||
175 | substs.extend((0..parent_param_count).map(|_| Ty::Unknown)); | ||
176 | if add_self_param { | ||
177 | // FIXME this add_self_param argument is kind of a hack: Traits have the | ||
178 | // Self type as an implicit first type parameter, but it can't be | ||
179 | // actually provided in the type arguments | ||
180 | substs.push(Ty::Unknown); | ||
181 | } | ||
182 | if let Some(generic_args) = &segment.args_and_bindings { | ||
183 | // if args are provided, it should be all of them, but we can't rely on that | ||
184 | let param_count = def_generics.params.len(); | ||
185 | for arg in generic_args.args.iter().take(param_count) { | ||
186 | match arg { | ||
187 | GenericArg::Type(type_ref) => { | ||
188 | let ty = Ty::from_hir(db, resolver, type_ref); | ||
189 | substs.push(ty); | ||
190 | } | ||
191 | } | ||
192 | } | ||
193 | } | ||
194 | // add placeholders for args that were not provided | ||
195 | // FIXME: handle defaults | ||
196 | let supplied_params = substs.len(); | ||
197 | for _ in supplied_params..def_generics.count_params_including_parent() { | ||
198 | substs.push(Ty::Unknown); | ||
199 | } | ||
200 | assert_eq!(substs.len(), def_generics.count_params_including_parent()); | ||
201 | Substs(substs.into()) | ||
202 | } | ||
203 | |||
204 | impl TraitRef { | ||
205 | pub(crate) fn from_hir( | ||
206 | db: &impl HirDatabase, | ||
207 | resolver: &Resolver, | ||
208 | type_ref: &TypeRef, | ||
209 | ) -> Option<Self> { | ||
210 | let path = match type_ref { | ||
211 | TypeRef::Path(path) => path, | ||
212 | _ => return None, | ||
213 | }; | ||
214 | let resolved = match resolver.resolve_path(db, &path).take_types()? { | ||
215 | Resolution::Def(ModuleDef::Trait(tr)) => tr, | ||
216 | _ => return None, | ||
217 | }; | ||
218 | let substs = Self::substs_from_path(db, resolver, path, resolved); | ||
219 | Some(TraitRef { trait_: resolved, substs }) | ||
220 | } | ||
221 | |||
222 | fn substs_from_path( | ||
223 | db: &impl HirDatabase, | ||
224 | resolver: &Resolver, | ||
225 | path: &Path, | ||
226 | resolved: Trait, | ||
227 | ) -> Substs { | ||
228 | let segment = path.segments.last().expect("path should have at least one segment"); | ||
229 | substs_from_path_segment(db, resolver, segment, &resolved.generic_params(db), true) | ||
230 | } | ||
231 | } | ||
232 | |||
188 | /// Build the declared type of an item. This depends on the namespace; e.g. for | 233 | /// Build the declared type of an item. This depends on the namespace; e.g. for |
189 | /// `struct Foo(usize)`, we have two types: The type of the struct itself, and | 234 | /// `struct Foo(usize)`, we have two types: The type of the struct itself, and |
190 | /// the constructor function `(usize) -> Foo` which lives in the values | 235 | /// the constructor function `(usize) -> Foo` which lives in the values |
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index bb23246a6..aac7d6384 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -72,9 +72,9 @@ impl CrateImplBlocks { | |||
72 | 72 | ||
73 | let target_ty = impl_block.target_ty(db); | 73 | let target_ty = impl_block.target_ty(db); |
74 | 74 | ||
75 | if let Some(tr) = impl_block.target_trait(db) { | 75 | if let Some(tr) = impl_block.target_trait_ref(db) { |
76 | self.impls_by_trait | 76 | self.impls_by_trait |
77 | .entry(tr) | 77 | .entry(tr.trait_) |
78 | .or_insert_with(Vec::new) | 78 | .or_insert_with(Vec::new) |
79 | .push((module.module_id, impl_id)); | 79 | .push((module.module_id, impl_id)); |
80 | } else { | 80 | } else { |
@@ -185,6 +185,8 @@ impl Ty { | |||
185 | // well (in fact, the 'implements' condition could just be considered a | 185 | // well (in fact, the 'implements' condition could just be considered a |
186 | // 'where Self: Trait' clause) | 186 | // 'where Self: Trait' clause) |
187 | candidates.retain(|(t, _m)| { | 187 | candidates.retain(|(t, _m)| { |
188 | // FIXME construct substs of the correct length for the trait | ||
189 | // - check in rustc whether it does anything smarter than putting variables for everything | ||
188 | let trait_ref = TraitRef { trait_: *t, substs: Substs::single(self.clone()) }; | 190 | let trait_ref = TraitRef { trait_: *t, substs: Substs::single(self.clone()) }; |
189 | db.implements(trait_ref) | 191 | db.implements(trait_ref) |
190 | }); | 192 | }); |