diff options
Diffstat (limited to 'gcc/rust/expand/rust-derive-partial-eq.cc')
-rw-r--r-- | gcc/rust/expand/rust-derive-partial-eq.cc | 147 |
1 files changed, 85 insertions, 62 deletions
diff --git a/gcc/rust/expand/rust-derive-partial-eq.cc b/gcc/rust/expand/rust-derive-partial-eq.cc index ff66faa..a0bf87a 100644 --- a/gcc/rust/expand/rust-derive-partial-eq.cc +++ b/gcc/rust/expand/rust-derive-partial-eq.cc @@ -64,11 +64,9 @@ DerivePartialEq::partialeq_impls ( } std::unique_ptr<AssociatedItem> -DerivePartialEq::eq_fn (std::unique_ptr<Expr> &&cmp_expression, +DerivePartialEq::eq_fn (std::unique_ptr<BlockExpr> &&block, std::string type_name) { - auto block = builder.block (tl::nullopt, std::move (cmp_expression)); - auto self_type = std::unique_ptr<TypeNoBounds> (new TypePath (builder.type_path ("Self"))); @@ -83,24 +81,6 @@ DerivePartialEq::eq_fn (std::unique_ptr<Expr> &&cmp_expression, std::move (block)); } -DerivePartialEq::SelfOther -DerivePartialEq::tuple_indexes (int idx) -{ - return SelfOther{ - builder.tuple_idx ("self", idx), - builder.tuple_idx ("other", idx), - }; -} - -DerivePartialEq::SelfOther -DerivePartialEq::field_acccesses (const std::string &field_name) -{ - return SelfOther{ - builder.field_access (builder.identifier ("self"), field_name), - builder.field_access (builder.identifier ("other"), field_name), - }; -} - std::unique_ptr<Expr> DerivePartialEq::build_eq_expression ( std::vector<SelfOther> &&field_expressions) @@ -134,12 +114,10 @@ void DerivePartialEq::visit_tuple (TupleStruct &item) { auto type_name = item.get_struct_name ().as_string (); - auto fields = std::vector<SelfOther> (); - - for (size_t idx = 0; idx < item.get_fields ().size (); idx++) - fields.emplace_back (tuple_indexes (idx)); + auto fields = SelfOther::indexes (builder, item.get_fields ()); - auto fn = eq_fn (build_eq_expression (std::move (fields)), type_name); + auto fn = eq_fn (builder.block (build_eq_expression (std::move (fields))), + type_name); expanded = partialeq_impls (std::move (fn), type_name, item.get_generic_params ()); @@ -149,13 +127,10 @@ void DerivePartialEq::visit_struct (StructStruct &item) { auto type_name = item.get_struct_name ().as_string (); - auto fields = std::vector<SelfOther> (); + auto fields = SelfOther::fields (builder, item.get_fields ()); - for (auto &field : item.get_fields ()) - fields.emplace_back ( - field_acccesses (field.get_field_name ().as_string ())); - - auto fn = eq_fn (build_eq_expression (std::move (fields)), type_name); + auto fn = eq_fn (builder.block (build_eq_expression (std::move (fields))), + type_name); expanded = partialeq_impls (std::move (fn), type_name, item.get_generic_params ()); @@ -199,8 +174,6 @@ DerivePartialEq::match_enum_tuple (PathInExpression variant_path, auto self_pattern_str = "__self_" + std::to_string (i); auto other_pattern_str = "__other_" + std::to_string (i); - rust_debug ("]ARTHUR[ %s", self_pattern_str.c_str ()); - self_patterns.emplace_back ( builder.identifier_pattern (self_pattern_str)); other_patterns.emplace_back ( @@ -240,15 +213,55 @@ MatchCase DerivePartialEq::match_enum_struct (PathInExpression variant_path, const EnumItemStruct &variant) { - // NOTE: We currently do not support compiling struct patterns where an - // identifier is assigned a new pattern, e.g. Bloop { f0: x } - // This is what we should be using to compile PartialEq for enum struct - // variants, as we need to be comparing the field of each instance meaning we - // need to give two different names to two different instances of the same - // field. We cannot just use the field's name like we do when deriving - // `Clone`. - - rust_unreachable (); + 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, loc, std::move (self_elts))), + false, false, loc)); + auto other_pattern = std::unique_ptr<Pattern> ( + new ReferencePattern (std::unique_ptr<Pattern> (new StructPattern ( + variant_path, loc, std::move (other_elts))), + false, false, 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), loc); + + auto expr = build_eq_expression (std::move (self_other_exprs)); + + return builder.match_case (std::move (pattern), std::move (expr)); } void @@ -257,46 +270,56 @@ DerivePartialEq::visit_enum (Enum &item) auto cases = std::vector<MatchCase> (); auto type_name = item.get_identifier ().as_string (); + auto eq_expr_fn = [this] (std::vector<SelfOther> &&fields) { + return build_eq_expression (std::move (fields)); + }; + + auto let_sd + = builder.discriminant_value (DerivePartialEq::self_discr, "self"); + auto let_od + = builder.discriminant_value (DerivePartialEq::other_discr, "other"); + + auto discr_cmp + = builder.comparison_expr (builder.identifier (DerivePartialEq::self_discr), + builder.identifier ( + DerivePartialEq::other_discr), + ComparisonOperator::EQUAL); + for (auto &variant : item.get_variants ()) { - auto variant_path - = builder.variant_path (type_name, - variant->get_identifier ().as_string ()); + auto enum_builder + = EnumMatchBuilder (type_name, variant->get_identifier ().as_string (), + eq_expr_fn, builder); switch (variant->get_enum_item_kind ()) { - case EnumItem::Kind::Identifier: - case EnumItem::Kind::Discriminant: - cases.emplace_back (match_enum_identifier (variant_path, variant)); - break; case EnumItem::Kind::Tuple: - cases.emplace_back ( - match_enum_tuple (variant_path, - static_cast<EnumItemTuple &> (*variant))); + cases.emplace_back (enum_builder.tuple (*variant)); break; case EnumItem::Kind::Struct: - rust_sorry_at ( - item.get_locus (), - "cannot derive(PartialEq) for enum struct variants yet"); + cases.emplace_back (enum_builder.strukt (*variant)); + break; + case EnumItem::Kind::Identifier: + case EnumItem::Kind::Discriminant: + // We don't need to do anything for these, as they are handled by the + // discriminant value comparison break; } } - // NOTE: Mention using discriminant_value and skipping that last case, and - // instead skipping all identifiers/discriminant enum items and returning - // `true` in the wildcard case - // In case the two instances of `Self` don't have the same discriminant, // automatically return false. cases.emplace_back ( - builder.match_case (builder.wildcard (), builder.literal_bool (false))); + builder.match_case (builder.wildcard (), std::move (discr_cmp))); auto match = builder.match (builder.tuple (vec (builder.identifier ("self"), builder.identifier ("other"))), std::move (cases)); - auto fn = eq_fn (std::move (match), type_name); + auto fn = eq_fn (builder.block (vec (std::move (let_sd), std::move (let_od)), + std::move (match)), + type_name); expanded = partialeq_impls (std::move (fn), type_name, item.get_generic_params ()); |