diff options
-rw-r--r-- | crates/ra_hir/src/ty.rs | 81 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 36 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests/data/adt_pattern.txt | 12 |
3 files changed, 89 insertions, 40 deletions
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index a13356714..cdecbd064 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -877,7 +877,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
877 | fn infer_pat(&mut self, pat: PatId, expected: &Expectation) -> Ty { | 877 | fn infer_pat(&mut self, pat: PatId, expected: &Expectation) -> Ty { |
878 | let body = Arc::clone(&self.body); // avoid borrow checker problem | 878 | let body = Arc::clone(&self.body); // avoid borrow checker problem |
879 | 879 | ||
880 | match (&body[pat], &expected.ty) { | 880 | let ty = match (&body[pat], &expected.ty) { |
881 | (Pat::Tuple(ref args), &Ty::Tuple(ref tuple_args)) | 881 | (Pat::Tuple(ref args), &Ty::Tuple(ref tuple_args)) |
882 | if args.len() == tuple_args.len() => | 882 | if args.len() == tuple_args.len() => |
883 | { | 883 | { |
@@ -885,42 +885,71 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
885 | // FIXME: can we do w/o cloning? | 885 | // FIXME: can we do w/o cloning? |
886 | self.infer_pat(pat, &Expectation::has_type(ty.clone())); | 886 | self.infer_pat(pat, &Expectation::has_type(ty.clone())); |
887 | } | 887 | } |
888 | expected.ty.clone() | ||
888 | } | 889 | } |
889 | (&Pat::Ref { pat, mutability }, &Ty::Ref(ref sub_ty, ty_mut)) | 890 | (&Pat::Ref { pat, mutability }, &Ty::Ref(ref sub_ty, ty_mut)) |
890 | if mutability == ty_mut => | 891 | if mutability == ty_mut => |
891 | { | 892 | { |
892 | self.infer_pat(pat, &Expectation::has_type((&**sub_ty).clone())); | 893 | self.infer_pat(pat, &Expectation::has_type((&**sub_ty).clone())); |
894 | expected.ty.clone() | ||
893 | } | 895 | } |
894 | (pattern, &Ty::Adt { def_id, .. }) => { | 896 | ( |
895 | let adt_def = def_id.resolve(self.db); | 897 | &Pat::TupleStruct { |
896 | match (pattern, adt_def) { | 898 | path: ref p, |
897 | (&Pat::Struct, Def::Struct(s)) => {} | 899 | args: ref sub_pats, |
898 | ( | 900 | }, |
899 | &Pat::TupleStruct { | 901 | _expected, |
900 | path: ref p, | 902 | ) => { |
901 | args: ref sub_pats, | 903 | let def = p |
902 | }, | 904 | .as_ref() |
903 | Def::Enum(ref e), | 905 | .and_then(|path| self.module.resolve_path(self.db, &path).take_types()) |
904 | ) => { | 906 | .map(|def_id| def_id.resolve(self.db)); |
905 | // TODO: resolve enum | 907 | |
906 | } | 908 | if let Some(def) = def { |
907 | ( | 909 | let (ty, fields) = match def { |
908 | &Pat::TupleStruct { | 910 | Def::Struct(s) => { |
909 | path: ref p, | 911 | let fields: Vec<_> = self |
910 | args: ref sub_pats, | 912 | .db |
911 | }, | 913 | .struct_data(s.def_id()) |
912 | Def::EnumVariant(ref e), | 914 | .variant_data |
913 | ) => { | 915 | .fields() |
914 | let variant_data = self.db.enum_variant_data(e.def_id); | 916 | .iter() |
917 | .cloned() | ||
918 | .collect(); | ||
919 | (type_for_struct(self.db, s), fields) | ||
920 | } | ||
921 | Def::EnumVariant(ev) => { | ||
922 | let fields: Vec<_> = | ||
923 | ev.variant_data(self.db).fields().iter().cloned().collect(); | ||
924 | (type_for_enum_variant(self.db, ev), fields) | ||
925 | } | ||
926 | _ => unreachable!(), | ||
927 | }; | ||
928 | // walk subpats | ||
929 | if fields.len() == sub_pats.len() { | ||
930 | for (&sub_pat, field) in sub_pats.iter().zip(fields.iter()) { | ||
931 | let sub_ty = Ty::from_hir( | ||
932 | self.db, | ||
933 | &self.module, | ||
934 | self.impl_block.as_ref(), | ||
935 | &field.type_ref, | ||
936 | ); | ||
937 | |||
938 | self.infer_pat(sub_pat, &Expectation::has_type(sub_ty)); | ||
939 | } | ||
940 | |||
941 | ty | ||
942 | } else { | ||
943 | expected.ty.clone() | ||
915 | } | 944 | } |
916 | _ => {} | 945 | } else { |
946 | expected.ty.clone() | ||
917 | } | 947 | } |
918 | } | 948 | } |
919 | // TODO: implement more | 949 | (_, ref _expected_ty) => expected.ty.clone(), |
920 | (_, ref _expected_ty) => {} | ||
921 | }; | 950 | }; |
922 | // use a new type variable if we got Ty::Unknown here | 951 | // use a new type variable if we got Ty::Unknown here |
923 | let ty = self.insert_type_vars_shallow(expected.ty.clone()); | 952 | let ty = self.insert_type_vars_shallow(ty); |
924 | self.unify(&ty, &expected.ty); | 953 | self.unify(&ty, &expected.ty); |
925 | let ty = self.resolve_ty_as_possible(ty); | 954 | let ty = self.resolve_ty_as_possible(ty); |
926 | self.write_pat_ty(pat, ty.clone()); | 955 | self.write_pat_ty(pat, ty.clone()); |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index ff2c8b0d4..75fe2cc6e 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -359,31 +359,39 @@ fn test(x: &str, y: isize) { | |||
359 | } | 359 | } |
360 | 360 | ||
361 | #[test] | 361 | #[test] |
362 | fn infer_pattern() { | 362 | fn infer_simple_pattern() { |
363 | check_inference( | 363 | check_inference( |
364 | r#" | 364 | r#" |
365 | enum E { | ||
366 | A { x: usize }, | ||
367 | B | ||
368 | } | ||
369 | |||
370 | fn test(x: &i32) { | 365 | fn test(x: &i32) { |
371 | let y = x; | 366 | let y = x; |
372 | let &z = x; | 367 | let &z = x; |
373 | let a = z; | 368 | let a = z; |
374 | let (c, d) = (1, "hello"); | 369 | let (c, d) = (1, "hello"); |
370 | } | ||
371 | "#, | ||
372 | "pattern.txt", | ||
373 | ); | ||
374 | } | ||
375 | |||
376 | #[test] | ||
377 | fn infer_adt_pattern() { | ||
378 | check_inference( | ||
379 | r#" | ||
380 | enum E { | ||
381 | A { x: usize }, | ||
382 | B | ||
383 | } | ||
384 | |||
385 | struct S(u32, E); | ||
375 | 386 | ||
387 | fn test() { | ||
376 | let e = E::A { x: 3 }; | 388 | let e = E::A { x: 3 }; |
377 | if let E::A { x: x } = e { | 389 | |
378 | x | 390 | let S(y, z) = foo; |
379 | }; | 391 | let E::A { x: new_var } = e; |
380 | match e { | ||
381 | E::A { x } => x, | ||
382 | E::B => 1, | ||
383 | }; | ||
384 | } | 392 | } |
385 | "#, | 393 | "#, |
386 | "pattern.txt", | 394 | "adt_pattern.txt", |
387 | ); | 395 | ); |
388 | } | 396 | } |
389 | 397 | ||
diff --git a/crates/ra_hir/src/ty/tests/data/adt_pattern.txt b/crates/ra_hir/src/ty/tests/data/adt_pattern.txt new file mode 100644 index 000000000..d23b865a0 --- /dev/null +++ b/crates/ra_hir/src/ty/tests/data/adt_pattern.txt | |||
@@ -0,0 +1,12 @@ | |||
1 | [49; 192) '{ ... }; }': () | ||
2 | [59; 60) 'e': E | ||
3 | [63; 76) 'E::A { x: 3 }': E | ||
4 | [73; 74) '3': usize | ||
5 | [82; 124) 'if let... }': [unknown] | ||
6 | [105; 106) 'e': E | ||
7 | [107; 124) '{ ... }': [unknown] | ||
8 | [117; 118) 'x': [unknown] | ||
9 | [130; 189) 'match ... }': [unknown] | ||
10 | [136; 137) 'e': E | ||
11 | [162; 163) 'x': [unknown] | ||
12 | [181; 182) '1': i32 | ||