https://gcc.gnu.org/g:714a56ca67d2a70318b4678474a8fc019a007d29

commit r16-2864-g714a56ca67d2a70318b4678474a8fc019a007d29
Author: Arthur Cohen <arthur.co...@embecosm.com>
Date:   Tue Apr 22 22:17:18 2025 +0200

    gccrs: derive-cmp: Add EnumMatchBuilder class
    
    gcc/rust/ChangeLog:
    
            * expand/rust-derive-cmp-common.h (class EnumMatchBuilder): New 
helper class.
            * expand/rust-derive-cmp-common.cc (EnumMatchBuilder::tuple): New 
function.
            (EnumMatchBuilder::strukt): New function.

Diff:
---
 gcc/rust/expand/rust-derive-cmp-common.cc | 115 ++++++++++++++++++++++++++++++
 gcc/rust/expand/rust-derive-cmp-common.h  |  44 ++++++++++++
 2 files changed, 159 insertions(+)

diff --git a/gcc/rust/expand/rust-derive-cmp-common.cc 
b/gcc/rust/expand/rust-derive-cmp-common.cc
index 752f7ce47780..83913784e971 100644
--- a/gcc/rust/expand/rust-derive-cmp-common.cc
+++ b/gcc/rust/expand/rust-derive-cmp-common.cc
@@ -18,6 +18,7 @@
 
 #include "rust-derive-cmp-common.h"
 #include "rust-ast-builder.h"
+#include "rust-item.h"
 
 namespace Rust {
 namespace AST {
@@ -63,5 +64,119 @@ SelfOther::fields (Builder builder, const 
std::vector<StructField> &fields)
   return vec;
 }
 
+MatchCase
+EnumMatchBuilder::tuple (EnumItem &variant_raw)
+{
+  auto &variant = static_cast<EnumItemTuple &> (variant_raw);
+
+  auto self_patterns = std::vector<std::unique_ptr<Pattern>> ();
+  auto other_patterns = std::vector<std::unique_ptr<Pattern>> ();
+
+  auto self_other_exprs = std::vector<SelfOther> ();
+
+  for (size_t i = 0; i < variant.get_tuple_fields ().size (); i++)
+    {
+      // The patterns we're creating for each field are `self_<i>` and
+      // `other_<i>` where `i` is the index of the field. It doesn't actually
+      // matter what we use, as long as it's ordered, unique, and that we can
+      // reuse it in the match case's return expression to check that they are
+      // equal.
+
+      auto self_pattern_str = "__self_" + std::to_string (i);
+      auto other_pattern_str = "__other_" + std::to_string (i);
+
+      self_patterns.emplace_back (
+       builder.identifier_pattern (self_pattern_str));
+      other_patterns.emplace_back (
+       builder.identifier_pattern (other_pattern_str));
+
+      self_other_exprs.emplace_back (SelfOther{
+       builder.identifier (self_pattern_str),
+       builder.identifier (other_pattern_str),
+      });
+    }
+
+  auto self_pattern_items = std::unique_ptr<TupleStructItems> (
+    new TupleStructItemsNoRange (std::move (self_patterns)));
+  auto other_pattern_items = std::unique_ptr<TupleStructItems> (
+    new TupleStructItemsNoRange (std::move (other_patterns)));
+
+  auto self_pattern = std::unique_ptr<Pattern> (
+    new ReferencePattern (std::unique_ptr<Pattern> (new TupleStructPattern (
+                           variant_path, std::move (self_pattern_items))),
+                         false, false, builder.loc));
+  auto other_pattern = std::unique_ptr<Pattern> (
+    new ReferencePattern (std::unique_ptr<Pattern> (new TupleStructPattern (
+                           variant_path, std::move (other_pattern_items))),
+                         false, false, builder.loc));
+
+  auto tuple_items = std::make_unique<TuplePatternItemsMultiple> (
+    vec (std::move (self_pattern), std::move (other_pattern)));
+
+  auto pattern
+    = std::make_unique<TuplePattern> (std::move (tuple_items), builder.loc);
+
+  auto expr = fn (std::move (self_other_exprs));
+
+  return builder.match_case (std::move (pattern), std::move (expr));
+}
+
+MatchCase
+EnumMatchBuilder::strukt (EnumItem &variant_raw)
+{
+  auto &variant = static_cast<EnumItemStruct &> (variant_raw);
+
+  auto self_fields = std::vector<std::unique_ptr<StructPatternField>> ();
+  auto other_fields = std::vector<std::unique_ptr<StructPatternField>> ();
+
+  auto self_other_exprs = std::vector<SelfOther> ();
+
+  for (auto &field : variant.get_struct_fields ())
+    {
+      // The patterns we're creating for each field are `self_<field>` and
+      // `other_<field>` where `field` is the name of the field. It doesn't
+      // actually matter what we use, as long as it's ordered, unique, and that
+      // we can reuse it in the match case's return expression to check that
+      // they are equal.
+
+      auto field_name = field.get_field_name ().as_string ();
+
+      auto self_pattern_str = "__self_" + field_name;
+      auto other_pattern_str = "__other_" + field_name;
+
+      self_fields.emplace_back (builder.struct_pattern_ident_pattern (
+       field_name, builder.identifier_pattern (self_pattern_str)));
+      other_fields.emplace_back (builder.struct_pattern_ident_pattern (
+       field_name, builder.identifier_pattern (other_pattern_str)));
+
+      self_other_exprs.emplace_back (SelfOther{
+       builder.identifier (self_pattern_str),
+       builder.identifier (other_pattern_str),
+      });
+    }
+
+  auto self_elts = StructPatternElements (std::move (self_fields));
+  auto other_elts = StructPatternElements (std::move (other_fields));
+
+  auto self_pattern = std::unique_ptr<Pattern> (
+    new ReferencePattern (std::unique_ptr<Pattern> (new StructPattern (
+                           variant_path, builder.loc, std::move (self_elts))),
+                         false, false, builder.loc));
+  auto other_pattern = std::unique_ptr<Pattern> (
+    new ReferencePattern (std::unique_ptr<Pattern> (new StructPattern (
+                           variant_path, builder.loc, std::move (other_elts))),
+                         false, false, builder.loc));
+
+  auto tuple_items = std::make_unique<TuplePatternItemsMultiple> (
+    vec (std::move (self_pattern), std::move (other_pattern)));
+
+  auto pattern
+    = std::make_unique<TuplePattern> (std::move (tuple_items), builder.loc);
+
+  auto expr = fn (std::move (self_other_exprs));
+
+  return builder.match_case (std::move (pattern), std::move (expr));
+}
+
 } // namespace AST
 } // namespace Rust
