diff options
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/ty.rs | 39 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 11 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests/data/pattern.txt | 15 |
3 files changed, 58 insertions, 7 deletions
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 854d3e3d9..324df5ef9 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, PatId, UnaryOp, BinaryOp, Statement}, | 39 | expr::{Body, Expr, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement}, |
40 | }; | 40 | }; |
41 | 41 | ||
42 | /// The ID of a type variable. | 42 | /// The ID of a type variable. |
@@ -872,6 +872,35 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
872 | } | 872 | } |
873 | } | 873 | } |
874 | 874 | ||
875 | // FIXME: Expectation should probably contain a reference to a Ty instead of | ||
876 | // a Ty itself | ||
877 | fn infer_pat(&mut self, pat: PatId, expected: &Expectation) -> Ty { | ||
878 | let body = Arc::clone(&self.body); // avoid borrow checker problem | ||
879 | match (&body[pat], &expected.ty) { | ||
880 | (Pat::Tuple(ref args), &Ty::Tuple(ref tuple_args)) | ||
881 | if args.len() == tuple_args.len() => | ||
882 | { | ||
883 | for (&pat, ty) in args.iter().zip(tuple_args.iter()) { | ||
884 | // FIXME: can we do w/o cloning? | ||
885 | self.infer_pat(pat, &Expectation::has_type(ty.clone())); | ||
886 | } | ||
887 | } | ||
888 | (&Pat::Ref { pat, mutability }, &Ty::Ref(ref sub_ty, ty_mut)) | ||
889 | if mutability == ty_mut => | ||
890 | { | ||
891 | self.infer_pat(pat, &Expectation::has_type((&**sub_ty).clone())); | ||
892 | } | ||
893 | // TODO: implement more | ||
894 | (_, ref _expected_ty) => {} | ||
895 | }; | ||
896 | // use a new type variable if we got Ty::Unknown here | ||
897 | let ty = self.insert_type_vars_shallow(expected.ty.clone()); | ||
898 | self.unify(&ty, &expected.ty); | ||
899 | let ty = self.resolve_ty_as_possible(ty); | ||
900 | self.write_pat_ty(pat, ty.clone()); | ||
901 | ty | ||
902 | } | ||
903 | |||
875 | fn infer_expr(&mut self, expr: ExprId, expected: &Expectation) -> Ty { | 904 | fn infer_expr(&mut self, expr: ExprId, expected: &Expectation) -> Ty { |
876 | let body = Arc::clone(&self.body); // avoid borrow checker problem | 905 | let body = Arc::clone(&self.body); // avoid borrow checker problem |
877 | let ty = match &body[expr] { | 906 | let ty = match &body[expr] { |
@@ -1168,9 +1197,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1168 | decl_ty | 1197 | decl_ty |
1169 | }; | 1198 | }; |
1170 | 1199 | ||
1171 | // TODO: walk the pattern here? | 1200 | self.infer_pat(*pat, &Expectation::has_type(ty))?; |
1172 | |||
1173 | self.write_pat_ty(*pat, ty); | ||
1174 | } | 1201 | } |
1175 | Statement::Expr(expr) => { | 1202 | Statement::Expr(expr) => { |
1176 | self.infer_expr(*expr, &Expectation::none()); | 1203 | self.infer_expr(*expr, &Expectation::none()); |
@@ -1191,9 +1218,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1191 | let ty = self.make_ty(type_ref); | 1218 | let ty = self.make_ty(type_ref); |
1192 | let ty = self.insert_type_vars(ty); | 1219 | let ty = self.insert_type_vars(ty); |
1193 | 1220 | ||
1194 | // TODO: walk pattern? | 1221 | self.infer_pat(*pat, &Expectation::has_type(ty))?; |
1195 | |||
1196 | self.write_pat_ty(*pat, ty); | ||
1197 | } | 1222 | } |
1198 | self.return_ty = { | 1223 | self.return_ty = { |
1199 | let ty = self.make_ty(signature.ret_type()); | 1224 | let ty = self.make_ty(signature.ret_type()); |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index fc1e5b09c..a55551cbb 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -362,11 +362,22 @@ fn test(x: &str, y: isize) { | |||
362 | fn infer_pattern() { | 362 | fn infer_pattern() { |
363 | check_inference( | 363 | check_inference( |
364 | r#" | 364 | r#" |
365 | enum E { A { x: usize }, B } | ||
366 | |||
365 | fn test(x: &i32) { | 367 | fn test(x: &i32) { |
366 | let y = x; | 368 | let y = x; |
367 | let &z = x; | 369 | let &z = x; |
368 | let a = z; | 370 | let a = z; |
369 | let (c, d) = (1, "hello"); | 371 | let (c, d) = (1, "hello"); |
372 | |||
373 | let e = E::A { x: 3 }; | ||
374 | if let E::A { x: x } = e { | ||
375 | x | ||
376 | }; | ||
377 | match e { | ||
378 | E::A { x } => x, | ||
379 | E::B => 1, | ||
380 | }; | ||
370 | } | 381 | } |
371 | "#, | 382 | "#, |
372 | "pattern.txt", | 383 | "pattern.txt", |
diff --git a/crates/ra_hir/src/ty/tests/data/pattern.txt b/crates/ra_hir/src/ty/tests/data/pattern.txt new file mode 100644 index 000000000..cca521833 --- /dev/null +++ b/crates/ra_hir/src/ty/tests/data/pattern.txt | |||
@@ -0,0 +1,15 @@ | |||
1 | [9; 10) 'x': &i32 | ||
2 | [18; 98) '{ ...o"); }': () | ||
3 | [28; 29) 'y': &i32 | ||
4 | [32; 33) 'x': &i32 | ||
5 | [43; 45) '&z': &i32 | ||
6 | [44; 45) 'z': i32 | ||
7 | [48; 49) 'x': &i32 | ||
8 | [59; 60) 'a': i32 | ||
9 | [63; 64) 'z': i32 | ||
10 | [74; 80) '(c, d)': (i32, &str) | ||
11 | [75; 76) 'c': i32 | ||
12 | [78; 79) 'd': &str | ||
13 | [83; 95) '(1, "hello")': (i32, &str) | ||
14 | [84; 85) '1': i32 | ||
15 | [87; 94) '"hello"': &str | ||