From: Yap Zhi Heng <[email protected]>

Previously, type checking of StructPattern will throw an error if it is used
to match against a tuple struct, even though it is possible to do so in rustc.

gcc/rust/ChangeLog:

        * typecheck/rust-hir-type-check-pattern.cc (visit(StructPattern)): Add 
type check
        support for StructPatterns matching against a TUPLE type ADT.
        * 
backend/rust-compile-pattern.cc(CompilePatternBindings::visit(StructPattern)):
        Update assert to allow TUPLE type ADTs.
        * hir/tree/rust-hir.cc (StructPatternField::as_string()): Improve info 
dumped.

Signed-off-by: Yap Zhi Heng <[email protected]>
---
 gcc/rust/backend/rust-compile-pattern.cc      |  5 ++-
 gcc/rust/hir/tree/rust-hir.cc                 | 21 ++++++++++-
 .../typecheck/rust-hir-type-check-pattern.cc  | 37 ++++++++++++++++---
 3 files changed, 54 insertions(+), 9 deletions(-)

diff --git a/gcc/rust/backend/rust-compile-pattern.cc 
b/gcc/rust/backend/rust-compile-pattern.cc
index 149f6b07411..9ebb4d1dd63 100644
--- a/gcc/rust/backend/rust-compile-pattern.cc
+++ b/gcc/rust/backend/rust-compile-pattern.cc
@@ -885,8 +885,9 @@ CompilePatternBindings::visit (HIR::StructPattern &pattern)
       rust_assert (ok);
     }
 
-  rust_assert (variant->get_variant_type ()
-              == TyTy::VariantDef::VariantType::STRUCT);
+  rust_assert (
+    variant->get_variant_type () == TyTy::VariantDef::VariantType::STRUCT
+    || variant->get_variant_type () == TyTy::VariantDef::VariantType::TUPLE);
 
   auto &struct_pattern_elems = pattern.get_struct_pattern_elems ();
   for (auto &field : struct_pattern_elems.get_struct_pattern_fields ())
diff --git a/gcc/rust/hir/tree/rust-hir.cc b/gcc/rust/hir/tree/rust-hir.cc
index 7aad4ef2730..ce10b02303c 100644
--- a/gcc/rust/hir/tree/rust-hir.cc
+++ b/gcc/rust/hir/tree/rust-hir.cc
@@ -2519,10 +2519,29 @@ StructPatternField::as_string () const
        * just the body */
       for (const auto &attr : outer_attrs)
        {
-         str += "\n  " + attr.as_string ();
+         str += "\n    " + attr.as_string ();
        }
     }
 
+  str += "\n   item type: ";
+  switch (get_item_type ())
+    {
+    case ItemType::TUPLE_PAT:
+      str += "TUPLE_PAT";
+      break;
+    case ItemType::IDENT_PAT:
+      str += "IDENT_PAT";
+      break;
+    case ItemType::IDENT:
+      str += "IDENT";
+      break;
+    default:
+      str += "UNKNOWN";
+      break;
+    }
+
+  str += "\n   mapping: " + mappings.as_string ();
+
   return str;
 }
 
diff --git a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc 
b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc
index 7b405510bb3..e964318bf7c 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc
@@ -299,7 +299,30 @@ TypeCheckPattern::visit (HIR::StructPattern &pattern)
 
   // error[E0532]: expected tuple struct or tuple variant, found struct
   // variant `Foo::D`
-  if (variant->get_variant_type () != TyTy::VariantDef::VariantType::STRUCT)
+  bool error_E0532 = false;
+  if (variant->get_variant_type () == TyTy::VariantDef::VariantType::TUPLE)
+    {
+      // Tuple structs can still be matched with struct patterns via index
+      // numbers e.g. Foo {0: a, .., 3: b}, so check whether the fields are of
+      // type TUPLE_PAT. Throw E0532 if not.
+      auto &struct_pattern_elems = pattern.get_struct_pattern_elems ();
+      for (auto &field : struct_pattern_elems.get_struct_pattern_fields ())
+       {
+         if (field->get_item_type ()
+             != HIR::StructPatternField::ItemType::TUPLE_PAT)
+           {
+             error_E0532 = true;
+             break;
+           }
+       }
+    }
+  else if (variant->get_variant_type ()
+          != TyTy::VariantDef::VariantType::STRUCT)
+    {
+      error_E0532 = true;
+    }
+
+  if (error_E0532)
     {
       std::string variant_type
        = TyTy::VariantDef::variant_type_string (variant->get_variant_type ());
@@ -508,7 +531,8 @@ TypeCheckPattern::visit (HIR::TuplePattern &pattern)
          {
            emit_pattern_size_error (pattern, par.get_fields ().size (),
                                     min_size_required);
-           // TODO attempt to continue to do typechecking even after wrong size
+           // TODO attempt to continue to do typechecking even after wrong
+           // size
            break;
          }
 
@@ -680,10 +704,11 @@ TypeCheckPattern::visit (HIR::SlicePattern &pattern)
 
              if (cap_wi < pattern_min_cap)
                {
-                 rust_error_at (
-                   pattern.get_locus (), ErrorCode::E0528,
-                   "pattern requires at least %lu elements but array has %lu",
-                   (unsigned long) pattern_min_cap, (unsigned long) cap_wi);
+                 rust_error_at (pattern.get_locus (), ErrorCode::E0528,
+                                "pattern requires at least %lu elements but "
+                                "array has %lu",
+                                (unsigned long) pattern_min_cap,
+                                (unsigned long) cap_wi);
                  break;
                }
            }
-- 
2.50.1

Reply via email to