aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/src/ty/infer.rs82
1 files changed, 60 insertions, 22 deletions
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index fe6553f79..a3c4f1886 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -469,16 +469,34 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
469 let typable: Option<TypableDef> = def.into(); 469 let typable: Option<TypableDef> = def.into();
470 let typable = typable?; 470 let typable = typable?;
471 471
472 // For example, this substs will take `Gen::make::*<u32>*`
472 let mut substs = 473 let mut substs =
473 Ty::substs_from_path_segment(self.db, &self.resolver, segment, typable); 474 Ty::substs_from_path_segment(self.db, &self.resolver, segment, typable);
474 475
475 if remaining_index > 0 { 476 if remaining_index > 0 {
476 substs = Ty::substs_from_path_segment( 477 // For example, this substs will take `Gen::*<u32>*::make`
478 let parent_substs = Ty::substs_from_path_segment(
477 self.db, 479 self.db,
478 &self.resolver, 480 &self.resolver,
479 &path.segments[remaining_index - 1], 481 &path.segments[remaining_index - 1],
480 typable, 482 typable,
481 ); 483 );
484
485 // merge parent and child substs
486 let max_len = std::cmp::max(substs.len(), parent_substs.len());
487 let mut merged = vec![];
488 for i in 0..max_len {
489 let s = match (substs.0.get(i), parent_substs.0.get(i)) {
490 (Some(s @ Ty::Apply(_)), _) => s,
491 (_, Some(s @ Ty::Apply(_))) => s,
492 (Some(s), _) => s,
493 (_, Some(s)) => s,
494 _ => unreachable!(),
495 };
496 merged.push(s.clone());
497 }
498
499 substs = Substs(merged.into());
482 } 500 }
483 501
484 let ty = self.db.type_for_def(typable, Namespace::Types); 502 let ty = self.db.type_for_def(typable, Namespace::Types);
@@ -549,32 +567,52 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
549 let ty = self.insert_type_vars(ty); 567 let ty = self.insert_type_vars(ty);
550 568
551 // plug the old parent_ty in 569 // plug the old parent_ty in
552 if let Some(actual_def_ty) = actual_def_ty { 570 let plug_self_types = || -> Option<()> {
571 let actual_def_ty = actual_def_ty?;
572
553 if let crate::ModuleDef::Function(func) = def { 573 if let crate::ModuleDef::Function(func) = def {
574 // We only do the infer if parent has generic params
554 let gen = func.generic_params(self.db); 575 let gen = func.generic_params(self.db);
555 if let Some(target_ty) = func.impl_block(self.db) { 576 if gen.count_parent_params() == 0 {
556 let target_ty = target_ty.target_ty(self.db); 577 return None;
557 let old_params = target_ty.substs().unwrap().clone(); 578 }
558 579
559 let target_ty = target_ty.subst(&substs); 580 let impl_block = func.impl_block(self.db)?;
560 let target_ty = self.insert_type_vars(target_ty); 581 let impl_block = impl_block.target_ty(self.db);
561 582
562 if gen.count_parent_params() > 0 { 583 // We save the impl block type params for later use
563 self.unify(&target_ty, &actual_def_ty); 584 let old_params = impl_block.substs().unwrap().clone();
564 585
565 if let Ty::Apply(ty) = &ty { 586 // Turn the impl block generic params to unknown
566 for (param, pty) in 587 let mut subst = vec![];
567 old_params.iter().zip(target_ty.substs().unwrap().iter()) 588 for _ in 0..impl_block.substs().map(|x| x.len()).unwrap_or(0) {
568 { 589 subst.push(Ty::Unknown);
569 if let Ty::Param { idx, .. } = param { 590 }
570 self.unify(pty, &ty.parameters.0[*idx as usize]); 591 let impl_block = impl_block.subst(&Substs(subst.into()));
571 } 592 let impl_block = self.insert_type_vars(impl_block);
593
594 // Unify *self type* and impl_block
595 // e.g. Gen::<u32,u64> <=> Gen::<u64, T>
596 self.unify(&impl_block, &actual_def_ty);
597
598 // The following code *link up* the function parent generic param
599 // and the impl_block generic param by unify them one by one
600 if let Ty::Apply(ty) = &ty {
601 old_params.iter().zip(impl_block.substs()?.iter()).for_each(
602 |(param, pty)| {
603 if let Ty::Param { idx, .. } = param {
604 self.unify(pty, &ty.parameters.0[*idx as usize]);
572 } 605 }
573 } 606 },
574 } 607 );
575 } 608 }
609
610 return Some(());
576 } 611 }
577 } 612 None
613 };
614
615 plug_self_types();
578 616
579 Some(ty) 617 Some(ty)
580 } 618 }