]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: derive-cmp: Add EnumMatchBuilder class
authorArthur Cohen <arthur.cohen@embecosm.com>
Tue, 22 Apr 2025 20:17:18 +0000 (22:17 +0200)
committerArthur Cohen <arthur.cohen@embecosm.com>
Tue, 5 Aug 2025 14:36:48 +0000 (16:36 +0200)
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.

gcc/rust/expand/rust-derive-cmp-common.cc
gcc/rust/expand/rust-derive-cmp-common.h

index 752f7ce47780704fec4c843d13938e0473ab3f3f..83913784e971fd62795e96618c8c534082fd76e7 100644 (file)
@@ -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
index bb7ae842a6fc9612d3d8dbe4909716ac1b829625..5902bb03b036e6ab5b4e4e3093d40ed5c0b46d9b 100644 (file)
@@ -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