diff --git a/gcc/rust/expand/rust-derive-cmp-common.h 
b/gcc/rust/expand/rust-derive-cmp-common.h
index bb7ae842a6fc..5902bb03b036 100644
--- a/gcc/rust/expand/rust-derive-cmp-common.h
+++ b/gcc/rust/expand/rust-derive-cmp-common.h
@@ -21,6 +21,8 @@
 
 #include "rust-ast.h"
 #include "rust-ast-builder.h"
+#include "rust-item.h"
+#include "rust-path.h"
 
 namespace Rust {
 namespace AST {
@@ -45,6 +47,48 @@ struct SelfOther
                                        const std::vector<StructField> &fields);
 };
 
+/**
+ * Builder for common match cases used when comparing two enum instances. This
+ * builder takes care of creating the unique patterns for the `self` instance
+ * and `other` instance, as well as the entire `MatchCase` required for 
building
+ * a proper comparision expression for an implementation of a comparision trait
+ * for an enum type. The functions take a lambda to use when creating the
+ * expression of the generated `MatchCase`.
+ */
+class EnumMatchBuilder
+{
+public:
+  /**
+   * The type of functions to call when creating the resulting expression in 
the
+   * generated `MatchCase`
+   */
+  using ExprFn
+    = std::function<std::unique_ptr<Expr> (std::vector<SelfOther> &&)>;
+
+  EnumMatchBuilder (PathInExpression &variant_path, ExprFn fn, Builder 
&builder)
+    : variant_path (variant_path), fn (fn), builder (builder)
+  {}
+
+  /**
+   * Generate a `MatchCase` for an enum tuple variant
+   *
+   * (&Enum::Tuple(self0, self1), &Enum::Tuple(other0, other1)) => <fn>
+   */
+  MatchCase tuple (EnumItem &variant);
+
+  /**
+   * Generate a `MatchCase` for an enum struct variant
+   *
+   * (&Enum::Struct { a: self_a }, &Enum::Struct { a: other_a }) => <fn>
+   */
+  MatchCase strukt (EnumItem &variant);
+
+private:
+  PathInExpression &variant_path;
+  ExprFn fn;
+  Builder &builder;
+};
+
 } // namespace AST
 } // namespace Rust

Reply via email to