From: Yap Zhi Heng <[email protected]>

gcc/rust/ChangeLog:

        * typecheck/rust-hir-type-check-expr.cc (visit(StructExprStruct)): 
Update to properly
        unwrap enum variants for type checking.
        * typecheck/rust-tyty.cc (VariantDef::get_fields) : Remove NUM assert.
        * backend/rust-compile-expr.cc: Update to properly unwrap enum variants 
for type
        resolution checking.

Signed-off-by: Yap Zhi Heng <[email protected]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.


Commit on github: 
https://github.com/Rust-GCC/gccrs/commit/32622b71b867ab153371db1e31bae6abfa7b5c2f

The commit has been mentioned in the following pull-request(s):
 - https://github.com/Rust-GCC/gccrs/pull/4342

 gcc/rust/backend/rust-compile-expr.cc         | 20 ++++++-
 .../typecheck/rust-hir-type-check-expr.cc     | 55 ++++++++++++++-----
 gcc/rust/typecheck/rust-tyty.cc               |  1 -
 gcc/testsuite/rust/compile/issue-4163-2.rs    | 10 ++++
 gcc/testsuite/rust/compile/issue-4163.rs      |  9 +++
 5 files changed, 78 insertions(+), 17 deletions(-)
 create mode 100644 gcc/testsuite/rust/compile/issue-4163-2.rs
 create mode 100644 gcc/testsuite/rust/compile/issue-4163.rs

diff --git a/gcc/rust/backend/rust-compile-expr.cc 
b/gcc/rust/backend/rust-compile-expr.cc
index 7c4cc4a1d..40bd2829f 100644
--- a/gcc/rust/backend/rust-compile-expr.cc
+++ b/gcc/rust/backend/rust-compile-expr.cc
@@ -499,7 +499,25 @@ CompileExpr::visit (HIR::StructExprStruct &struct_expr)
       return;
     }
 
-  rust_assert (tyty->is_unit ());
+  TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (tyty);
+  TyTy::VariantDef *variant = nullptr;
+  if (adt->is_enum ())
+    {
+      // unwrap variant and ensure that it can be resolved
+      HirId variant_id;
+      bool ok = ctx->get_tyctx ()->lookup_variant_definition (
+       struct_expr.get_struct_name ().get_mappings ().get_hirid (),
+       &variant_id);
+      rust_assert (ok);
+
+      ok = adt->lookup_variant_by_id (variant_id, &variant);
+      rust_assert (ok);
+    }
+  else
+    {
+      rust_assert (tyty->is_unit ());
+    }
+
   translated = unit_expression (struct_expr.get_locus ());
 }
 
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc 
b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
index 089a40627..327144f3f 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
@@ -1187,31 +1187,56 @@ TypeCheckExpr::visit (HIR::ArrayExpr &expr)
 void
 TypeCheckExpr::visit (HIR::StructExprStruct &struct_expr)
 {
-  TyTy::BaseType *struct_path_ty
-    = TypeCheckExpr::Resolve (struct_expr.get_struct_name ());
+  HIR::PathInExpression &path = struct_expr.get_struct_name ();
+
+  TyTy::BaseType *struct_path_ty = TypeCheckExpr::Resolve (path);
   if (struct_path_ty->get_kind () != TyTy::TypeKind::ADT)
     {
-      rust_error_at (struct_expr.get_struct_name ().get_locus (),
-                    "expected an ADT type for constructor");
+      rust_error_at (path.get_locus (), "expected an ADT type for 
constructor");
       return;
     }
 
   TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (struct_path_ty);
-  for (auto variant : adt->get_variants ())
+  TyTy::VariantDef *variant;
+
+  // unwrap and type check the variant if it's an enum
+  if (adt->is_enum ())
     {
-      if (!variant->get_fields ().empty ())
+      HirId variant_id;
+      bool ok = context->lookup_variant_definition (
+       struct_expr.get_struct_name ().get_mappings ().get_hirid (),
+       &variant_id);
+      if (!ok)
        {
-         std::vector<std::string> field_names;
-         for (auto &field : variant->get_fields ())
-           field_names.push_back (field->get_name ());
-         Error missing_fields_error
-           = TypeCheckStructExpr::make_missing_field_error (
-             struct_expr.get_locus (), field_names,
-             struct_path_ty->get_name ());
-         // We might want to return or handle these in the future emit for now.
-         missing_fields_error.emit ();
+         rich_location r (line_table, struct_expr.get_locus ());
+         r.add_range (struct_expr.get_struct_name ().get_locus ());
+         rust_error_at (
+           struct_expr.get_struct_name ().get_locus (), ErrorCode::E0574,
+           "expected a struct, variant or union type, found enum %qs",
+           adt->get_name ().c_str ());
          return;
        }
+
+      ok = adt->lookup_variant_by_id (variant_id, &variant);
+      rust_assert (ok);
+    }
+  else
+    {
+      rust_assert (adt->number_of_variants () == 1);
+      variant = adt->get_variants ().at (0);
+    }
+
+  if (!variant->get_fields ().empty ())
+    {
+      std::vector<std::string> field_names;
+      for (auto &field : variant->get_fields ())
+       field_names.push_back (field->get_name ());
+      Error missing_fields_error
+       = TypeCheckStructExpr::make_missing_field_error (
+         struct_expr.get_locus (), field_names, struct_path_ty->get_name ());
+      // We might want to return or handle these in the future emit for now.
+      missing_fields_error.emit ();
+      return;
     }
 
   infered = struct_path_ty;
diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
index 4f7beb70c..161c15e78 100644
--- a/gcc/rust/typecheck/rust-tyty.cc
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -1604,7 +1604,6 @@ VariantDef::get_field_at_index (size_t index)
 std::vector<StructFieldType *> &
 VariantDef::get_fields ()
 {
-  rust_assert (type != NUM);
   return fields;
 }
 
diff --git a/gcc/testsuite/rust/compile/issue-4163-2.rs 
b/gcc/testsuite/rust/compile/issue-4163-2.rs
new file mode 100644
index 000000000..c36b66967
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-4163-2.rs
@@ -0,0 +1,10 @@
+enum Enum {
+    NotEmpty {x: i32},
+    Struct {},
+    Tuple (),
+}
+
+fn main() {
+    Enum::Struct {};
+    Enum::Tuple {};
+}
\ No newline at end of file
diff --git a/gcc/testsuite/rust/compile/issue-4163.rs 
b/gcc/testsuite/rust/compile/issue-4163.rs
new file mode 100644
index 000000000..fde5bccef
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-4163.rs
@@ -0,0 +1,9 @@
+enum Enum {
+    Unit,
+    Tuple(i32),
+    Struct { x: i32 },
+}
+
+fn main() {
+    Enum::Unit {};
+}
\ No newline at end of file

base-commit: 0d89970b7f65bebd5d8409e9614a881757dbf5ba
-- 
2.52.0

Reply via email to