]> git.lizzy.rs Git - rust.git/commitdiff
Correct binding pattern's type; handle invalid records.
authorDawer <7803845+iDawer@users.noreply.github.com>
Sat, 22 May 2021 07:36:48 +0000 (12:36 +0500)
committerDawer <7803845+iDawer@users.noreply.github.com>
Mon, 31 May 2021 19:49:44 +0000 (00:49 +0500)
crates/hir_ty/src/diagnostics/match_check.rs

index 992bb868222bb3feca2662053b0fa28fc2ebe97f..1d250413d2218f97cff92c00080fab75818652c3 100644 (file)
@@ -24,6 +24,7 @@
 pub(crate) enum PatternError {
     Unimplemented,
     UnresolvedVariant,
+    MissingField,
 }
 
 #[derive(Clone, Debug, PartialEq)]
@@ -105,7 +106,7 @@ pub(crate) fn lower_pattern(&mut self, pat: hir_def::expr::PatId) -> Pat {
     }
 
     fn lower_pattern_unadjusted(&mut self, pat: hir_def::expr::PatId) -> Pat {
-        let ty = &self.infer[pat];
+        let mut ty = &self.infer[pat];
         let variant = self.infer.variant_resolution_for_pat(pat);
 
         let kind = match self.body[pat] {
@@ -127,6 +128,9 @@ fn lower_pattern_unadjusted(&mut self, pat: hir_def::expr::PatId) -> Pat {
             }
 
             hir_def::expr::Pat::Bind { subpat, .. } => {
+                if let TyKind::Ref(.., rty) = ty.kind(&Interner) {
+                    ty = rty;
+                }
                 PatKind::Binding { subpattern: self.lower_opt_pattern(subpat) }
             }
 
@@ -140,13 +144,21 @@ fn lower_pattern_unadjusted(&mut self, pat: hir_def::expr::PatId) -> Pat {
                 let variant_data = variant.unwrap().variant_data(self.db.upcast());
                 let subpatterns = args
                     .iter()
-                    .map(|field| FieldPat {
+                    .map(|field| {
                         // XXX(iDawer): field lookup is inefficient
-                        field: variant_data.field(&field.name).unwrap(),
-                        pattern: self.lower_pattern(field.pat),
+                        variant_data.field(&field.name).map(|lfield_id| FieldPat {
+                            field: lfield_id,
+                            pattern: self.lower_pattern(field.pat),
+                        })
                     })
                     .collect();
-                self.lower_variant_or_leaf(pat, ty, subpatterns)
+                match subpatterns {
+                    Some(subpatterns) => self.lower_variant_or_leaf(pat, ty, subpatterns),
+                    None => {
+                        self.errors.push(PatternError::MissingField);
+                        PatKind::Wild
+                    }
+                }
             }
             hir_def::expr::Pat::TupleStruct { .. } | hir_def::expr::Pat::Record { .. } => {
                 self.errors.push(PatternError::UnresolvedVariant);
@@ -1090,6 +1102,31 @@ fn main() {
         );
     }
 
+    #[test]
+    fn binding_ref_has_correct_type() {
+        // Asserts `PatKind::Binding(ref _x): bool`, not &bool.
+        // If that's not true match checking will panic with "incompatible constructors"
+        // FIXME: make facilities to test this directly like `tests::check_infer(..)`
+        check_diagnostics(
+            r#"
+enum Foo { A }
+fn main() {
+    // FIXME: this should not bail out but current behavior is such as the old algorithm.
+    // ExprValidator::validate_match(..) checks types of top level patterns incorrecly.
+    match Foo::A {
+        ref _x => {}
+    //  ^^^^^^ Internal: match check bailed out
+        Foo::A => {}
+    }
+    match (true,) {
+        (ref _x,) => {}
+        (true,) => {}
+    }
+}
+"#,
+        );
+    }
+
     #[test]
     fn enum_non_exhaustive() {
         check_diagnostics(
@@ -1161,6 +1198,19 @@ fn main() {
         );
     }
 
+    #[test]
+    fn record_struct_no_such_field() {
+        check_diagnostics(
+            r#"
+struct Foo { }
+fn main(f: Foo) {
+    match f { Foo { bar } => () }
+    //        ^^^^^^^^^^^ Internal: match check bailed out
+}
+"#,
+        );
+    }
+
     mod false_negatives {
         //! The implementation of match checking here is a work in progress. As we roll this out, we
         //! prefer false negatives to false positives (ideally there would be no false positives). This