diff options
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 82 |
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 | } |