From 9433a108cfcf3a9c7de9299d6641a5abf9031a17 Mon Sep 17 00:00:00 2001 From: Marcus Klaas de Vries Date: Thu, 17 Jan 2019 10:54:47 +0100 Subject: Make pattern inference work w/o proper expecations --- crates/ra_hir/src/ty.rs | 72 +++++++++++++++-------------- crates/ra_hir/src/ty/tests/data/pattern.txt | 26 ++++++++++- 2 files changed, 63 insertions(+), 35 deletions(-) diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 75794b732..8ad80990e 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -911,7 +911,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { return Ty::Unknown; }; - // walk subpats if fields.len() != sub_pats.len() { return Ty::Unknown; } @@ -944,44 +943,49 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { ty } - // FIXME: Expectation should probably contain a reference to a Ty instead of - // a Ty itself + // TODO: Expectation should probably contain a Cow pointer to Ty? + // so that we can make new expectations of subtypes cheaply fn infer_pat(&mut self, pat: PatId, expected: &Expectation) -> Ty { let body = Arc::clone(&self.body); // avoid borrow checker problem - // FIXME: we can do some inference even if the expected ty isnt already - // of the right form - let ty = 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())); - } - expected.ty.clone() + let ty = match &body[pat] { + Pat::Tuple(ref args) => { + // this can probably be done without cloning/ collecting + let expectations = match expected.ty { + Ty::Tuple(ref tuple_args) if args.len() == tuple_args.len() => { + tuple_args.iter().cloned().collect() + } + _ => vec![Ty::Unknown; args.len()], + }; + + let inner_tys = args + .iter() + .zip(expectations.into_iter()) + .map(|(&pat, ty)| self.infer_pat(pat, &Expectation::has_type(ty))) + .collect::>() + .into(); + + Ty::Tuple(inner_tys) } - (&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() + Pat::Ref { pat, mutability } => { + let expectation = match expected.ty { + Ty::Ref(ref sub_ty, exp_mut) if *mutability == exp_mut => { + Expectation::has_type((&**sub_ty).clone()) + } + _ => Expectation::none(), + }; + let subty = self.infer_pat(*pat, &expectation); + Ty::Ref(subty.into(), *mutability) } - ( - &Pat::TupleStruct { - path: ref p, - args: ref sub_pats, - }, - _, - ) => self.infer_tuple_struct(p.as_ref(), sub_pats), - ( - &Pat::Struct { - path: ref p, - args: ref fields, - }, - _, - ) => self.infer_struct(p.as_ref(), fields), - (_, ref _expected_ty) => expected.ty.clone(), + Pat::TupleStruct { + path: ref p, + args: ref sub_pats, + } => self.infer_tuple_struct(p.as_ref(), sub_pats), + Pat::Struct { + path: ref p, + args: ref fields, + } => self.infer_struct(p.as_ref(), fields), + _ => Ty::Unknown, }; // use a new type variable if we got Ty::Unknown here let ty = self.insert_type_vars_shallow(ty); diff --git a/crates/ra_hir/src/ty/tests/data/pattern.txt b/crates/ra_hir/src/ty/tests/data/pattern.txt index cca521833..8b7c967c4 100644 --- a/crates/ra_hir/src/ty/tests/data/pattern.txt +++ b/crates/ra_hir/src/ty/tests/data/pattern.txt @@ -1,5 +1,5 @@ [9; 10) 'x': &i32 -[18; 98) '{ ...o"); }': () +[18; 259) '{ ...c }; }': () [28; 29) 'y': &i32 [32; 33) 'x': &i32 [43; 45) '&z': &i32 @@ -13,3 +13,27 @@ [83; 95) '(1, "hello")': (i32, &str) [84; 85) '1': i32 [87; 94) '"hello"': &str +[102; 152) 'for (e... }': () +[106; 112) '(e, f)': ([unknown], [unknown]) +[107; 108) 'e': [unknown] +[110; 111) 'f': [unknown] +[116; 125) 'some_iter': [unknown] +[126; 152) '{ ... }': () +[140; 141) 'g': [unknown] +[144; 145) 'e': [unknown] +[158; 205) 'if let... }': () +[165; 170) '[val]': [unknown] +[173; 176) 'opt': [unknown] +[177; 205) '{ ... }': () +[191; 192) 'h': [unknown] +[195; 198) 'val': [unknown] +[215; 221) 'lambda': [unknown] +[224; 256) '|a: u6...b; c }': [unknown] +[225; 226) 'a': u64 +[233; 234) 'b': u64 +[236; 237) 'c': i32 +[244; 256) '{ a + b; c }': i32 +[246; 247) 'a': u64 +[246; 251) 'a + b': u64 +[250; 251) 'b': u64 +[253; 254) 'c': i32 -- cgit v1.2.3