aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_ty
diff options
context:
space:
mode:
authorDawer <[email protected]>2021-05-22 08:36:48 +0100
committerDawer <[email protected]>2021-05-31 20:49:44 +0100
commit4899ac8c053ef782c25c87b12b54dbcbfdb5e0fb (patch)
tree3cc5d66b09f594dc0f0afec4df85895193f11543 /crates/hir_ty
parent3088ca0a53540e0d7ae14f0d18efcad16cad0735 (diff)
Correct binding pattern's type; handle invalid records.
Diffstat (limited to 'crates/hir_ty')
-rw-r--r--crates/hir_ty/src/diagnostics/match_check.rs60
1 files changed, 55 insertions, 5 deletions
diff --git a/crates/hir_ty/src/diagnostics/match_check.rs b/crates/hir_ty/src/diagnostics/match_check.rs
index 992bb8682..1d250413d 100644
--- a/crates/hir_ty/src/diagnostics/match_check.rs
+++ b/crates/hir_ty/src/diagnostics/match_check.rs
@@ -24,6 +24,7 @@ pub(crate) type PatId = Idx<Pat>;
24pub(crate) enum PatternError { 24pub(crate) enum PatternError {
25 Unimplemented, 25 Unimplemented,
26 UnresolvedVariant, 26 UnresolvedVariant,
27 MissingField,
27} 28}
28 29
29#[derive(Clone, Debug, PartialEq)] 30#[derive(Clone, Debug, PartialEq)]
@@ -105,7 +106,7 @@ impl<'a> PatCtxt<'a> {
105 } 106 }
106 107
107 fn lower_pattern_unadjusted(&mut self, pat: hir_def::expr::PatId) -> Pat { 108 fn lower_pattern_unadjusted(&mut self, pat: hir_def::expr::PatId) -> Pat {
108 let ty = &self.infer[pat]; 109 let mut ty = &self.infer[pat];
109 let variant = self.infer.variant_resolution_for_pat(pat); 110 let variant = self.infer.variant_resolution_for_pat(pat);
110 111
111 let kind = match self.body[pat] { 112 let kind = match self.body[pat] {
@@ -127,6 +128,9 @@ impl<'a> PatCtxt<'a> {
127 } 128 }
128 129
129 hir_def::expr::Pat::Bind { subpat, .. } => { 130 hir_def::expr::Pat::Bind { subpat, .. } => {
131 if let TyKind::Ref(.., rty) = ty.kind(&Interner) {
132 ty = rty;
133 }
130 PatKind::Binding { subpattern: self.lower_opt_pattern(subpat) } 134 PatKind::Binding { subpattern: self.lower_opt_pattern(subpat) }
131 } 135 }
132 136
@@ -140,13 +144,21 @@ impl<'a> PatCtxt<'a> {
140 let variant_data = variant.unwrap().variant_data(self.db.upcast()); 144 let variant_data = variant.unwrap().variant_data(self.db.upcast());
141 let subpatterns = args 145 let subpatterns = args
142 .iter() 146 .iter()
143 .map(|field| FieldPat { 147 .map(|field| {
144 // XXX(iDawer): field lookup is inefficient 148 // XXX(iDawer): field lookup is inefficient
145 field: variant_data.field(&field.name).unwrap(), 149 variant_data.field(&field.name).map(|lfield_id| FieldPat {
146 pattern: self.lower_pattern(field.pat), 150 field: lfield_id,
151 pattern: self.lower_pattern(field.pat),
152 })
147 }) 153 })
148 .collect(); 154 .collect();
149 self.lower_variant_or_leaf(pat, ty, subpatterns) 155 match subpatterns {
156 Some(subpatterns) => self.lower_variant_or_leaf(pat, ty, subpatterns),
157 None => {
158 self.errors.push(PatternError::MissingField);
159 PatKind::Wild
160 }
161 }
150 } 162 }
151 hir_def::expr::Pat::TupleStruct { .. } | hir_def::expr::Pat::Record { .. } => { 163 hir_def::expr::Pat::TupleStruct { .. } | hir_def::expr::Pat::Record { .. } => {
152 self.errors.push(PatternError::UnresolvedVariant); 164 self.errors.push(PatternError::UnresolvedVariant);
@@ -1091,6 +1103,31 @@ fn main() {
1091 } 1103 }
1092 1104
1093 #[test] 1105 #[test]
1106 fn binding_ref_has_correct_type() {
1107 // Asserts `PatKind::Binding(ref _x): bool`, not &bool.
1108 // If that's not true match checking will panic with "incompatible constructors"
1109 // FIXME: make facilities to test this directly like `tests::check_infer(..)`
1110 check_diagnostics(
1111 r#"
1112enum Foo { A }
1113fn main() {
1114 // FIXME: this should not bail out but current behavior is such as the old algorithm.
1115 // ExprValidator::validate_match(..) checks types of top level patterns incorrecly.
1116 match Foo::A {
1117 ref _x => {}
1118 // ^^^^^^ Internal: match check bailed out
1119 Foo::A => {}
1120 }
1121 match (true,) {
1122 (ref _x,) => {}
1123 (true,) => {}
1124 }
1125}
1126"#,
1127 );
1128 }
1129
1130 #[test]
1094 fn enum_non_exhaustive() { 1131 fn enum_non_exhaustive() {
1095 check_diagnostics( 1132 check_diagnostics(
1096 r#" 1133 r#"
@@ -1161,6 +1198,19 @@ fn main() {
1161 ); 1198 );
1162 } 1199 }
1163 1200
1201 #[test]
1202 fn record_struct_no_such_field() {
1203 check_diagnostics(
1204 r#"
1205struct Foo { }
1206fn main(f: Foo) {
1207 match f { Foo { bar } => () }
1208 // ^^^^^^^^^^^ Internal: match check bailed out
1209}
1210"#,
1211 );
1212 }
1213
1164 mod false_negatives { 1214 mod false_negatives {
1165 //! The implementation of match checking here is a work in progress. As we roll this out, we 1215 //! The implementation of match checking here is a work in progress. As we roll this out, we
1166 //! prefer false negatives to false positives (ideally there would be no false positives). This 1216 //! prefer false negatives to false positives (ideally there would be no false positives). This