diff options
author | Marcus Klaas de Vries <[email protected]> | 2019-01-17 09:54:47 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2019-01-19 12:37:25 +0000 |
commit | 9433a108cfcf3a9c7de9299d6641a5abf9031a17 (patch) | |
tree | d7054f505217be400c1e4b77417a2b9c525dd90f | |
parent | be1b4034a523081cfeea1c7a1d61130d5d1778e1 (diff) |
Make pattern inference work w/o proper expecations
-rw-r--r-- | crates/ra_hir/src/ty.rs | 72 | ||||
-rw-r--r-- | 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> { | |||
911 | return Ty::Unknown; | 911 | return Ty::Unknown; |
912 | }; | 912 | }; |
913 | 913 | ||
914 | // walk subpats | ||
915 | if fields.len() != sub_pats.len() { | 914 | if fields.len() != sub_pats.len() { |
916 | return Ty::Unknown; | 915 | return Ty::Unknown; |
917 | } | 916 | } |
@@ -944,44 +943,49 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
944 | ty | 943 | ty |
945 | } | 944 | } |
946 | 945 | ||
947 | // FIXME: Expectation should probably contain a reference to a Ty instead of | 946 | // TODO: Expectation should probably contain a Cow pointer to Ty? |
948 | // a Ty itself | 947 | // so that we can make new expectations of subtypes cheaply |
949 | fn infer_pat(&mut self, pat: PatId, expected: &Expectation) -> Ty { | 948 | fn infer_pat(&mut self, pat: PatId, expected: &Expectation) -> Ty { |
950 | let body = Arc::clone(&self.body); // avoid borrow checker problem | 949 | let body = Arc::clone(&self.body); // avoid borrow checker problem |
951 | 950 | ||
952 | // FIXME: we can do some inference even if the expected ty isnt already | 951 | let ty = match &body[pat] { |
953 | // of the right form | 952 | Pat::Tuple(ref args) => { |
954 | let ty = match (&body[pat], &expected.ty) { | 953 | // this can probably be done without cloning/ collecting |
955 | (Pat::Tuple(ref args), &Ty::Tuple(ref tuple_args)) | 954 | let expectations = match expected.ty { |
956 | if args.len() == tuple_args.len() => | 955 | Ty::Tuple(ref tuple_args) if args.len() == tuple_args.len() => { |
957 | { | 956 | tuple_args.iter().cloned().collect() |
958 | for (&pat, ty) in args.iter().zip(tuple_args.iter()) { | 957 | } |
959 | // FIXME: can we do w/o cloning? | 958 | _ => vec![Ty::Unknown; args.len()], |
960 | self.infer_pat(pat, &Expectation::has_type(ty.clone())); | 959 | }; |
961 | } | 960 | |
962 | expected.ty.clone() | 961 | let inner_tys = args |
962 | .iter() | ||
963 | .zip(expectations.into_iter()) | ||
964 | .map(|(&pat, ty)| self.infer_pat(pat, &Expectation::has_type(ty))) | ||
965 | .collect::<Vec<_>>() | ||
966 | .into(); | ||
967 | |||
968 | Ty::Tuple(inner_tys) | ||
963 | } | 969 | } |
964 | (&Pat::Ref { pat, mutability }, &Ty::Ref(ref sub_ty, ty_mut)) | 970 | Pat::Ref { pat, mutability } => { |
965 | if mutability == ty_mut => | 971 | let expectation = match expected.ty { |
966 | { | 972 | Ty::Ref(ref sub_ty, exp_mut) if *mutability == exp_mut => { |
967 | self.infer_pat(pat, &Expectation::has_type((&**sub_ty).clone())); | 973 | Expectation::has_type((&**sub_ty).clone()) |
968 | expected.ty.clone() | 974 | } |
975 | _ => Expectation::none(), | ||
976 | }; | ||
977 | let subty = self.infer_pat(*pat, &expectation); | ||
978 | Ty::Ref(subty.into(), *mutability) | ||
969 | } | 979 | } |
970 | ( | 980 | Pat::TupleStruct { |
971 | &Pat::TupleStruct { | 981 | path: ref p, |
972 | path: ref p, | 982 | args: ref sub_pats, |
973 | args: ref sub_pats, | 983 | } => self.infer_tuple_struct(p.as_ref(), sub_pats), |
974 | }, | 984 | Pat::Struct { |
975 | _, | 985 | path: ref p, |
976 | ) => self.infer_tuple_struct(p.as_ref(), sub_pats), | 986 | args: ref fields, |
977 | ( | 987 | } => self.infer_struct(p.as_ref(), fields), |
978 | &Pat::Struct { | 988 | _ => Ty::Unknown, |
979 | path: ref p, | ||
980 | args: ref fields, | ||
981 | }, | ||
982 | _, | ||
983 | ) => self.infer_struct(p.as_ref(), fields), | ||
984 | (_, ref _expected_ty) => expected.ty.clone(), | ||
985 | }; | 989 | }; |
986 | // use a new type variable if we got Ty::Unknown here | 990 | // use a new type variable if we got Ty::Unknown here |
987 | let ty = self.insert_type_vars_shallow(ty); | 991 | 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 @@ | |||
1 | [9; 10) 'x': &i32 | 1 | [9; 10) 'x': &i32 |
2 | [18; 98) '{ ...o"); }': () | 2 | [18; 259) '{ ...c }; }': () |
3 | [28; 29) 'y': &i32 | 3 | [28; 29) 'y': &i32 |
4 | [32; 33) 'x': &i32 | 4 | [32; 33) 'x': &i32 |
5 | [43; 45) '&z': &i32 | 5 | [43; 45) '&z': &i32 |
@@ -13,3 +13,27 @@ | |||
13 | [83; 95) '(1, "hello")': (i32, &str) | 13 | [83; 95) '(1, "hello")': (i32, &str) |
14 | [84; 85) '1': i32 | 14 | [84; 85) '1': i32 |
15 | [87; 94) '"hello"': &str | 15 | [87; 94) '"hello"': &str |
16 | [102; 152) 'for (e... }': () | ||
17 | [106; 112) '(e, f)': ([unknown], [unknown]) | ||
18 | [107; 108) 'e': [unknown] | ||
19 | [110; 111) 'f': [unknown] | ||
20 | [116; 125) 'some_iter': [unknown] | ||
21 | [126; 152) '{ ... }': () | ||
22 | [140; 141) 'g': [unknown] | ||
23 | [144; 145) 'e': [unknown] | ||
24 | [158; 205) 'if let... }': () | ||
25 | [165; 170) '[val]': [unknown] | ||
26 | [173; 176) 'opt': [unknown] | ||
27 | [177; 205) '{ ... }': () | ||
28 | [191; 192) 'h': [unknown] | ||
29 | [195; 198) 'val': [unknown] | ||
30 | [215; 221) 'lambda': [unknown] | ||
31 | [224; 256) '|a: u6...b; c }': [unknown] | ||
32 | [225; 226) 'a': u64 | ||
33 | [233; 234) 'b': u64 | ||
34 | [236; 237) 'c': i32 | ||
35 | [244; 256) '{ a + b; c }': i32 | ||
36 | [246; 247) 'a': u64 | ||
37 | [246; 251) 'a + b': u64 | ||
38 | [250; 251) 'b': u64 | ||
39 | [253; 254) 'c': i32 | ||