diff options
author | Florian Diebold <[email protected]> | 2019-10-31 18:28:33 +0000 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-11-01 18:57:08 +0000 |
commit | 1173c3dab5f77a1afd367d547790dd82c558fe0d (patch) | |
tree | 50d39c98ad4ac7deae11800d20c0a5dbeb9ed8bc /crates/ra_hir/src/ty/infer | |
parent | c7cedea270c492e9a2c8b81c1312fda44fd8217e (diff) |
Refactor to unify with method resolution
Diffstat (limited to 'crates/ra_hir/src/ty/infer')
-rw-r--r-- | crates/ra_hir/src/ty/infer/path.rs | 135 |
1 files changed, 27 insertions, 108 deletions
diff --git a/crates/ra_hir/src/ty/infer/path.rs b/crates/ra_hir/src/ty/infer/path.rs index c58564b22..1946bf608 100644 --- a/crates/ra_hir/src/ty/infer/path.rs +++ b/crates/ra_hir/src/ty/infer/path.rs | |||
@@ -6,11 +6,9 @@ use super::{ExprOrPatId, InferenceContext, TraitRef}; | |||
6 | use crate::{ | 6 | use crate::{ |
7 | db::HirDatabase, | 7 | db::HirDatabase, |
8 | resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs}, | 8 | resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs}, |
9 | ty::{lower, traits::TraitEnvironment, Canonical}, | 9 | ty::{method_resolution, Substs, Ty, TypableDef, TypeWalk}, |
10 | ty::{Substs, Ty, TypableDef, TypeWalk}, | 10 | AssocItem, Container, HasGenericParams, Name, Namespace, Path, |
11 | AssocItem, HasGenericParams, Name, Namespace, Path, Trait, | ||
12 | }; | 11 | }; |
13 | use std::sync::Arc; | ||
14 | 12 | ||
15 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | 13 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { |
16 | pub(super) fn infer_path( | 14 | pub(super) fn infer_path( |
@@ -184,91 +182,34 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
184 | return None; | 182 | return None; |
185 | } | 183 | } |
186 | 184 | ||
187 | self.find_inherent_assoc_candidate(ty.clone(), name, id) | ||
188 | .or_else(|| self.find_trait_assoc_candidate(ty.clone(), name, id)) | ||
189 | } | ||
190 | |||
191 | fn find_inherent_assoc_candidate( | ||
192 | &mut self, | ||
193 | ty: Ty, | ||
194 | name: &Name, | ||
195 | id: ExprOrPatId, | ||
196 | ) -> Option<(ValueNs, Option<Substs>)> { | ||
197 | let krate = self.resolver.krate()?; | ||
198 | |||
199 | // Find impl | ||
200 | let item = ty.clone().iterate_impl_items(self.db, krate, |item| match item { | ||
201 | AssocItem::Function(func) => { | ||
202 | if *name == func.name(self.db) { | ||
203 | Some(AssocItem::Function(func)) | ||
204 | } else { | ||
205 | None | ||
206 | } | ||
207 | } | ||
208 | |||
209 | AssocItem::Const(konst) => { | ||
210 | if konst.name(self.db).map_or(false, |n| n == *name) { | ||
211 | Some(AssocItem::Const(konst)) | ||
212 | } else { | ||
213 | None | ||
214 | } | ||
215 | } | ||
216 | AssocItem::TypeAlias(_) => None, | ||
217 | })?; | ||
218 | let def = match item { | ||
219 | AssocItem::Function(f) => ValueNs::Function(f), | ||
220 | AssocItem::Const(c) => ValueNs::Const(c), | ||
221 | AssocItem::TypeAlias(_) => unreachable!(), | ||
222 | }; | ||
223 | let substs = self.find_self_types(&def, ty); | ||
224 | |||
225 | self.write_assoc_resolution(id, item); | ||
226 | Some((def, substs)) | ||
227 | } | ||
228 | |||
229 | fn find_trait_assoc_candidate( | ||
230 | &mut self, | ||
231 | ty: Ty, | ||
232 | name: &Name, | ||
233 | id: ExprOrPatId, | ||
234 | ) -> Option<(ValueNs, Option<Substs>)> { | ||
235 | let krate = self.resolver.krate()?; | ||
236 | |||
237 | let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone()); | 185 | let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone()); |
238 | 186 | ||
239 | let env = lower::trait_env(self.db, &self.resolver); | 187 | method_resolution::iterate_method_candidates( |
240 | // if we have `T: Trait` in the param env, the trait doesn't need to be in scope | 188 | &canonical_ty.value, |
241 | let traits_from_env = env | 189 | self.db, |
242 | .trait_predicates_for_self_ty(&ty) | 190 | &self.resolver.clone(), |
243 | .map(|tr| tr.trait_) | 191 | Some(name), |
244 | .flat_map(|t| t.all_super_traits(self.db)); | 192 | method_resolution::LookupMode::Path, |
245 | let traits = traits_from_env.chain(self.resolver.traits_in_scope(self.db)); | 193 | move |_ty, item| { |
246 | 194 | let def = match item { | |
247 | 'traits: for t in traits { | 195 | AssocItem::Function(f) => ValueNs::Function(f), |
248 | let data = t.trait_data(self.db); | 196 | AssocItem::Const(c) => ValueNs::Const(c), |
249 | let mut known_implemented = false; | 197 | AssocItem::TypeAlias(_) => unreachable!(), |
250 | for item in data.items() { | 198 | }; |
251 | if let AssocItem::Function(f) = *item { | 199 | match item.container(self.db) { |
252 | if f.name(self.db) == *name { | 200 | Container::ImplBlock(_) => { |
253 | if !known_implemented { | 201 | let substs = self.find_self_types(&def, ty.clone()); |
254 | let goal = generic_implements_goal( | 202 | |
255 | self.db, | 203 | self.write_assoc_resolution(id, item); |
256 | env.clone(), | 204 | Some((def, substs)) |
257 | t, | 205 | } |
258 | canonical_ty.value.clone(), | 206 | Container::Trait(t) => { |
259 | ); | ||
260 | if self.db.trait_solve(krate, goal).is_none() { | ||
261 | continue 'traits; | ||
262 | } | ||
263 | } | ||
264 | known_implemented = true; | ||
265 | |||
266 | // we're picking this method | 207 | // we're picking this method |
267 | let trait_substs = Substs::build_for_def(self.db, t) | 208 | let trait_substs = Substs::build_for_def(self.db, t) |
268 | .push(ty.clone()) | 209 | .push(ty.clone()) |
269 | .fill(std::iter::repeat_with(|| self.new_type_var())) | 210 | .fill(std::iter::repeat_with(|| self.new_type_var())) |
270 | .build(); | 211 | .build(); |
271 | let substs = Substs::build_for_def(self.db, f) | 212 | let substs = Substs::build_for_def(self.db, item) |
272 | .use_parent_substs(&trait_substs) | 213 | .use_parent_substs(&trait_substs) |
273 | .fill_with_params() | 214 | .fill_with_params() |
274 | .build(); | 215 | .build(); |
@@ -277,14 +218,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
277 | substs: trait_substs, | 218 | substs: trait_substs, |
278 | })); | 219 | })); |
279 | 220 | ||
280 | self.write_assoc_resolution(id, *item); | 221 | self.write_assoc_resolution(id, item); |
281 | return Some((ValueNs::Function(f), Some(substs))); | 222 | Some((def, Some(substs))) |
282 | } | 223 | } |
283 | } | 224 | } |
284 | } | 225 | }, |
285 | } | 226 | ) |
286 | |||
287 | None | ||
288 | } | 227 | } |
289 | 228 | ||
290 | fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> { | 229 | fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> { |
@@ -317,23 +256,3 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
317 | } | 256 | } |
318 | } | 257 | } |
319 | } | 258 | } |
320 | |||
321 | // TODO remove duplication | ||
322 | /// This creates Substs for a trait with the given Self type and type variables | ||
323 | /// for all other parameters, to query Chalk with it. | ||
324 | fn generic_implements_goal( | ||
325 | db: &impl HirDatabase, | ||
326 | env: Arc<TraitEnvironment>, | ||
327 | trait_: Trait, | ||
328 | self_ty: Canonical<Ty>, | ||
329 | ) -> Canonical<super::InEnvironment<super::Obligation>> { | ||
330 | let num_vars = self_ty.num_vars; | ||
331 | let substs = super::Substs::build_for_def(db, trait_) | ||
332 | .push(self_ty.value) | ||
333 | .fill_with_bound_vars(num_vars as u32) | ||
334 | .build(); | ||
335 | let num_vars = substs.len() - 1 + self_ty.num_vars; | ||
336 | let trait_ref = TraitRef { trait_, substs }; | ||
337 | let obligation = super::Obligation::Trait(trait_ref); | ||
338 | Canonical { num_vars, value: super::InEnvironment::new(env, obligation) } | ||
339 | } | ||