From 9c2d83a4c809b0b11ca389bb454e197859e5116c Mon Sep 17 00:00:00 2001 From: Marcus Klaas de Vries Date: Wed, 16 Jan 2019 17:47:59 +0100 Subject: Add crude implementation of tuplestruct pattern inference --- crates/ra_hir/src/ty.rs | 81 +++++++++++++++++-------- crates/ra_hir/src/ty/tests.rs | 36 ++++++----- crates/ra_hir/src/ty/tests/data/adt_pattern.txt | 12 ++++ 3 files changed, 89 insertions(+), 40 deletions(-) create mode 100644 crates/ra_hir/src/ty/tests/data/adt_pattern.txt 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> { 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) { + let ty = match (&body[pat], &expected.ty) { (Pat::Tuple(ref args), &Ty::Tuple(ref tuple_args)) if args.len() == tuple_args.len() => { @@ -885,42 +885,71 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { // FIXME: can we do w/o cloning? self.infer_pat(pat, &Expectation::has_type(ty.clone())); } + expected.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())); + expected.ty.clone() } - (pattern, &Ty::Adt { def_id, .. }) => { - let adt_def = def_id.resolve(self.db); - match (pattern, adt_def) { - (&Pat::Struct, Def::Struct(s)) => {} - ( - &Pat::TupleStruct { - path: ref p, - args: ref sub_pats, - }, - Def::Enum(ref e), - ) => { - // TODO: resolve enum - } - ( - &Pat::TupleStruct { - path: ref p, - args: ref sub_pats, - }, - Def::EnumVariant(ref e), - ) => { - let variant_data = self.db.enum_variant_data(e.def_id); + ( + &Pat::TupleStruct { + path: ref p, + args: ref sub_pats, + }, + _expected, + ) => { + let def = p + .as_ref() + .and_then(|path| self.module.resolve_path(self.db, &path).take_types()) + .map(|def_id| def_id.resolve(self.db)); + + if let Some(def) = def { + let (ty, fields) = match def { + Def::Struct(s) => { + let fields: Vec<_> = self + .db + .struct_data(s.def_id()) + .variant_data + .fields() + .iter() + .cloned() + .collect(); + (type_for_struct(self.db, s), fields) + } + Def::EnumVariant(ev) => { + let fields: Vec<_> = + ev.variant_data(self.db).fields().iter().cloned().collect(); + (type_for_enum_variant(self.db, ev), fields) + } + _ => unreachable!(), + }; + // walk subpats + if fields.len() == sub_pats.len() { + for (&sub_pat, field) in sub_pats.iter().zip(fields.iter()) { + let sub_ty = Ty::from_hir( + self.db, + &self.module, + self.impl_block.as_ref(), + &field.type_ref, + ); + + self.infer_pat(sub_pat, &Expectation::has_type(sub_ty)); + } + + ty + } else { + expected.ty.clone() } - _ => {} + } else { + expected.ty.clone() } } - // TODO: implement more - (_, ref _expected_ty) => {} + (_, ref _expected_ty) => expected.ty.clone(), }; // use a new type variable if we got Ty::Unknown here - let ty = self.insert_type_vars_shallow(expected.ty.clone()); + let ty = self.insert_type_vars_shallow(ty); self.unify(&ty, &expected.ty); let ty = self.resolve_ty_as_possible(ty); 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) { } #[test] -fn infer_pattern() { +fn infer_simple_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"); +} +"#, + "pattern.txt", + ); +} + +#[test] +fn infer_adt_pattern() { + check_inference( + r#" +enum E { + A { x: usize }, + B +} + +struct S(u32, E); +fn test() { let e = E::A { x: 3 }; - if let E::A { x: x } = e { - x - }; - match e { - E::A { x } => x, - E::B => 1, - }; + + let S(y, z) = foo; + let E::A { x: new_var } = e; } "#, - "pattern.txt", + "adt_pattern.txt", ); } 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 @@ +[49; 192) '{ ... }; }': () +[59; 60) 'e': E +[63; 76) 'E::A { x: 3 }': E +[73; 74) '3': usize +[82; 124) 'if let... }': [unknown] +[105; 106) 'e': E +[107; 124) '{ ... }': [unknown] +[117; 118) 'x': [unknown] +[130; 189) 'match ... }': [unknown] +[136; 137) 'e': E +[162; 163) 'x': [unknown] +[181; 182) '1': i32 -- cgit v1.2.3