aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-12-02 17:12:49 +0000
committerFlorian Diebold <[email protected]>2019-12-02 18:33:13 +0000
commitcfa50df33e1ebfa89f7fbdece7454699f858de92 (patch)
treef793df3b6eab65a110bf1cc22258eaad15f77df9
parent456d52fdfa8525af2a54e76ee5300f0a40ef582a (diff)
Refactor a bit
-rw-r--r--crates/ra_hir_ty/src/infer/path.rs38
-rw-r--r--crates/ra_hir_ty/src/method_resolution.rs98
-rw-r--r--crates/ra_hir_ty/src/tests.rs15
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
228fn iterate_method_candidates_autoref<T>( 228fn 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
276fn iterate_method_candidates_by_receiver<T>( 276fn 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
303fn iterate_method_candidates_inner<T>( 310fn 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
437pub(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
448fn 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
451pub fn implements_trait( 465pub 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]
3497fn method_resolution_impl_ref_before_trait() {
3498 let t = type_at(
3499 r#"
3500//- /main.rs
3501trait Trait { fn foo(self) -> u128; }
3502struct S;
3503impl S { fn foo(&self) -> i8 { 0 } }
3504impl Trait for &S { fn foo(self) -> u128 { 0 } }
3505fn test() { S.foo()<|>; }
3506"#,
3507 );
3508 assert_eq!(t, "i8");
3509}
3510
3511#[test]
3497fn method_resolution_trait_autoderef() { 3512fn method_resolution_trait_autoderef() {
3498 let t = type_at( 3513 let t = type_at(
3499 r#" 3514 r#"