From 5648dcd36e65dde9c8f41884eed64a7e1a1d2073 Mon Sep 17 00:00:00 2001 From: Marcus Klaas de Vries Date: Tue, 15 Jan 2019 18:47:37 +0100 Subject: Implement type inference for tuples and refs --- crates/ra_hir/src/ty.rs | 39 +++++++++++++++++++++++------ crates/ra_hir/src/ty/tests.rs | 11 ++++++++ crates/ra_hir/src/ty/tests/data/pattern.txt | 15 +++++++++++ 3 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 crates/ra_hir/src/ty/tests/data/pattern.txt 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::{ db::HirDatabase, type_ref::{TypeRef, Mutability}, name::KnownName, - expr::{Body, Expr, Literal, ExprId, PatId, UnaryOp, BinaryOp, Statement}, + expr::{Body, Expr, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement}, }; /// The ID of a type variable. @@ -872,6 +872,35 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } } + // FIXME: Expectation should probably contain a reference to a Ty instead of + // a Ty itself + fn infer_pat(&mut self, pat: PatId, expected: &Expectation) -> Ty { + let body = Arc::clone(&self.body); // avoid borrow checker problem + match (&body[pat], &expected.ty) { + (Pat::Tuple(ref args), &Ty::Tuple(ref tuple_args)) + if args.len() == tuple_args.len() => + { + for (&pat, ty) in args.iter().zip(tuple_args.iter()) { + // FIXME: can we do w/o cloning? + self.infer_pat(pat, &Expectation::has_type(ty.clone())); + } + } + (&Pat::Ref { pat, mutability }, &Ty::Ref(ref sub_ty, ty_mut)) + if mutability == ty_mut => + { + self.infer_pat(pat, &Expectation::has_type((&**sub_ty).clone())); + } + // TODO: implement more + (_, ref _expected_ty) => {} + }; + // use a new type variable if we got Ty::Unknown here + let ty = self.insert_type_vars_shallow(expected.ty.clone()); + self.unify(&ty, &expected.ty); + let ty = self.resolve_ty_as_possible(ty); + self.write_pat_ty(pat, ty.clone()); + ty + } + fn infer_expr(&mut self, expr: ExprId, expected: &Expectation) -> Ty { let body = Arc::clone(&self.body); // avoid borrow checker problem let ty = match &body[expr] { @@ -1168,9 +1197,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { decl_ty }; - // TODO: walk the pattern here? - - self.write_pat_ty(*pat, ty); + self.infer_pat(*pat, &Expectation::has_type(ty))?; } Statement::Expr(expr) => { self.infer_expr(*expr, &Expectation::none()); @@ -1191,9 +1218,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let ty = self.make_ty(type_ref); let ty = self.insert_type_vars(ty); - // TODO: walk pattern? - - self.write_pat_ty(*pat, ty); + self.infer_pat(*pat, &Expectation::has_type(ty))?; } self.return_ty = { 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) { fn infer_pattern() { check_inference( r#" +enum E { A { x: usize }, B } + fn test(x: &i32) { let y = x; let &z = x; let a = z; let (c, d) = (1, "hello"); + + let e = E::A { x: 3 }; + if let E::A { x: x } = e { + x + }; + match e { + E::A { x } => x, + E::B => 1, + }; } "#, "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 @@ +[9; 10) 'x': &i32 +[18; 98) '{ ...o"); }': () +[28; 29) 'y': &i32 +[32; 33) 'x': &i32 +[43; 45) '&z': &i32 +[44; 45) 'z': i32 +[48; 49) 'x': &i32 +[59; 60) 'a': i32 +[63; 64) 'z': i32 +[74; 80) '(c, d)': (i32, &str) +[75; 76) 'c': i32 +[78; 79) 'd': &str +[83; 95) '(1, "hello")': (i32, &str) +[84; 85) '1': i32 +[87; 94) '"hello"': &str -- cgit v1.2.3