From 714a56ca67d2a70318b4678474a8fc019a007d29 Mon Sep 17 00:00:00 2001 From: Arthur Cohen Date: Tue, 22 Apr 2025 22:17:18 +0200 Subject: [PATCH] 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. --- 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 752f7ce4778..83913784e97 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 &fields) return vec; } +MatchCase +EnumMatchBuilder::tuple (EnumItem &variant_raw) +{ + auto &variant = static_cast (variant_raw); + + auto self_patterns = std::vector> (); + auto other_patterns = std::vector> (); + + auto self_other_exprs = std::vector (); + + for (size_t i = 0; i < variant.get_tuple_fields ().size (); i++) + { + // The patterns we're creating for each field are `self_` and + // `other_` 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 ( + new TupleStructItemsNoRange (std::move (self_patterns))); + auto other_pattern_items = std::unique_ptr ( + new TupleStructItemsNoRange (std::move (other_patterns))); + + auto self_pattern = std::unique_ptr ( + new ReferencePattern (std::unique_ptr (new TupleStructPattern ( + variant_path, std::move (self_pattern_items))), + false, false, builder.loc)); + auto other_pattern = std::unique_ptr ( + new ReferencePattern (std::unique_ptr (new TupleStructPattern ( + variant_path, std::move (other_pattern_items))), + false, false, builder.loc)); + + auto tuple_items = std::make_unique ( + vec (std::move (self_pattern), std::move (other_pattern))); + + auto pattern + = std::make_unique (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 (variant_raw); + + auto self_fields = std::vector> (); + auto other_fields = std::vector> (); + + auto self_other_exprs = std::vector (); + + for (auto &field : variant.get_struct_fields ()) + { + // The patterns we're creating for each field are `self_` and + // `other_` 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 ( + new ReferencePattern (std::unique_ptr (new StructPattern ( + variant_path, builder.loc, std::move (self_elts))), + false, false, builder.loc)); + auto other_pattern = std::unique_ptr ( + new ReferencePattern (std::unique_ptr (new StructPattern ( + variant_path, builder.loc, std::move (other_elts))), + false, false, builder.loc)); + + auto tuple_items = std::make_unique ( + vec (std::move (self_pattern), std::move (other_pattern))); + + auto pattern + = std::make_unique (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 bb7ae842a6f..5902bb03b03 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 &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::vector &&)>; + + 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)) => + */ + MatchCase tuple (EnumItem &variant); + + /** + * Generate a `MatchCase` for an enum struct variant + * + * (&Enum::Struct { a: self_a }, &Enum::Struct { a: other_a }) => + */ + MatchCase strukt (EnumItem &variant); + +private: + PathInExpression &variant_path; + ExprFn fn; + Builder &builder; +}; + } // namespace AST } // namespace Rust -- 2.47.3