aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty.rs
diff options
context:
space:
mode:
authorMarcus Klaas de Vries <[email protected]>2019-01-16 19:26:58 +0000
committerAleksey Kladov <[email protected]>2019-01-19 12:37:25 +0000
commit3340807bd24f398dca158e85eebae74012d8ef4b (patch)
treed0f94210a723ddbdcdfa9c64e66d59c68b52caca /crates/ra_hir/src/ty.rs
parentab5deb78117693d776723bc0144e7b34e6f782d1 (diff)
Get basic struct pattern type inference working!
Diffstat (limited to 'crates/ra_hir/src/ty.rs')
-rw-r--r--crates/ra_hir/src/ty.rs143
1 files changed, 94 insertions, 49 deletions
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index 3e1a4f02e..6bad61a2a 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -36,7 +36,7 @@ use crate::{
36 db::HirDatabase, 36 db::HirDatabase,
37 type_ref::{TypeRef, Mutability}, 37 type_ref::{TypeRef, Mutability},
38 name::KnownName, 38 name::KnownName,
39 expr::{Body, Expr, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement}, 39 expr::{Body, Expr, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat},
40}; 40};
41 41
42/// The ID of a type variable. 42/// The ID of a type variable.
@@ -872,6 +872,90 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
872 } 872 }
873 } 873 }
874 874
875 fn resolve_fields(&self, path: Option<&Path>) -> Option<(Ty, Vec<crate::adt::StructField>)> {
876 let def = path
877 .and_then(|path| self.module.resolve_path(self.db, &path).take_types())
878 .map(|def_id| def_id.resolve(self.db));
879
880 let def = if let Some(def) = def {
881 def
882 } else {
883 return None;
884 };
885
886 match def {
887 Def::Struct(s) => {
888 let fields: Vec<_> = self
889 .db
890 .struct_data(s.def_id())
891 .variant_data
892 .fields()
893 .iter()
894 .cloned()
895 .collect();
896 Some((type_for_struct(self.db, s), fields))
897 }
898 Def::EnumVariant(ev) => {
899 let fields: Vec<_> = ev.variant_data(self.db).fields().iter().cloned().collect();
900 Some((type_for_enum_variant(self.db, ev), fields))
901 }
902 _ => None,
903 }
904 }
905
906 fn infer_tuple_struct(&mut self, path: Option<&Path>, sub_pats: &[PatId]) -> Ty {
907 let (ty, fields) = if let Some(x) = self.resolve_fields(path) {
908 x
909 } else {
910 return Ty::Unknown;
911 };
912
913 // walk subpats
914 if fields.len() != sub_pats.len() {
915 return Ty::Unknown;
916 }
917
918 for (&sub_pat, field) in sub_pats.iter().zip(fields.iter()) {
919 let sub_ty = Ty::from_hir(
920 self.db,
921 &self.module,
922 self.impl_block.as_ref(),
923 &field.type_ref,
924 );
925
926 self.infer_pat(sub_pat, &Expectation::has_type(sub_ty));
927 }
928
929 ty
930 }
931
932 fn infer_struct(&mut self, path: Option<&Path>, sub_pats: &[FieldPat]) -> Ty {
933 let (ty, fields) = if let Some(x) = self.resolve_fields(path) {
934 x
935 } else {
936 return Ty::Unknown;
937 };
938
939 for sub_pat in sub_pats {
940 let tyref = fields
941 .iter()
942 .find(|field| field.name == sub_pat.name)
943 .map(|field| &field.type_ref);
944
945 if let Some(typeref) = tyref {
946 let sub_ty = Ty::from_hir(self.db, &self.module, self.impl_block.as_ref(), typeref);
947
948 if let Some(pat) = sub_pat.pat {
949 self.infer_pat(pat, &Expectation::has_type(sub_ty));
950 } else {
951 // TODO: deal with this case: S { x, y }
952 }
953 }
954 }
955
956 ty
957 }
958
875 // FIXME: Expectation should probably contain a reference to a Ty instead of 959 // FIXME: Expectation should probably contain a reference to a Ty instead of
876 // a Ty itself 960 // a Ty itself
877 fn infer_pat(&mut self, pat: PatId, expected: &Expectation) -> Ty { 961 fn infer_pat(&mut self, pat: PatId, expected: &Expectation) -> Ty {
@@ -900,54 +984,15 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
900 path: ref p, 984 path: ref p,
901 args: ref sub_pats, 985 args: ref sub_pats,
902 }, 986 },
903 _expected, 987 _,
904 ) => { 988 ) => self.infer_tuple_struct(p.as_ref(), sub_pats),
905 let def = p 989 (
906 .as_ref() 990 &Pat::Struct {
907 .and_then(|path| self.module.resolve_path(self.db, &path).take_types()) 991 path: ref p,
908 .map(|def_id| def_id.resolve(self.db)); 992 args: ref fields,
909 993 },
910 if let Some(def) = def { 994 _,
911 let (ty, fields) = match def { 995 ) => self.infer_struct(p.as_ref(), fields),
912 Def::Struct(s) => {
913 let fields: Vec<_> = self
914 .db
915 .struct_data(s.def_id())
916 .variant_data
917 .fields()
918 .iter()
919 .cloned()
920 .collect();
921 (type_for_struct(self.db, s), fields)
922 }
923 Def::EnumVariant(ev) => {
924 let fields: Vec<_> =
925 ev.variant_data(self.db).fields().iter().cloned().collect();
926 (type_for_enum_variant(self.db, ev), fields)
927 }
928 _ => unreachable!(),
929 };
930 // walk subpats
931 if fields.len() == sub_pats.len() {
932 for (&sub_pat, field) in sub_pats.iter().zip(fields.iter()) {
933 let sub_ty = Ty::from_hir(
934 self.db,
935 &self.module,
936 self.impl_block.as_ref(),
937 &field.type_ref,
938 );
939
940 self.infer_pat(sub_pat, &Expectation::has_type(sub_ty));
941 }
942
943 ty
944 } else {
945 expected.ty.clone()
946 }
947 } else {
948 expected.ty.clone()
949 }
950 }
951 (_, ref _expected_ty) => expected.ty.clone(), 996 (_, ref _expected_ty) => expected.ty.clone(),
952 }; 997 };
953 // use a new type variable if we got Ty::Unknown here 998 // use a new type variable if we got Ty::Unknown here