diff options
Diffstat (limited to 'crates/ra_hir/src/ty/infer.rs')
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 95 |
1 files changed, 78 insertions, 17 deletions
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 268d2c110..7200446ba 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -63,6 +63,24 @@ enum ExprOrPatId { | |||
63 | 63 | ||
64 | impl_froms!(ExprOrPatId: ExprId, PatId); | 64 | impl_froms!(ExprOrPatId: ExprId, PatId); |
65 | 65 | ||
66 | /// Binding modes inferred for patterns. | ||
67 | /// https://doc.rust-lang.org/reference/patterns.html#binding-modes | ||
68 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] | ||
69 | enum BindingMode { | ||
70 | Move, | ||
71 | Ref(Mutability), | ||
72 | } | ||
73 | |||
74 | impl BindingMode { | ||
75 | pub fn convert(annotation: &BindingAnnotation) -> BindingMode { | ||
76 | match annotation { | ||
77 | BindingAnnotation::Unannotated | BindingAnnotation::Mutable => BindingMode::Move, | ||
78 | BindingAnnotation::Ref => BindingMode::Ref(Mutability::Shared), | ||
79 | BindingAnnotation::RefMut => BindingMode::Ref(Mutability::Mut), | ||
80 | } | ||
81 | } | ||
82 | } | ||
83 | |||
66 | /// The result of type inference: A mapping from expressions and patterns to types. | 84 | /// The result of type inference: A mapping from expressions and patterns to types. |
67 | #[derive(Clone, PartialEq, Eq, Debug)] | 85 | #[derive(Clone, PartialEq, Eq, Debug)] |
68 | pub struct InferenceResult { | 86 | pub struct InferenceResult { |
@@ -530,6 +548,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
530 | path: Option<&Path>, | 548 | path: Option<&Path>, |
531 | subpats: &[PatId], | 549 | subpats: &[PatId], |
532 | expected: &Ty, | 550 | expected: &Ty, |
551 | default_bm: BindingMode, | ||
533 | ) -> Ty { | 552 | ) -> Ty { |
534 | let (ty, def) = self.resolve_variant(path); | 553 | let (ty, def) = self.resolve_variant(path); |
535 | 554 | ||
@@ -542,13 +561,19 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
542 | .and_then(|d| d.field(self.db, &Name::tuple_field_name(i))) | 561 | .and_then(|d| d.field(self.db, &Name::tuple_field_name(i))) |
543 | .map_or(Ty::Unknown, |field| field.ty(self.db)) | 562 | .map_or(Ty::Unknown, |field| field.ty(self.db)) |
544 | .subst(&substs); | 563 | .subst(&substs); |
545 | self.infer_pat(subpat, &expected_ty); | 564 | self.infer_pat(subpat, &expected_ty, default_bm); |
546 | } | 565 | } |
547 | 566 | ||
548 | ty | 567 | ty |
549 | } | 568 | } |
550 | 569 | ||
551 | fn infer_struct_pat(&mut self, path: Option<&Path>, subpats: &[FieldPat], expected: &Ty) -> Ty { | 570 | fn infer_struct_pat( |
571 | &mut self, | ||
572 | path: Option<&Path>, | ||
573 | subpats: &[FieldPat], | ||
574 | expected: &Ty, | ||
575 | default_bm: BindingMode, | ||
576 | ) -> Ty { | ||
552 | let (ty, def) = self.resolve_variant(path); | 577 | let (ty, def) = self.resolve_variant(path); |
553 | 578 | ||
554 | self.unify(&ty, expected); | 579 | self.unify(&ty, expected); |
@@ -559,15 +584,42 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
559 | let matching_field = def.and_then(|it| it.field(self.db, &subpat.name)); | 584 | let matching_field = def.and_then(|it| it.field(self.db, &subpat.name)); |
560 | let expected_ty = | 585 | let expected_ty = |
561 | matching_field.map_or(Ty::Unknown, |field| field.ty(self.db)).subst(&substs); | 586 | matching_field.map_or(Ty::Unknown, |field| field.ty(self.db)).subst(&substs); |
562 | self.infer_pat(subpat.pat, &expected_ty); | 587 | self.infer_pat(subpat.pat, &expected_ty, default_bm); |
563 | } | 588 | } |
564 | 589 | ||
565 | ty | 590 | ty |
566 | } | 591 | } |
567 | 592 | ||
568 | fn infer_pat(&mut self, pat: PatId, expected: &Ty) -> Ty { | 593 | fn infer_pat(&mut self, pat: PatId, mut expected: &Ty, mut default_bm: BindingMode) -> Ty { |
569 | let body = Arc::clone(&self.body); // avoid borrow checker problem | 594 | let body = Arc::clone(&self.body); // avoid borrow checker problem |
570 | 595 | ||
596 | let is_non_ref_pat = match &body[pat] { | ||
597 | Pat::Tuple(..) | ||
598 | | Pat::TupleStruct { .. } | ||
599 | | Pat::Struct { .. } | ||
600 | | Pat::Range { .. } | ||
601 | | Pat::Slice { .. } => true, | ||
602 | // TODO: Path/Lit might actually evaluate to ref, but inference is unimplemented. | ||
603 | Pat::Path(..) | Pat::Lit(..) => true, | ||
604 | Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Missing => false, | ||
605 | }; | ||
606 | if is_non_ref_pat { | ||
607 | while let Ty::Ref(inner, mutability) = expected { | ||
608 | expected = inner; | ||
609 | default_bm = match default_bm { | ||
610 | BindingMode::Move => BindingMode::Ref(*mutability), | ||
611 | BindingMode::Ref(Mutability::Shared) => BindingMode::Ref(Mutability::Shared), | ||
612 | BindingMode::Ref(Mutability::Mut) => BindingMode::Ref(*mutability), | ||
613 | } | ||
614 | } | ||
615 | } else if let Pat::Ref { .. } = &body[pat] { | ||
616 | default_bm = BindingMode::Move; | ||
617 | } | ||
618 | |||
619 | // Lose mutability. | ||
620 | let default_bm = default_bm; | ||
621 | let expected = expected; | ||
622 | |||
571 | let ty = match &body[pat] { | 623 | let ty = match &body[pat] { |
572 | Pat::Tuple(ref args) => { | 624 | Pat::Tuple(ref args) => { |
573 | let expectations = match *expected { | 625 | let expectations = match *expected { |
@@ -579,7 +631,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
579 | let inner_tys = args | 631 | let inner_tys = args |
580 | .iter() | 632 | .iter() |
581 | .zip(expectations_iter) | 633 | .zip(expectations_iter) |
582 | .map(|(&pat, ty)| self.infer_pat(pat, ty)) | 634 | .map(|(&pat, ty)| self.infer_pat(pat, ty, default_bm)) |
583 | .collect::<Vec<_>>() | 635 | .collect::<Vec<_>>() |
584 | .into(); | 636 | .into(); |
585 | 637 | ||
@@ -595,14 +647,14 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
595 | } | 647 | } |
596 | _ => &Ty::Unknown, | 648 | _ => &Ty::Unknown, |
597 | }; | 649 | }; |
598 | let subty = self.infer_pat(*pat, expectation); | 650 | let subty = self.infer_pat(*pat, expectation, default_bm); |
599 | Ty::Ref(subty.into(), *mutability) | 651 | Ty::Ref(subty.into(), *mutability) |
600 | } | 652 | } |
601 | Pat::TupleStruct { path: ref p, args: ref subpats } => { | 653 | Pat::TupleStruct { path: ref p, args: ref subpats } => { |
602 | self.infer_tuple_struct_pat(p.as_ref(), subpats, expected) | 654 | self.infer_tuple_struct_pat(p.as_ref(), subpats, expected, default_bm) |
603 | } | 655 | } |
604 | Pat::Struct { path: ref p, args: ref fields } => { | 656 | Pat::Struct { path: ref p, args: ref fields } => { |
605 | self.infer_struct_pat(p.as_ref(), fields, expected) | 657 | self.infer_struct_pat(p.as_ref(), fields, expected, default_bm) |
606 | } | 658 | } |
607 | Pat::Path(path) => { | 659 | Pat::Path(path) => { |
608 | // TODO use correct resolver for the surrounding expression | 660 | // TODO use correct resolver for the surrounding expression |
@@ -610,17 +662,26 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
610 | self.infer_path_expr(&resolver, &path, pat.into()).unwrap_or(Ty::Unknown) | 662 | self.infer_path_expr(&resolver, &path, pat.into()).unwrap_or(Ty::Unknown) |
611 | } | 663 | } |
612 | Pat::Bind { mode, name: _name, subpat } => { | 664 | Pat::Bind { mode, name: _name, subpat } => { |
665 | let mode = if mode == &BindingAnnotation::Unannotated { | ||
666 | default_bm | ||
667 | } else { | ||
668 | BindingMode::convert(mode) | ||
669 | }; | ||
613 | let inner_ty = if let Some(subpat) = subpat { | 670 | let inner_ty = if let Some(subpat) = subpat { |
614 | self.infer_pat(*subpat, expected) | 671 | self.infer_pat(*subpat, expected, default_bm) |
615 | } else { | 672 | } else { |
616 | expected.clone() | 673 | expected.clone() |
617 | }; | 674 | }; |
618 | let inner_ty = self.insert_type_vars_shallow(inner_ty); | 675 | let inner_ty = self.insert_type_vars_shallow(inner_ty); |
619 | 676 | ||
620 | let bound_ty = match mode { | 677 | let bound_ty = match mode { |
621 | BindingAnnotation::Ref => Ty::Ref(inner_ty.clone().into(), Mutability::Shared), | 678 | BindingMode::Ref(Mutability::Shared) => { |
622 | BindingAnnotation::RefMut => Ty::Ref(inner_ty.clone().into(), Mutability::Mut), | 679 | Ty::Ref(inner_ty.clone().into(), Mutability::Shared) |
623 | BindingAnnotation::Mutable | BindingAnnotation::Unannotated => inner_ty.clone(), | 680 | } |
681 | BindingMode::Ref(Mutability::Mut) => { | ||
682 | Ty::Ref(inner_ty.clone().into(), Mutability::Mut) | ||
683 | } | ||
684 | BindingMode::Move => inner_ty.clone(), | ||
624 | }; | 685 | }; |
625 | let bound_ty = self.resolve_ty_as_possible(&mut vec![], bound_ty); | 686 | let bound_ty = self.resolve_ty_as_possible(&mut vec![], bound_ty); |
626 | self.write_pat_ty(pat, bound_ty); | 687 | self.write_pat_ty(pat, bound_ty); |
@@ -700,7 +761,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
700 | } | 761 | } |
701 | Expr::For { iterable, body, pat } => { | 762 | Expr::For { iterable, body, pat } => { |
702 | let _iterable_ty = self.infer_expr(*iterable, &Expectation::none()); | 763 | let _iterable_ty = self.infer_expr(*iterable, &Expectation::none()); |
703 | self.infer_pat(*pat, &Ty::Unknown); | 764 | self.infer_pat(*pat, &Ty::Unknown, BindingMode::Move); |
704 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); | 765 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); |
705 | Ty::unit() | 766 | Ty::unit() |
706 | } | 767 | } |
@@ -714,7 +775,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
714 | } else { | 775 | } else { |
715 | Ty::Unknown | 776 | Ty::Unknown |
716 | }; | 777 | }; |
717 | self.infer_pat(*arg_pat, &expected); | 778 | self.infer_pat(*arg_pat, &expected, BindingMode::Move); |
718 | } | 779 | } |
719 | 780 | ||
720 | // TODO: infer lambda type etc. | 781 | // TODO: infer lambda type etc. |
@@ -804,7 +865,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
804 | 865 | ||
805 | for arm in arms { | 866 | for arm in arms { |
806 | for &pat in &arm.pats { | 867 | for &pat in &arm.pats { |
807 | let _pat_ty = self.infer_pat(pat, &input_ty); | 868 | let _pat_ty = self.infer_pat(pat, &input_ty, BindingMode::Move); |
808 | } | 869 | } |
809 | if let Some(guard_expr) = arm.guard { | 870 | if let Some(guard_expr) = arm.guard { |
810 | self.infer_expr(guard_expr, &Expectation::has_type(Ty::Bool)); | 871 | self.infer_expr(guard_expr, &Expectation::has_type(Ty::Bool)); |
@@ -1004,7 +1065,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1004 | decl_ty | 1065 | decl_ty |
1005 | }; | 1066 | }; |
1006 | 1067 | ||
1007 | self.infer_pat(*pat, &ty); | 1068 | self.infer_pat(*pat, &ty, BindingMode::Move); |
1008 | } | 1069 | } |
1009 | Statement::Expr(expr) => { | 1070 | Statement::Expr(expr) => { |
1010 | self.infer_expr(*expr, &Expectation::none()); | 1071 | self.infer_expr(*expr, &Expectation::none()); |
@@ -1020,7 +1081,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1020 | for (type_ref, pat) in signature.params().iter().zip(body.params()) { | 1081 | for (type_ref, pat) in signature.params().iter().zip(body.params()) { |
1021 | let ty = self.make_ty(type_ref); | 1082 | let ty = self.make_ty(type_ref); |
1022 | 1083 | ||
1023 | self.infer_pat(*pat, &ty); | 1084 | self.infer_pat(*pat, &ty, BindingMode::Move); |
1024 | } | 1085 | } |
1025 | self.return_ty = self.make_ty(signature.ret_type()); | 1086 | self.return_ty = self.make_ty(signature.ret_type()); |
1026 | } | 1087 | } |