diff options
Diffstat (limited to 'crates/ra_hir/src/ty.rs')
-rw-r--r-- | crates/ra_hir/src/ty.rs | 143 |
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 |