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