diff options
author | Florian Diebold <[email protected]> | 2019-12-02 17:12:49 +0000 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-12-02 18:33:13 +0000 |
commit | cfa50df33e1ebfa89f7fbdece7454699f858de92 (patch) | |
tree | f793df3b6eab65a110bf1cc22258eaad15f77df9 | |
parent | 456d52fdfa8525af2a54e76ee5300f0a40ef582a (diff) |
Refactor a bit
-rw-r--r-- | crates/ra_hir_ty/src/infer/path.rs | 38 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/method_resolution.rs | 98 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests.rs | 15 |
3 files changed, 74 insertions, 77 deletions
diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs index d0d7646a4..b0024c6e1 100644 --- a/crates/ra_hir_ty/src/infer/path.rs +++ b/crates/ra_hir_ty/src/infer/path.rs | |||
@@ -206,7 +206,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
206 | AssocItemId::TypeAliasId(_) => unreachable!(), | 206 | AssocItemId::TypeAliasId(_) => unreachable!(), |
207 | }; | 207 | }; |
208 | let substs = match container { | 208 | let substs = match container { |
209 | ContainerId::ImplId(_) => self.find_self_types(&def, ty.clone()), | 209 | ContainerId::ImplId(impl_id) => { |
210 | method_resolution::inherent_impl_substs(self.db, impl_id, &ty) | ||
211 | } | ||
210 | ContainerId::TraitId(trait_) => { | 212 | ContainerId::TraitId(trait_) => { |
211 | // we're picking this method | 213 | // we're picking this method |
212 | let trait_substs = Substs::build_for_def(self.db, trait_) | 214 | let trait_substs = Substs::build_for_def(self.db, trait_) |
@@ -231,38 +233,4 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
231 | }, | 233 | }, |
232 | ) | 234 | ) |
233 | } | 235 | } |
234 | |||
235 | fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> { | ||
236 | if let ValueNs::FunctionId(func) = *def { | ||
237 | // We only do the infer if parent has generic params | ||
238 | let gen = self.db.generic_params(func.into()); | ||
239 | if gen.count_parent_params() == 0 { | ||
240 | return None; | ||
241 | } | ||
242 | |||
243 | let impl_id = match func.lookup(self.db).container { | ||
244 | ContainerId::ImplId(it) => it, | ||
245 | _ => return None, | ||
246 | }; | ||
247 | let self_ty = self.db.impl_self_ty(impl_id).clone(); | ||
248 | let self_ty_substs = self_ty.substs()?; | ||
249 | let actual_substs = actual_def_ty.substs()?; | ||
250 | |||
251 | let mut new_substs = vec![Ty::Unknown; gen.count_parent_params()]; | ||
252 | |||
253 | // The following code *link up* the function actual parma type | ||
254 | // and impl_block type param index | ||
255 | self_ty_substs.iter().zip(actual_substs.iter()).for_each(|(param, pty)| { | ||
256 | if let Ty::Param { idx, .. } = param { | ||
257 | if let Some(s) = new_substs.get_mut(*idx as usize) { | ||
258 | *s = pty.clone(); | ||
259 | } | ||
260 | } | ||
261 | }); | ||
262 | |||
263 | Some(Substs(new_substs.into())) | ||
264 | } else { | ||
265 | None | ||
266 | } | ||
267 | } | ||
268 | } | 236 | } |
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index 97281cf15..21efb196a 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs | |||
@@ -191,13 +191,13 @@ pub fn iterate_method_candidates<T>( | |||
191 | let ty = InEnvironment { value: ty.clone(), environment }; | 191 | let ty = InEnvironment { value: ty.clone(), environment }; |
192 | let krate = resolver.krate()?; | 192 | let krate = resolver.krate()?; |
193 | 193 | ||
194 | // We have to be careful about the order of operations here. | 194 | // We have to be careful about the order we're looking at candidates |
195 | // Consider the case where we're resolving `x.clone()` where `x: | 195 | // in here. Consider the case where we're resolving `x.clone()` |
196 | // &Vec<_>`. This resolves to the clone method with self type | 196 | // where `x: &Vec<_>`. This resolves to the clone method with self |
197 | // `Vec<_>`, *not* `&_`. I.e. we need to consider methods where the | 197 | // type `Vec<_>`, *not* `&_`. I.e. we need to consider methods where |
198 | // receiver type exactly matches before cases where we have to do | 198 | // the receiver type exactly matches before cases where we have to |
199 | // autoref. But in the autoderef steps, the `&_` self type comes up | 199 | // do autoref. But in the autoderef steps, the `&_` self type comes |
200 | // *before* the `Vec<_>` self type. | 200 | // up *before* the `Vec<_>` self type. |
201 | // | 201 | // |
202 | // On the other hand, we don't want to just pick any by-value method | 202 | // On the other hand, we don't want to just pick any by-value method |
203 | // before any by-autoref method; it's just that we need to consider | 203 | // before any by-autoref method; it's just that we need to consider |
@@ -206,7 +206,7 @@ pub fn iterate_method_candidates<T>( | |||
206 | 206 | ||
207 | let deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty.clone()).collect(); | 207 | let deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty.clone()).collect(); |
208 | for i in 0..deref_chain.len() { | 208 | for i in 0..deref_chain.len() { |
209 | if let Some(result) = iterate_method_candidates_autoref( | 209 | if let Some(result) = iterate_method_candidates_with_autoref( |
210 | &deref_chain[i..], | 210 | &deref_chain[i..], |
211 | db, | 211 | db, |
212 | resolver, | 212 | resolver, |
@@ -220,12 +220,12 @@ pub fn iterate_method_candidates<T>( | |||
220 | } | 220 | } |
221 | LookupMode::Path => { | 221 | LookupMode::Path => { |
222 | // No autoderef for path lookups | 222 | // No autoderef for path lookups |
223 | iterate_method_candidates_inner(&ty, db, resolver, name, None, &mut callback) | 223 | iterate_method_candidates_for_self_ty(&ty, db, resolver, name, &mut callback) |
224 | } | 224 | } |
225 | } | 225 | } |
226 | } | 226 | } |
227 | 227 | ||
228 | fn iterate_method_candidates_autoref<T>( | 228 | fn iterate_method_candidates_with_autoref<T>( |
229 | deref_chain: &[Canonical<Ty>], | 229 | deref_chain: &[Canonical<Ty>], |
230 | db: &impl HirDatabase, | 230 | db: &impl HirDatabase, |
231 | resolver: &Resolver, | 231 | resolver: &Resolver, |
@@ -275,18 +275,25 @@ fn iterate_method_candidates_autoref<T>( | |||
275 | 275 | ||
276 | fn iterate_method_candidates_by_receiver<T>( | 276 | fn iterate_method_candidates_by_receiver<T>( |
277 | receiver_ty: &Canonical<Ty>, | 277 | receiver_ty: &Canonical<Ty>, |
278 | deref_chain: &[Canonical<Ty>], | 278 | rest_of_deref_chain: &[Canonical<Ty>], |
279 | db: &impl HirDatabase, | 279 | db: &impl HirDatabase, |
280 | resolver: &Resolver, | 280 | resolver: &Resolver, |
281 | name: Option<&Name>, | 281 | name: Option<&Name>, |
282 | mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, | 282 | mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, |
283 | ) -> Option<T> { | 283 | ) -> Option<T> { |
284 | // TODO: do we need to do the whole loop for inherents before traits? | ||
285 | // We're looking for methods with *receiver* type receiver_ty. These could | 284 | // We're looking for methods with *receiver* type receiver_ty. These could |
286 | // be found in any of the derefs of receiver_ty, so we have to go through | 285 | // be found in any of the derefs of receiver_ty, so we have to go through |
287 | // that. | 286 | // that. |
288 | for self_ty in std::iter::once(receiver_ty).chain(deref_chain) { | 287 | let krate = resolver.krate()?; |
289 | if let Some(result) = iterate_method_candidates_inner( | 288 | for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) { |
289 | if let Some(result) = | ||
290 | iterate_inherent_methods(self_ty, db, name, Some(receiver_ty), krate, &mut callback) | ||
291 | { | ||
292 | return Some(result); | ||
293 | } | ||
294 | } | ||
295 | for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) { | ||
296 | if let Some(result) = iterate_trait_method_candidates( | ||
290 | self_ty, | 297 | self_ty, |
291 | db, | 298 | db, |
292 | resolver, | 299 | resolver, |
@@ -300,22 +307,19 @@ fn iterate_method_candidates_by_receiver<T>( | |||
300 | None | 307 | None |
301 | } | 308 | } |
302 | 309 | ||
303 | fn iterate_method_candidates_inner<T>( | 310 | fn iterate_method_candidates_for_self_ty<T>( |
304 | self_ty: &Canonical<Ty>, | 311 | self_ty: &Canonical<Ty>, |
305 | db: &impl HirDatabase, | 312 | db: &impl HirDatabase, |
306 | resolver: &Resolver, | 313 | resolver: &Resolver, |
307 | name: Option<&Name>, | 314 | name: Option<&Name>, |
308 | receiver_ty: Option<&Canonical<Ty>>, | ||
309 | mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, | 315 | mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, |
310 | ) -> Option<T> { | 316 | ) -> Option<T> { |
311 | let krate = resolver.krate()?; | 317 | let krate = resolver.krate()?; |
312 | if let Some(result) = | 318 | if let Some(result) = iterate_inherent_methods(self_ty, db, name, None, krate, &mut callback) { |
313 | iterate_inherent_methods(self_ty, db, name, receiver_ty, krate, &mut callback) | ||
314 | { | ||
315 | return Some(result); | 319 | return Some(result); |
316 | } | 320 | } |
317 | if let Some(result) = | 321 | if let Some(result) = |
318 | iterate_trait_method_candidates(self_ty, db, resolver, name, receiver_ty, &mut callback) | 322 | iterate_trait_method_candidates(self_ty, db, resolver, name, None, &mut callback) |
319 | { | 323 | { |
320 | return Some(result); | 324 | return Some(result); |
321 | } | 325 | } |
@@ -412,29 +416,11 @@ fn is_valid_candidate( | |||
412 | if !data.has_self_param { | 416 | if !data.has_self_param { |
413 | return false; | 417 | return false; |
414 | } | 418 | } |
415 | let substs = match m.lookup(db).container { | 419 | let transformed_receiver_ty = match transform_receiver_ty(db, m, self_ty) { |
416 | hir_def::ContainerId::TraitId(_) => Substs::build_for_def(db, item) | 420 | Some(ty) => ty, |
417 | .push(self_ty.value.clone()) | 421 | None => return false, |
418 | .fill_with_unknown() | ||
419 | .build(), | ||
420 | hir_def::ContainerId::ImplId(impl_id) => { | ||
421 | let vars = | ||
422 | Substs::build_for_def(db, impl_id).fill_with_bound_vars(0).build(); | ||
423 | let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars); | ||
424 | let self_ty_with_vars = | ||
425 | Canonical { num_vars: vars.len(), value: &self_ty_with_vars }; | ||
426 | if let Some(substs) = super::infer::unify(self_ty_with_vars, &self_ty.value) | ||
427 | { | ||
428 | substs | ||
429 | } else { | ||
430 | return false; | ||
431 | } | ||
432 | } | ||
433 | hir_def::ContainerId::ModuleId(_) => unreachable!(), | ||
434 | }; | 422 | }; |
435 | let sig = db.callable_item_signature(m.into()); | 423 | if transformed_receiver_ty != receiver_ty.value { |
436 | let receiver = sig.params()[0].clone().subst(&substs); | ||
437 | if receiver != receiver_ty.value { | ||
438 | return false; | 424 | return false; |
439 | } | 425 | } |
440 | } | 426 | } |
@@ -448,6 +434,34 @@ fn is_valid_candidate( | |||
448 | } | 434 | } |
449 | } | 435 | } |
450 | 436 | ||
437 | pub(crate) fn inherent_impl_substs( | ||
438 | db: &impl HirDatabase, | ||
439 | impl_id: ImplId, | ||
440 | self_ty: &Ty, | ||
441 | ) -> Option<Substs> { | ||
442 | let vars = Substs::build_for_def(db, impl_id).fill_with_bound_vars(0).build(); | ||
443 | let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars); | ||
444 | let self_ty_with_vars = Canonical { num_vars: vars.len(), value: &self_ty_with_vars }; | ||
445 | super::infer::unify(self_ty_with_vars, self_ty) | ||
446 | } | ||
447 | |||
448 | fn transform_receiver_ty( | ||
449 | db: &impl HirDatabase, | ||
450 | function_id: FunctionId, | ||
451 | self_ty: &Canonical<Ty>, | ||
452 | ) -> Option<Ty> { | ||
453 | let substs = match function_id.lookup(db).container { | ||
454 | hir_def::ContainerId::TraitId(_) => Substs::build_for_def(db, function_id) | ||
455 | .push(self_ty.value.clone()) | ||
456 | .fill_with_unknown() | ||
457 | .build(), | ||
458 | hir_def::ContainerId::ImplId(impl_id) => inherent_impl_substs(db, impl_id, &self_ty.value)?, | ||
459 | hir_def::ContainerId::ModuleId(_) => unreachable!(), | ||
460 | }; | ||
461 | let sig = db.callable_item_signature(function_id.into()); | ||
462 | Some(sig.params()[0].clone().subst(&substs)) | ||
463 | } | ||
464 | |||
451 | pub fn implements_trait( | 465 | pub fn implements_trait( |
452 | ty: &Canonical<Ty>, | 466 | ty: &Canonical<Ty>, |
453 | db: &impl HirDatabase, | 467 | db: &impl HirDatabase, |
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index be8768c62..d28e835c7 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs | |||
@@ -3494,6 +3494,21 @@ fn test() { S.foo()<|>; } | |||
3494 | } | 3494 | } |
3495 | 3495 | ||
3496 | #[test] | 3496 | #[test] |
3497 | fn method_resolution_impl_ref_before_trait() { | ||
3498 | let t = type_at( | ||
3499 | r#" | ||
3500 | //- /main.rs | ||
3501 | trait Trait { fn foo(self) -> u128; } | ||
3502 | struct S; | ||
3503 | impl S { fn foo(&self) -> i8 { 0 } } | ||
3504 | impl Trait for &S { fn foo(self) -> u128 { 0 } } | ||
3505 | fn test() { S.foo()<|>; } | ||
3506 | "#, | ||
3507 | ); | ||
3508 | assert_eq!(t, "i8"); | ||
3509 | } | ||
3510 | |||
3511 | #[test] | ||
3497 | fn method_resolution_trait_autoderef() { | 3512 | fn method_resolution_trait_autoderef() { |
3498 | let t = type_at( | 3513 | let t = type_at( |
3499 | r#" | 3514 | r#" |