aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/ty')
-rw-r--r--crates/ra_hir/src/ty/display.rs56
-rw-r--r--crates/ra_hir/src/ty/infer.rs130
-rw-r--r--crates/ra_hir/src/ty/lower.rs99
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs10
-rw-r--r--crates/ra_hir/src/ty/primitive.rs64
-rw-r--r--crates/ra_hir/src/ty/tests.rs59
6 files changed, 306 insertions, 112 deletions
diff --git a/crates/ra_hir/src/ty/display.rs b/crates/ra_hir/src/ty/display.rs
new file mode 100644
index 000000000..63ec9d7e1
--- /dev/null
+++ b/crates/ra_hir/src/ty/display.rs
@@ -0,0 +1,56 @@
1use std::fmt;
2
3use crate::db::HirDatabase;
4
5pub struct HirFormatter<'a, 'b, DB> {
6 pub db: &'a DB,
7 fmt: &'a mut fmt::Formatter<'b>,
8}
9
10pub trait HirDisplay {
11 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result;
12 fn display<'a, DB>(&'a self, db: &'a DB) -> HirDisplayWrapper<'a, DB, Self>
13 where
14 Self: Sized,
15 {
16 HirDisplayWrapper(db, self)
17 }
18}
19
20impl<'a, 'b, DB> HirFormatter<'a, 'b, DB>
21where
22 DB: HirDatabase,
23{
24 pub fn write_joined<T: HirDisplay>(
25 &mut self,
26 iter: impl IntoIterator<Item = T>,
27 sep: &str,
28 ) -> fmt::Result {
29 let mut first = true;
30 for e in iter {
31 if !first {
32 write!(self, "{}", sep)?;
33 }
34 first = false;
35 e.hir_fmt(self)?;
36 }
37 Ok(())
38 }
39
40 /// This allows using the `write!` macro directly with a `HirFormatter`.
41 pub fn write_fmt(&mut self, args: fmt::Arguments) -> fmt::Result {
42 fmt::write(self.fmt, args)
43 }
44}
45
46pub struct HirDisplayWrapper<'a, DB, T>(&'a DB, &'a T);
47
48impl<'a, DB, T> fmt::Display for HirDisplayWrapper<'a, DB, T>
49where
50 DB: HirDatabase,
51 T: HirDisplay,
52{
53 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
54 self.1.hir_fmt(&mut HirFormatter { db: self.0, fmt: f })
55 }
56}
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 268d2c110..735cdecb9 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -63,6 +63,30 @@ enum ExprOrPatId {
63 63
64impl_froms!(ExprOrPatId: ExprId, PatId); 64impl_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)]
69enum BindingMode {
70 Move,
71 Ref(Mutability),
72}
73
74impl 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
84impl Default for BindingMode {
85 fn default() -> Self {
86 BindingMode::Move
87 }
88}
89
66/// The result of type inference: A mapping from expressions and patterns to types. 90/// The result of type inference: A mapping from expressions and patterns to types.
67#[derive(Clone, PartialEq, Eq, Debug)] 91#[derive(Clone, PartialEq, Eq, Debug)]
68pub struct InferenceResult { 92pub struct InferenceResult {
@@ -530,6 +554,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
530 path: Option<&Path>, 554 path: Option<&Path>,
531 subpats: &[PatId], 555 subpats: &[PatId],
532 expected: &Ty, 556 expected: &Ty,
557 default_bm: BindingMode,
533 ) -> Ty { 558 ) -> Ty {
534 let (ty, def) = self.resolve_variant(path); 559 let (ty, def) = self.resolve_variant(path);
535 560
@@ -542,13 +567,19 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
542 .and_then(|d| d.field(self.db, &Name::tuple_field_name(i))) 567 .and_then(|d| d.field(self.db, &Name::tuple_field_name(i)))
543 .map_or(Ty::Unknown, |field| field.ty(self.db)) 568 .map_or(Ty::Unknown, |field| field.ty(self.db))
544 .subst(&substs); 569 .subst(&substs);
545 self.infer_pat(subpat, &expected_ty); 570 self.infer_pat(subpat, &expected_ty, default_bm);
546 } 571 }
547 572
548 ty 573 ty
549 } 574 }
550 575
551 fn infer_struct_pat(&mut self, path: Option<&Path>, subpats: &[FieldPat], expected: &Ty) -> Ty { 576 fn infer_struct_pat(
577 &mut self,
578 path: Option<&Path>,
579 subpats: &[FieldPat],
580 expected: &Ty,
581 default_bm: BindingMode,
582 ) -> Ty {
552 let (ty, def) = self.resolve_variant(path); 583 let (ty, def) = self.resolve_variant(path);
553 584
554 self.unify(&ty, expected); 585 self.unify(&ty, expected);
@@ -559,15 +590,45 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
559 let matching_field = def.and_then(|it| it.field(self.db, &subpat.name)); 590 let matching_field = def.and_then(|it| it.field(self.db, &subpat.name));
560 let expected_ty = 591 let expected_ty =
561 matching_field.map_or(Ty::Unknown, |field| field.ty(self.db)).subst(&substs); 592 matching_field.map_or(Ty::Unknown, |field| field.ty(self.db)).subst(&substs);
562 self.infer_pat(subpat.pat, &expected_ty); 593 self.infer_pat(subpat.pat, &expected_ty, default_bm);
563 } 594 }
564 595
565 ty 596 ty
566 } 597 }
567 598
568 fn infer_pat(&mut self, pat: PatId, expected: &Ty) -> Ty { 599 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 600 let body = Arc::clone(&self.body); // avoid borrow checker problem
570 601
602 let is_non_ref_pat = match &body[pat] {
603 Pat::Tuple(..)
604 | Pat::TupleStruct { .. }
605 | Pat::Struct { .. }
606 | Pat::Range { .. }
607 | Pat::Slice { .. } => true,
608 // TODO: Path/Lit might actually evaluate to ref, but inference is unimplemented.
609 Pat::Path(..) | Pat::Lit(..) => true,
610 Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Missing => false,
611 };
612 if is_non_ref_pat {
613 while let Ty::Ref(inner, mutability) = expected {
614 expected = inner;
615 default_bm = match default_bm {
616 BindingMode::Move => BindingMode::Ref(*mutability),
617 BindingMode::Ref(Mutability::Shared) => BindingMode::Ref(Mutability::Shared),
618 BindingMode::Ref(Mutability::Mut) => BindingMode::Ref(*mutability),
619 }
620 }
621 } else if let Pat::Ref { .. } = &body[pat] {
622 tested_by!(match_ergonomics_ref);
623 // When you encounter a `&pat` pattern, reset to Move.
624 // This is so that `w` is by value: `let (_, &w) = &(1, &2);`
625 default_bm = BindingMode::Move;
626 }
627
628 // Lose mutability.
629 let default_bm = default_bm;
630 let expected = expected;
631
571 let ty = match &body[pat] { 632 let ty = match &body[pat] {
572 Pat::Tuple(ref args) => { 633 Pat::Tuple(ref args) => {
573 let expectations = match *expected { 634 let expectations = match *expected {
@@ -579,7 +640,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
579 let inner_tys = args 640 let inner_tys = args
580 .iter() 641 .iter()
581 .zip(expectations_iter) 642 .zip(expectations_iter)
582 .map(|(&pat, ty)| self.infer_pat(pat, ty)) 643 .map(|(&pat, ty)| self.infer_pat(pat, ty, default_bm))
583 .collect::<Vec<_>>() 644 .collect::<Vec<_>>()
584 .into(); 645 .into();
585 646
@@ -595,14 +656,14 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
595 } 656 }
596 _ => &Ty::Unknown, 657 _ => &Ty::Unknown,
597 }; 658 };
598 let subty = self.infer_pat(*pat, expectation); 659 let subty = self.infer_pat(*pat, expectation, default_bm);
599 Ty::Ref(subty.into(), *mutability) 660 Ty::Ref(subty.into(), *mutability)
600 } 661 }
601 Pat::TupleStruct { path: ref p, args: ref subpats } => { 662 Pat::TupleStruct { path: ref p, args: ref subpats } => {
602 self.infer_tuple_struct_pat(p.as_ref(), subpats, expected) 663 self.infer_tuple_struct_pat(p.as_ref(), subpats, expected, default_bm)
603 } 664 }
604 Pat::Struct { path: ref p, args: ref fields } => { 665 Pat::Struct { path: ref p, args: ref fields } => {
605 self.infer_struct_pat(p.as_ref(), fields, expected) 666 self.infer_struct_pat(p.as_ref(), fields, expected, default_bm)
606 } 667 }
607 Pat::Path(path) => { 668 Pat::Path(path) => {
608 // TODO use correct resolver for the surrounding expression 669 // TODO use correct resolver for the surrounding expression
@@ -610,17 +671,21 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
610 self.infer_path_expr(&resolver, &path, pat.into()).unwrap_or(Ty::Unknown) 671 self.infer_path_expr(&resolver, &path, pat.into()).unwrap_or(Ty::Unknown)
611 } 672 }
612 Pat::Bind { mode, name: _name, subpat } => { 673 Pat::Bind { mode, name: _name, subpat } => {
674 let mode = if mode == &BindingAnnotation::Unannotated {
675 default_bm
676 } else {
677 BindingMode::convert(mode)
678 };
613 let inner_ty = if let Some(subpat) = subpat { 679 let inner_ty = if let Some(subpat) = subpat {
614 self.infer_pat(*subpat, expected) 680 self.infer_pat(*subpat, expected, default_bm)
615 } else { 681 } else {
616 expected.clone() 682 expected.clone()
617 }; 683 };
618 let inner_ty = self.insert_type_vars_shallow(inner_ty); 684 let inner_ty = self.insert_type_vars_shallow(inner_ty);
619 685
620 let bound_ty = match mode { 686 let bound_ty = match mode {
621 BindingAnnotation::Ref => Ty::Ref(inner_ty.clone().into(), Mutability::Shared), 687 BindingMode::Ref(mutability) => Ty::Ref(inner_ty.clone().into(), mutability),
622 BindingAnnotation::RefMut => Ty::Ref(inner_ty.clone().into(), Mutability::Mut), 688 BindingMode::Move => inner_ty.clone(),
623 BindingAnnotation::Mutable | BindingAnnotation::Unannotated => inner_ty.clone(),
624 }; 689 };
625 let bound_ty = self.resolve_ty_as_possible(&mut vec![], bound_ty); 690 let bound_ty = self.resolve_ty_as_possible(&mut vec![], bound_ty);
626 self.write_pat_ty(pat, bound_ty); 691 self.write_pat_ty(pat, bound_ty);
@@ -700,7 +765,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
700 } 765 }
701 Expr::For { iterable, body, pat } => { 766 Expr::For { iterable, body, pat } => {
702 let _iterable_ty = self.infer_expr(*iterable, &Expectation::none()); 767 let _iterable_ty = self.infer_expr(*iterable, &Expectation::none());
703 self.infer_pat(*pat, &Ty::Unknown); 768 self.infer_pat(*pat, &Ty::Unknown, BindingMode::default());
704 self.infer_expr(*body, &Expectation::has_type(Ty::unit())); 769 self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
705 Ty::unit() 770 Ty::unit()
706 } 771 }
@@ -714,7 +779,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
714 } else { 779 } else {
715 Ty::Unknown 780 Ty::Unknown
716 }; 781 };
717 self.infer_pat(*arg_pat, &expected); 782 self.infer_pat(*arg_pat, &expected, BindingMode::default());
718 } 783 }
719 784
720 // TODO: infer lambda type etc. 785 // TODO: infer lambda type etc.
@@ -724,11 +789,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
724 Expr::Call { callee, args } => { 789 Expr::Call { callee, args } => {
725 let callee_ty = self.infer_expr(*callee, &Expectation::none()); 790 let callee_ty = self.infer_expr(*callee, &Expectation::none());
726 let (param_tys, ret_ty) = match &callee_ty { 791 let (param_tys, ret_ty) = match &callee_ty {
727 Ty::FnPtr(sig) => (sig.input.clone(), sig.output.clone()), 792 Ty::FnPtr(sig) => (sig.params().to_vec(), sig.ret().clone()),
728 Ty::FnDef { substs, sig, .. } => { 793 Ty::FnDef { substs, def, .. } => {
729 let ret_ty = sig.output.clone().subst(&substs); 794 let sig = self.db.callable_item_signature(*def);
795 let ret_ty = sig.ret().clone().subst(&substs);
730 let param_tys = 796 let param_tys =
731 sig.input.iter().map(|ty| ty.clone().subst(&substs)).collect(); 797 sig.params().iter().map(|ty| ty.clone().subst(&substs)).collect();
732 (param_tys, ret_ty) 798 (param_tys, ret_ty)
733 } 799 }
734 _ => { 800 _ => {
@@ -762,19 +828,21 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
762 let method_ty = self.insert_type_vars(method_ty); 828 let method_ty = self.insert_type_vars(method_ty);
763 let (expected_receiver_ty, param_tys, ret_ty) = match &method_ty { 829 let (expected_receiver_ty, param_tys, ret_ty) = match &method_ty {
764 Ty::FnPtr(sig) => { 830 Ty::FnPtr(sig) => {
765 if !sig.input.is_empty() { 831 if !sig.params().is_empty() {
766 (sig.input[0].clone(), sig.input[1..].to_vec(), sig.output.clone()) 832 (sig.params()[0].clone(), sig.params()[1..].to_vec(), sig.ret().clone())
767 } else { 833 } else {
768 (Ty::Unknown, Vec::new(), sig.output.clone()) 834 (Ty::Unknown, Vec::new(), sig.ret().clone())
769 } 835 }
770 } 836 }
771 Ty::FnDef { substs, sig, .. } => { 837 Ty::FnDef { substs, def, .. } => {
772 let ret_ty = sig.output.clone().subst(&substs); 838 let sig = self.db.callable_item_signature(*def);
773 839 let ret_ty = sig.ret().clone().subst(&substs);
774 if !sig.input.is_empty() { 840
775 let mut arg_iter = sig.input.iter().map(|ty| ty.clone().subst(&substs)); 841 if !sig.params().is_empty() {
776 let receiver_ty = arg_iter.next().unwrap(); 842 let mut params_iter =
777 (receiver_ty, arg_iter.collect(), ret_ty) 843 sig.params().iter().map(|ty| ty.clone().subst(&substs));
844 let receiver_ty = params_iter.next().unwrap();
845 (receiver_ty, params_iter.collect(), ret_ty)
778 } else { 846 } else {
779 (Ty::Unknown, Vec::new(), ret_ty) 847 (Ty::Unknown, Vec::new(), ret_ty)
780 } 848 }
@@ -804,7 +872,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
804 872
805 for arm in arms { 873 for arm in arms {
806 for &pat in &arm.pats { 874 for &pat in &arm.pats {
807 let _pat_ty = self.infer_pat(pat, &input_ty); 875 let _pat_ty = self.infer_pat(pat, &input_ty, BindingMode::default());
808 } 876 }
809 if let Some(guard_expr) = arm.guard { 877 if let Some(guard_expr) = arm.guard {
810 self.infer_expr(guard_expr, &Expectation::has_type(Ty::Bool)); 878 self.infer_expr(guard_expr, &Expectation::has_type(Ty::Bool));
@@ -1004,7 +1072,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1004 decl_ty 1072 decl_ty
1005 }; 1073 };
1006 1074
1007 self.infer_pat(*pat, &ty); 1075 self.infer_pat(*pat, &ty, BindingMode::default());
1008 } 1076 }
1009 Statement::Expr(expr) => { 1077 Statement::Expr(expr) => {
1010 self.infer_expr(*expr, &Expectation::none()); 1078 self.infer_expr(*expr, &Expectation::none());
@@ -1020,7 +1088,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1020 for (type_ref, pat) in signature.params().iter().zip(body.params()) { 1088 for (type_ref, pat) in signature.params().iter().zip(body.params()) {
1021 let ty = self.make_ty(type_ref); 1089 let ty = self.make_ty(type_ref);
1022 1090
1023 self.infer_pat(*pat, &ty); 1091 self.infer_pat(*pat, &ty, BindingMode::default());
1024 } 1092 }
1025 self.return_ty = self.make_ty(signature.ret_type()); 1093 self.return_ty = self.make_ty(signature.ret_type());
1026 } 1094 }
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index f4e055feb..278f592d3 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -9,7 +9,7 @@
9use std::sync::Arc; 9use std::sync::Arc;
10 10
11use crate::{ 11use crate::{
12 Function, Struct, StructField, Enum, EnumVariant, Path, Name, 12 Function, Struct, StructField, Enum, EnumVariant, Path,
13 ModuleDef, TypeAlias, 13 ModuleDef, TypeAlias,
14 Const, Static, 14 Const, Static,
15 HirDatabase, 15 HirDatabase,
@@ -51,12 +51,10 @@ impl Ty {
51 } 51 }
52 TypeRef::Placeholder => Ty::Unknown, 52 TypeRef::Placeholder => Ty::Unknown,
53 TypeRef::Fn(params) => { 53 TypeRef::Fn(params) => {
54 let mut inner_tys = 54 let inner_tys =
55 params.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect::<Vec<_>>(); 55 params.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect::<Vec<_>>();
56 let return_ty = 56 let sig = FnSig { params_and_return: inner_tys.into() };
57 inner_tys.pop().expect("TypeRef::Fn should always have at least return type"); 57 Ty::FnPtr(sig)
58 let sig = FnSig { input: inner_tys, output: return_ty };
59 Ty::FnPtr(Arc::new(sig))
60 } 58 }
61 TypeRef::Error => Ty::Unknown, 59 TypeRef::Error => Ty::Unknown,
62 } 60 }
@@ -214,6 +212,15 @@ pub(crate) fn type_for_def(db: &impl HirDatabase, def: TypableDef, ns: Namespace
214 } 212 }
215} 213}
216 214
215/// Build the signature of a callable item (function, struct or enum variant).
216pub(crate) fn callable_item_sig(db: &impl HirDatabase, def: CallableDef) -> FnSig {
217 match def {
218 CallableDef::Function(f) => fn_sig_for_fn(db, f),
219 CallableDef::Struct(s) => fn_sig_for_struct_constructor(db, s),
220 CallableDef::EnumVariant(e) => fn_sig_for_enum_variant_constructor(db, e),
221 }
222}
223
217/// Build the type of a specific field of a struct or enum variant. 224/// Build the type of a specific field of a struct or enum variant.
218pub(crate) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty { 225pub(crate) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty {
219 let parent_def = field.parent_def(db); 226 let parent_def = field.parent_def(db);
@@ -226,19 +233,21 @@ pub(crate) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty {
226 Ty::from_hir(db, &resolver, type_ref) 233 Ty::from_hir(db, &resolver, type_ref)
227} 234}
228 235
236fn fn_sig_for_fn(db: &impl HirDatabase, def: Function) -> FnSig {
237 let signature = def.signature(db);
238 let resolver = def.resolver(db);
239 let params =
240 signature.params().iter().map(|tr| Ty::from_hir(db, &resolver, tr)).collect::<Vec<_>>();
241 let ret = Ty::from_hir(db, &resolver, signature.ret_type());
242 FnSig::from_params_and_return(params, ret)
243}
244
229/// Build the declared type of a function. This should not need to look at the 245/// Build the declared type of a function. This should not need to look at the
230/// function body. 246/// function body.
231fn type_for_fn(db: &impl HirDatabase, def: Function) -> Ty { 247fn type_for_fn(db: &impl HirDatabase, def: Function) -> Ty {
232 let signature = def.signature(db);
233 let resolver = def.resolver(db);
234 let generics = def.generic_params(db); 248 let generics = def.generic_params(db);
235 let name = def.name(db);
236 let input =
237 signature.params().iter().map(|tr| Ty::from_hir(db, &resolver, tr)).collect::<Vec<_>>();
238 let output = Ty::from_hir(db, &resolver, signature.ret_type());
239 let sig = Arc::new(FnSig { input, output });
240 let substs = make_substs(&generics); 249 let substs = make_substs(&generics);
241 Ty::FnDef { def: def.into(), sig, name, substs } 250 Ty::FnDef { def: def.into(), substs }
242} 251}
243 252
244/// Build the declared type of a const. 253/// Build the declared type of a const.
@@ -257,44 +266,58 @@ fn type_for_static(db: &impl HirDatabase, def: Static) -> Ty {
257 Ty::from_hir(db, &resolver, signature.type_ref()) 266 Ty::from_hir(db, &resolver, signature.type_ref())
258} 267}
259 268
260/// Build the type of a tuple struct constructor. 269fn fn_sig_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> FnSig {
261fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty {
262 let var_data = def.variant_data(db); 270 let var_data = def.variant_data(db);
263 let fields = match var_data.fields() { 271 let fields = match var_data.fields() {
264 Some(fields) => fields, 272 Some(fields) => fields,
265 None => return type_for_struct(db, def), // Unit struct 273 None => panic!("fn_sig_for_struct_constructor called on unit struct"),
266 }; 274 };
267 let resolver = def.resolver(db); 275 let resolver = def.resolver(db);
268 let generics = def.generic_params(db); 276 let params = fields
269 let name = def.name(db).unwrap_or_else(Name::missing);
270 let input = fields
271 .iter() 277 .iter()
272 .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref)) 278 .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref))
273 .collect::<Vec<_>>(); 279 .collect::<Vec<_>>();
274 let output = type_for_struct(db, def); 280 let ret = type_for_struct(db, def);
275 let sig = Arc::new(FnSig { input, output }); 281 FnSig::from_params_and_return(params, ret)
282}
283
284/// Build the type of a tuple struct constructor.
285fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty {
286 let var_data = def.variant_data(db);
287 if var_data.fields().is_none() {
288 return type_for_struct(db, def); // Unit struct
289 }
290 let generics = def.generic_params(db);
276 let substs = make_substs(&generics); 291 let substs = make_substs(&generics);
277 Ty::FnDef { def: def.into(), sig, name, substs } 292 Ty::FnDef { def: def.into(), substs }
278} 293}
279 294
280/// Build the type of a tuple enum variant constructor. 295fn fn_sig_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariant) -> FnSig {
281fn type_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariant) -> Ty {
282 let var_data = def.variant_data(db); 296 let var_data = def.variant_data(db);
283 let fields = match var_data.fields() { 297 let fields = match var_data.fields() {
284 Some(fields) => fields, 298 Some(fields) => fields,
285 None => return type_for_enum(db, def.parent_enum(db)), // Unit variant 299 None => panic!("fn_sig_for_enum_variant_constructor called for unit variant"),
286 }; 300 };
287 let resolver = def.parent_enum(db).resolver(db); 301 let resolver = def.parent_enum(db).resolver(db);
288 let generics = def.parent_enum(db).generic_params(db); 302 let params = fields
289 let name = def.name(db).unwrap_or_else(Name::missing);
290 let input = fields
291 .iter() 303 .iter()
292 .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref)) 304 .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref))
293 .collect::<Vec<_>>(); 305 .collect::<Vec<_>>();
306 let generics = def.parent_enum(db).generic_params(db);
307 let substs = make_substs(&generics);
308 let ret = type_for_enum(db, def.parent_enum(db)).subst(&substs);
309 FnSig::from_params_and_return(params, ret)
310}
311
312/// Build the type of a tuple enum variant constructor.
313fn type_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariant) -> Ty {
314 let var_data = def.variant_data(db);
315 if var_data.fields().is_none() {
316 return type_for_enum(db, def.parent_enum(db)); // Unit variant
317 }
318 let generics = def.parent_enum(db).generic_params(db);
294 let substs = make_substs(&generics); 319 let substs = make_substs(&generics);
295 let output = type_for_enum(db, def.parent_enum(db)).subst(&substs); 320 Ty::FnDef { def: def.into(), substs }
296 let sig = Arc::new(FnSig { input, output });
297 Ty::FnDef { def: def.into(), sig, name, substs }
298} 321}
299 322
300fn make_substs(generics: &GenericParams) -> Substs { 323fn make_substs(generics: &GenericParams) -> Substs {
@@ -310,20 +333,12 @@ fn make_substs(generics: &GenericParams) -> Substs {
310 333
311fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Ty { 334fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Ty {
312 let generics = s.generic_params(db); 335 let generics = s.generic_params(db);
313 Ty::Adt { 336 Ty::Adt { def_id: s.into(), substs: make_substs(&generics) }
314 def_id: s.into(),
315 name: s.name(db).unwrap_or_else(Name::missing),
316 substs: make_substs(&generics),
317 }
318} 337}
319 338
320fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Ty { 339fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Ty {
321 let generics = s.generic_params(db); 340 let generics = s.generic_params(db);
322 Ty::Adt { 341 Ty::Adt { def_id: s.into(), substs: make_substs(&generics) }
323 def_id: s.into(),
324 name: s.name(db).unwrap_or_else(Name::missing),
325 substs: make_substs(&generics),
326 }
327} 342}
328 343
329fn type_for_type_alias(db: &impl HirDatabase, t: TypeAlias) -> Ty { 344fn type_for_type_alias(db: &impl HirDatabase, t: TypeAlias) -> Ty {
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index 94b757af2..804824868 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -7,10 +7,12 @@ use std::sync::Arc;
7use rustc_hash::FxHashMap; 7use rustc_hash::FxHashMap;
8 8
9use crate::{ 9use crate::{
10 HirDatabase, module_tree::ModuleId, Module, Crate, Name, Function, Trait, 10 HirDatabase, Module, Crate, Name, Function, Trait,
11 ids::TraitId, 11 ids::TraitId,
12 impl_block::{ImplId, ImplBlock, ImplItem}, 12 impl_block::{ImplId, ImplBlock, ImplItem},
13 ty::{AdtDef, Ty}, 13 ty::{AdtDef, Ty},
14 nameres::CrateModuleId,
15
14}; 16};
15 17
16/// This is used as a key for indexing impls. 18/// This is used as a key for indexing impls.
@@ -33,10 +35,10 @@ impl TyFingerprint {
33 35
34#[derive(Debug, PartialEq, Eq)] 36#[derive(Debug, PartialEq, Eq)]
35pub struct CrateImplBlocks { 37pub struct CrateImplBlocks {
36 /// To make sense of the ModuleIds, we need the source root. 38 /// To make sense of the CrateModuleIds, we need the source root.
37 krate: Crate, 39 krate: Crate,
38 impls: FxHashMap<TyFingerprint, Vec<(ModuleId, ImplId)>>, 40 impls: FxHashMap<TyFingerprint, Vec<(CrateModuleId, ImplId)>>,
39 impls_by_trait: FxHashMap<TraitId, Vec<(ModuleId, ImplId)>>, 41 impls_by_trait: FxHashMap<TraitId, Vec<(CrateModuleId, ImplId)>>,
40} 42}
41 43
42impl CrateImplBlocks { 44impl CrateImplBlocks {
diff --git a/crates/ra_hir/src/ty/primitive.rs b/crates/ra_hir/src/ty/primitive.rs
index 5741ca90d..30aeac48e 100644
--- a/crates/ra_hir/src/ty/primitive.rs
+++ b/crates/ra_hir/src/ty/primitive.rs
@@ -10,14 +10,6 @@ pub enum UncertainIntTy {
10} 10}
11 11
12impl UncertainIntTy { 12impl UncertainIntTy {
13 pub fn ty_to_string(&self) -> &'static str {
14 match *self {
15 UncertainIntTy::Unknown => "{integer}",
16 UncertainIntTy::Signed(ty) => ty.ty_to_string(),
17 UncertainIntTy::Unsigned(ty) => ty.ty_to_string(),
18 }
19 }
20
21 pub fn from_name(name: &Name) -> Option<UncertainIntTy> { 13 pub fn from_name(name: &Name) -> Option<UncertainIntTy> {
22 if let Some(ty) = IntTy::from_name(name) { 14 if let Some(ty) = IntTy::from_name(name) {
23 Some(UncertainIntTy::Signed(ty)) 15 Some(UncertainIntTy::Signed(ty))
@@ -29,6 +21,16 @@ impl UncertainIntTy {
29 } 21 }
30} 22}
31 23
24impl fmt::Display for UncertainIntTy {
25 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
26 match *self {
27 UncertainIntTy::Unknown => write!(f, "{{integer}}"),
28 UncertainIntTy::Signed(ty) => write!(f, "{}", ty),
29 UncertainIntTy::Unsigned(ty) => write!(f, "{}", ty),
30 }
31 }
32}
33
32#[derive(Debug, Clone, Eq, PartialEq, Hash, Copy)] 34#[derive(Debug, Clone, Eq, PartialEq, Hash, Copy)]
33pub enum UncertainFloatTy { 35pub enum UncertainFloatTy {
34 Unknown, 36 Unknown,
@@ -36,13 +38,6 @@ pub enum UncertainFloatTy {
36} 38}
37 39
38impl UncertainFloatTy { 40impl UncertainFloatTy {
39 pub fn ty_to_string(&self) -> &'static str {
40 match *self {
41 UncertainFloatTy::Unknown => "{float}",
42 UncertainFloatTy::Known(ty) => ty.ty_to_string(),
43 }
44 }
45
46 pub fn from_name(name: &Name) -> Option<UncertainFloatTy> { 41 pub fn from_name(name: &Name) -> Option<UncertainFloatTy> {
47 if let Some(ty) = FloatTy::from_name(name) { 42 if let Some(ty) = FloatTy::from_name(name) {
48 Some(UncertainFloatTy::Known(ty)) 43 Some(UncertainFloatTy::Known(ty))
@@ -52,6 +47,15 @@ impl UncertainFloatTy {
52 } 47 }
53} 48}
54 49
50impl fmt::Display for UncertainFloatTy {
51 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
52 match *self {
53 UncertainFloatTy::Unknown => write!(f, "{{float}}"),
54 UncertainFloatTy::Known(ty) => write!(f, "{}", ty),
55 }
56 }
57}
58
55#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] 59#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
56pub enum IntTy { 60pub enum IntTy {
57 Isize, 61 Isize,
@@ -70,22 +74,19 @@ impl fmt::Debug for IntTy {
70 74
71impl fmt::Display for IntTy { 75impl fmt::Display for IntTy {
72 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 76 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
73 write!(f, "{}", self.ty_to_string()) 77 let s = match *self {
74 }
75}
76
77impl IntTy {
78 pub fn ty_to_string(&self) -> &'static str {
79 match *self {
80 IntTy::Isize => "isize", 78 IntTy::Isize => "isize",
81 IntTy::I8 => "i8", 79 IntTy::I8 => "i8",
82 IntTy::I16 => "i16", 80 IntTy::I16 => "i16",
83 IntTy::I32 => "i32", 81 IntTy::I32 => "i32",
84 IntTy::I64 => "i64", 82 IntTy::I64 => "i64",
85 IntTy::I128 => "i128", 83 IntTy::I128 => "i128",
86 } 84 };
85 write!(f, "{}", s)
87 } 86 }
87}
88 88
89impl IntTy {
89 pub fn from_name(name: &Name) -> Option<IntTy> { 90 pub fn from_name(name: &Name) -> Option<IntTy> {
90 match name.as_known_name()? { 91 match name.as_known_name()? {
91 KnownName::Isize => Some(IntTy::Isize), 92 KnownName::Isize => Some(IntTy::Isize),
@@ -109,18 +110,21 @@ pub enum UintTy {
109 U128, 110 U128,
110} 111}
111 112
112impl UintTy { 113impl fmt::Display for UintTy {
113 pub fn ty_to_string(&self) -> &'static str { 114 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
114 match *self { 115 let s = match *self {
115 UintTy::Usize => "usize", 116 UintTy::Usize => "usize",
116 UintTy::U8 => "u8", 117 UintTy::U8 => "u8",
117 UintTy::U16 => "u16", 118 UintTy::U16 => "u16",
118 UintTy::U32 => "u32", 119 UintTy::U32 => "u32",
119 UintTy::U64 => "u64", 120 UintTy::U64 => "u64",
120 UintTy::U128 => "u128", 121 UintTy::U128 => "u128",
121 } 122 };
123 write!(f, "{}", s)
122 } 124 }
125}
123 126
127impl UintTy {
124 pub fn from_name(name: &Name) -> Option<UintTy> { 128 pub fn from_name(name: &Name) -> Option<UintTy> {
125 match name.as_known_name()? { 129 match name.as_known_name()? {
126 KnownName::Usize => Some(UintTy::Usize), 130 KnownName::Usize => Some(UintTy::Usize),
@@ -140,12 +144,6 @@ impl fmt::Debug for UintTy {
140 } 144 }
141} 145}
142 146
143impl fmt::Display for UintTy {
144 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
145 write!(f, "{}", self.ty_to_string())
146 }
147}
148
149#[derive(Clone, PartialEq, Eq, Hash, Copy, PartialOrd, Ord)] 147#[derive(Clone, PartialEq, Eq, Hash, Copy, PartialOrd, Ord)]
150pub enum FloatTy { 148pub enum FloatTy {
151 F32, 149 F32,
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index c7d409e6d..0f2172ddf 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -10,6 +10,7 @@ use test_utils::covers;
10use crate::{ 10use crate::{
11 source_binder, 11 source_binder,
12 mock::MockDatabase, 12 mock::MockDatabase,
13 ty::display::HirDisplay,
13}; 14};
14 15
15// These tests compare the inference results for all expressions in a file 16// These tests compare the inference results for all expressions in a file
@@ -830,6 +831,60 @@ fn test(x: &i32) {
830} 831}
831 832
832#[test] 833#[test]
834fn infer_pattern_match_ergonomics() {
835 assert_snapshot_matches!(
836 infer(r#"
837struct A<T>(T);
838
839fn test() {
840 let A(n) = &A(1);
841 let A(n) = &mut A(1);
842}
843"#),
844 @r###"
845[28; 79) '{ ...(1); }': ()
846[38; 42) 'A(n)': A<i32>
847[40; 41) 'n': &i32
848[45; 50) '&A(1)': &A<i32>
849[46; 47) 'A': A<i32>(T) -> A<T>
850[46; 50) 'A(1)': A<i32>
851[48; 49) '1': i32
852[60; 64) 'A(n)': A<i32>
853[62; 63) 'n': &mut i32
854[67; 76) '&mut A(1)': &mut A<i32>
855[72; 73) 'A': A<i32>(T) -> A<T>
856[72; 76) 'A(1)': A<i32>
857[74; 75) '1': i32"###
858 );
859}
860
861#[test]
862fn infer_pattern_match_ergonomics_ref() {
863 covers!(match_ergonomics_ref);
864 assert_snapshot_matches!(
865 infer(r#"
866fn test() {
867 let v = &(1, &2);
868 let (_, &w) = v;
869}
870"#),
871 @r###"
872[11; 57) '{ ...= v; }': ()
873[21; 22) 'v': &(i32, &i32)
874[25; 33) '&(1, &2)': &(i32, &i32)
875[26; 33) '(1, &2)': (i32, &i32)
876[27; 28) '1': i32
877[30; 32) '&2': &i32
878[31; 32) '2': i32
879[43; 50) '(_, &w)': (i32, &i32)
880[44; 45) '_': i32
881[47; 49) '&w': &i32
882[48; 49) 'w': i32
883[53; 54) 'v': &(i32, &i32)"###
884 );
885}
886
887#[test]
833fn infer_adt_pattern() { 888fn infer_adt_pattern() {
834 assert_snapshot_matches!( 889 assert_snapshot_matches!(
835 infer(r#" 890 infer(r#"
@@ -2142,7 +2197,7 @@ fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
2142 let node = algo::find_node_at_offset::<ast::Expr>(syntax.syntax(), pos.offset).unwrap(); 2197 let node = algo::find_node_at_offset::<ast::Expr>(syntax.syntax(), pos.offset).unwrap();
2143 let expr = body_source_map.node_expr(node).unwrap(); 2198 let expr = body_source_map.node_expr(node).unwrap();
2144 let ty = &inference_result[expr]; 2199 let ty = &inference_result[expr];
2145 ty.to_string() 2200 ty.display(db).to_string()
2146} 2201}
2147 2202
2148fn infer(content: &str) -> String { 2203fn infer(content: &str) -> String {
@@ -2178,7 +2233,7 @@ fn infer(content: &str) -> String {
2178 "{} '{}': {}\n", 2233 "{} '{}': {}\n",
2179 syntax_ptr.range(), 2234 syntax_ptr.range(),
2180 ellipsize(node.text().to_string().replace("\n", " "), 15), 2235 ellipsize(node.text().to_string().replace("\n", " "), 15),
2181 ty 2236 ty.display(&db)
2182 ) 2237 )
2183 .unwrap(); 2238 .unwrap();
2184 } 2239 }