aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-01-19 14:48:55 +0000
committerFlorian Diebold <[email protected]>2019-01-19 15:02:06 +0000
commit9e4b5ecec4fa4f6a20bb4d47f09de602e9c29608 (patch)
treeb94dd19bc5c2acd05b4de97e27ed4491d54cb78f /crates
parentd37bb128effd19e3aec347e3d4f2e27b5cdb9404 (diff)
Make generics work in struct patterns
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir/src/ty.rs61
-rw-r--r--crates/ra_hir/src/ty/tests.rs26
-rw-r--r--crates/ra_hir/src/ty/tests/data/generics_in_patterns.txt17
3 files changed, 87 insertions, 17 deletions
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index 1d2d1b906..3608daae4 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -683,9 +683,9 @@ pub(super) fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Ty {
683 683
684pub(super) fn type_for_field(db: &impl HirDatabase, def_id: DefId, field: Name) -> Option<Ty> { 684pub(super) fn type_for_field(db: &impl HirDatabase, def_id: DefId, field: Name) -> Option<Ty> {
685 let def = def_id.resolve(db); 685 let def = def_id.resolve(db);
686 let variant_data = match def { 686 let (variant_data, generics) = match def {
687 Def::Struct(s) => s.variant_data(db), 687 Def::Struct(s) => (s.variant_data(db), s.generics(db)),
688 Def::EnumVariant(ev) => ev.variant_data(db), 688 Def::EnumVariant(ev) => (ev.variant_data(db), ev.parent_enum(db).generics(db)),
689 // TODO: unions 689 // TODO: unions
690 _ => panic!( 690 _ => panic!(
691 "trying to get type for field in non-struct/variant {:?}", 691 "trying to get type for field in non-struct/variant {:?}",
@@ -694,7 +694,6 @@ pub(super) fn type_for_field(db: &impl HirDatabase, def_id: DefId, field: Name)
694 }; 694 };
695 let module = def_id.module(db); 695 let module = def_id.module(db);
696 let impl_block = def_id.impl_block(db); 696 let impl_block = def_id.impl_block(db);
697 let generics = db.generics(def_id);
698 let type_ref = variant_data.get_field_type_ref(&field)?; 697 let type_ref = variant_data.get_field_type_ref(&field)?;
699 Some(Ty::from_hir( 698 Some(Ty::from_hir(
700 db, 699 db,
@@ -893,6 +892,14 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
893 ty 892 ty
894 } 893 }
895 894
895 fn unify_substs(&mut self, substs1: &Substs, substs2: &Substs) -> bool {
896 substs1
897 .0
898 .iter()
899 .zip(substs2.0.iter())
900 .all(|(t1, t2)| self.unify(t1, t2))
901 }
902
896 fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { 903 fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
897 // try to resolve type vars first 904 // try to resolve type vars first
898 let ty1 = self.resolve_ty_shallow(ty1); 905 let ty1 = self.resolve_ty_shallow(ty1);
@@ -913,12 +920,16 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
913 (Ty::Bool, _) | (Ty::Str, _) | (Ty::Never, _) | (Ty::Char, _) => ty1 == ty2, 920 (Ty::Bool, _) | (Ty::Str, _) | (Ty::Never, _) | (Ty::Char, _) => ty1 == ty2,
914 ( 921 (
915 Ty::Adt { 922 Ty::Adt {
916 def_id: def_id1, .. 923 def_id: def_id1,
924 substs: substs1,
925 ..
917 }, 926 },
918 Ty::Adt { 927 Ty::Adt {
919 def_id: def_id2, .. 928 def_id: def_id2,
929 substs: substs2,
930 ..
920 }, 931 },
921 ) if def_id1 == def_id2 => true, 932 ) if def_id1 == def_id2 => self.unify_substs(substs1, substs2),
922 (Ty::Slice(t1), Ty::Slice(t2)) => self.unify(t1, t2), 933 (Ty::Slice(t1), Ty::Slice(t2)) => self.unify(t1, t2),
923 (Ty::RawPtr(t1, m1), Ty::RawPtr(t2, m2)) if m1 == m2 => self.unify(t1, t2), 934 (Ty::RawPtr(t1, m1), Ty::RawPtr(t2, m2)) if m1 == m2 => self.unify(t1, t2),
924 (Ty::Ref(t1, m1), Ty::Ref(t2, m2)) if m1 == m2 => self.unify(t1, t2), 935 (Ty::Ref(t1, m1), Ty::Ref(t2, m2)) if m1 == m2 => self.unify(t1, t2),
@@ -1088,49 +1099,65 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1088 } 1099 }
1089 } 1100 }
1090 1101
1091 fn resolve_fields(&self, path: Option<&Path>) -> Option<(Ty, Vec<StructField>)> { 1102 fn resolve_fields(&mut self, path: Option<&Path>) -> Option<(Ty, Vec<StructField>)> {
1092 let def_id = self.module.resolve_path(self.db, path?).take_types()?; 1103 let (ty, def_id) = self.resolve_variant(path);
1104 let def_id = def_id?;
1093 let def = def_id.resolve(self.db); 1105 let def = def_id.resolve(self.db);
1094 1106
1095 match def { 1107 match def {
1096 Def::Struct(s) => { 1108 Def::Struct(s) => {
1097 let fields = s.fields(self.db); 1109 let fields = s.fields(self.db);
1098 Some((type_for_struct(self.db, s), fields)) 1110 Some((ty, fields))
1099 } 1111 }
1100 Def::EnumVariant(ev) => { 1112 Def::EnumVariant(ev) => {
1101 let fields = ev.fields(self.db); 1113 let fields = ev.fields(self.db);
1102 Some((type_for_enum_variant(self.db, ev), fields)) 1114 Some((ty, fields))
1103 } 1115 }
1104 _ => None, 1116 _ => None,
1105 } 1117 }
1106 } 1118 }
1107 1119
1108 fn infer_tuple_struct_pat(&mut self, path: Option<&Path>, subpats: &[PatId]) -> Ty { 1120 fn infer_tuple_struct_pat(
1121 &mut self,
1122 path: Option<&Path>,
1123 subpats: &[PatId],
1124 expected: &Ty,
1125 ) -> Ty {
1109 let (ty, fields) = self 1126 let (ty, fields) = self
1110 .resolve_fields(path) 1127 .resolve_fields(path)
1111 .unwrap_or((Ty::Unknown, Vec::new())); 1128 .unwrap_or((Ty::Unknown, Vec::new()));
1112 1129
1130 self.unify(&ty, expected);
1131
1132 let substs = ty.substs().expect("adt should have substs");
1133
1113 for (i, &subpat) in subpats.iter().enumerate() { 1134 for (i, &subpat) in subpats.iter().enumerate() {
1114 let expected_ty = fields 1135 let expected_ty = fields
1115 .get(i) 1136 .get(i)
1116 .and_then(|field| field.ty(self.db)) 1137 .and_then(|field| field.ty(self.db))
1117 .unwrap_or(Ty::Unknown); 1138 .unwrap_or(Ty::Unknown)
1139 .subst(&substs);
1118 self.infer_pat(subpat, &expected_ty); 1140 self.infer_pat(subpat, &expected_ty);
1119 } 1141 }
1120 1142
1121 ty 1143 ty
1122 } 1144 }
1123 1145
1124 fn infer_struct_pat(&mut self, path: Option<&Path>, subpats: &[FieldPat]) -> Ty { 1146 fn infer_struct_pat(&mut self, path: Option<&Path>, subpats: &[FieldPat], expected: &Ty) -> Ty {
1125 let (ty, fields) = self 1147 let (ty, fields) = self
1126 .resolve_fields(path) 1148 .resolve_fields(path)
1127 .unwrap_or((Ty::Unknown, Vec::new())); 1149 .unwrap_or((Ty::Unknown, Vec::new()));
1128 1150
1151 self.unify(&ty, expected);
1152
1153 let substs = ty.substs().expect("adt should have substs");
1154
1129 for subpat in subpats { 1155 for subpat in subpats {
1130 let matching_field = fields.iter().find(|field| field.name() == &subpat.name); 1156 let matching_field = fields.iter().find(|field| field.name() == &subpat.name);
1131 let expected_ty = matching_field 1157 let expected_ty = matching_field
1132 .and_then(|field| field.ty(self.db)) 1158 .and_then(|field| field.ty(self.db))
1133 .unwrap_or(Ty::Unknown); 1159 .unwrap_or(Ty::Unknown)
1160 .subst(&substs);
1134 self.infer_pat(subpat.pat, &expected_ty); 1161 self.infer_pat(subpat.pat, &expected_ty);
1135 } 1162 }
1136 1163
@@ -1175,11 +1202,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1175 Pat::TupleStruct { 1202 Pat::TupleStruct {
1176 path: ref p, 1203 path: ref p,
1177 args: ref subpats, 1204 args: ref subpats,
1178 } => self.infer_tuple_struct_pat(p.as_ref(), subpats), 1205 } => self.infer_tuple_struct_pat(p.as_ref(), subpats, expected),
1179 Pat::Struct { 1206 Pat::Struct {
1180 path: ref p, 1207 path: ref p,
1181 args: ref fields, 1208 args: ref fields,
1182 } => self.infer_struct_pat(p.as_ref(), fields), 1209 } => self.infer_struct_pat(p.as_ref(), fields, expected),
1183 Pat::Path(path) => self 1210 Pat::Path(path) => self
1184 .module 1211 .module
1185 .resolve_path(self.db, &path) 1212 .resolve_path(self.db, &path)
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index c590a09db..06e32df59 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -439,6 +439,32 @@ fn test(a1: A<u32>, i: i32) {
439} 439}
440 440
441#[test] 441#[test]
442fn infer_generics_in_patterns() {
443 check_inference(
444 r#"
445struct A<T> {
446 x: T,
447}
448
449enum Option<T> {
450 Some(T),
451 None,
452}
453
454fn test(a1: A<u32>, o: Option<u64>) {
455 let A { x: x2 } = a1;
456 let A::<i64> { x: x3 } = A { x: 1 };
457 match o {
458 Option::Some(t) => t,
459 _ => 1,
460 };
461}
462"#,
463 "generics_in_patterns.txt",
464 );
465}
466
467#[test]
442fn infer_function_generics() { 468fn infer_function_generics() {
443 check_inference( 469 check_inference(
444 r#" 470 r#"
diff --git a/crates/ra_hir/src/ty/tests/data/generics_in_patterns.txt b/crates/ra_hir/src/ty/tests/data/generics_in_patterns.txt
new file mode 100644
index 000000000..1b01ef19e
--- /dev/null
+++ b/crates/ra_hir/src/ty/tests/data/generics_in_patterns.txt
@@ -0,0 +1,17 @@
1[79; 81) 'a1': A<u32>
2[91; 92) 'o': Option<u64>
3[107; 244) '{ ... }; }': ()
4[117; 128) 'A { x: x2 }': A<u32>
5[124; 126) 'x2': u32
6[131; 133) 'a1': A<u32>
7[143; 161) 'A::<i6...: x3 }': A<i64>
8[157; 159) 'x3': i64
9[164; 174) 'A { x: 1 }': A<i64>
10[171; 172) '1': i64
11[180; 241) 'match ... }': u64
12[186; 187) 'o': Option<u64>
13[198; 213) 'Option::Some(t)': Option<u64>
14[211; 212) 't': u64
15[217; 218) 't': u64
16[228; 229) '_': Option<u64>
17[233; 234) '1': u64