Skip to content

Commit 91d3a53

Browse files
committed
derive(PartialEq): Allow deriving enum structs
gcc/rust/ChangeLog: * expand/rust-derive-partial-eq.cc (DerivePartialEq::match_enum_tuple): Remove debug call. (DerivePartialEq::match_enum_struct): Add proper implementation. (DerivePartialEq::visit_enum): Call it. gcc/testsuite/ChangeLog: * rust/execute/torture/derive-partialeq2.rs: New test.
1 parent 1d8f176 commit 91d3a53

File tree

2 files changed

+118
-14
lines changed

2 files changed

+118
-14
lines changed

gcc/rust/expand/rust-derive-partial-eq.cc

+52-14
Original file line numberDiff line numberDiff line change
@@ -199,8 +199,6 @@ DerivePartialEq::match_enum_tuple (PathInExpression variant_path,
199199
auto self_pattern_str = "__self_" + std::to_string (i);
200200
auto other_pattern_str = "__other_" + std::to_string (i);
201201

202-
rust_debug ("]ARTHUR[ %s", self_pattern_str.c_str ());
203-
204202
self_patterns.emplace_back (
205203
builder.identifier_pattern (self_pattern_str));
206204
other_patterns.emplace_back (
@@ -240,15 +238,55 @@ MatchCase
240238
DerivePartialEq::match_enum_struct (PathInExpression variant_path,
241239
const EnumItemStruct &variant)
242240
{
243-
// NOTE: We currently do not support compiling struct patterns where an
244-
// identifier is assigned a new pattern, e.g. Bloop { f0: x }
245-
// This is what we should be using to compile PartialEq for enum struct
246-
// variants, as we need to be comparing the field of each instance meaning we
247-
// need to give two different names to two different instances of the same
248-
// field. We cannot just use the field's name like we do when deriving
249-
// `Clone`.
250-
251-
rust_unreachable ();
241+
auto self_fields = std::vector<std::unique_ptr<StructPatternField>> ();
242+
auto other_fields = std::vector<std::unique_ptr<StructPatternField>> ();
243+
244+
auto self_other_exprs = std::vector<SelfOther> ();
245+
246+
for (auto &field : variant.get_struct_fields ())
247+
{
248+
// The patterns we're creating for each field are `self_<field>` and
249+
// `other_<field>` where `field` is the name of the field. It doesn't
250+
// actually matter what we use, as long as it's ordered, unique, and that
251+
// we can reuse it in the match case's return expression to check that
252+
// they are equal.
253+
254+
auto field_name = field.get_field_name ().as_string ();
255+
256+
auto self_pattern_str = "__self_" + field_name;
257+
auto other_pattern_str = "__other_" + field_name;
258+
259+
self_fields.emplace_back (builder.struct_pattern_ident_pattern (
260+
field_name, builder.identifier_pattern (self_pattern_str)));
261+
other_fields.emplace_back (builder.struct_pattern_ident_pattern (
262+
field_name, builder.identifier_pattern (other_pattern_str)));
263+
264+
self_other_exprs.emplace_back (SelfOther{
265+
builder.identifier (self_pattern_str),
266+
builder.identifier (other_pattern_str),
267+
});
268+
}
269+
270+
auto self_elts = StructPatternElements (std::move (self_fields));
271+
auto other_elts = StructPatternElements (std::move (other_fields));
272+
273+
auto self_pattern = std::unique_ptr<Pattern> (
274+
new ReferencePattern (std::unique_ptr<Pattern> (new StructPattern (
275+
variant_path, loc, std::move (self_elts))),
276+
false, false, loc));
277+
auto other_pattern = std::unique_ptr<Pattern> (
278+
new ReferencePattern (std::unique_ptr<Pattern> (new StructPattern (
279+
variant_path, loc, std::move (other_elts))),
280+
false, false, loc));
281+
282+
auto tuple_items = std::make_unique<TuplePatternItemsMultiple> (
283+
vec (std::move (self_pattern), std::move (other_pattern)));
284+
285+
auto pattern = std::make_unique<TuplePattern> (std::move (tuple_items), loc);
286+
287+
auto expr = build_eq_expression (std::move (self_other_exprs));
288+
289+
return builder.match_case (std::move (pattern), std::move (expr));
252290
}
253291

254292
void
@@ -275,9 +313,9 @@ DerivePartialEq::visit_enum (Enum &item)
275313
static_cast<EnumItemTuple &> (*variant)));
276314
break;
277315
case EnumItem::Kind::Struct:
278-
rust_sorry_at (
279-
item.get_locus (),
280-
"cannot derive(PartialEq) for enum struct variants yet");
316+
cases.emplace_back (
317+
match_enum_struct (variant_path,
318+
static_cast<EnumItemStruct &> (*variant)));
281319
break;
282320
}
283321
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// { dg-output "true\r*\nfalse\r*\nfalse\r*\nfalse\r*\nfalse\r*\n" }
2+
3+
#![feature(intrinsics)]
4+
5+
#[lang = "sized"]
6+
trait Sized {}
7+
8+
#[lang = "copy"]
9+
trait Copy {}
10+
11+
#[lang = "structural_peq"]
12+
trait StructuralPartialEq {}
13+
14+
#[lang = "eq"]
15+
pub trait PartialEq<Rhs: ?Sized = Self> {
16+
/// This method tests for `self` and `other` values to be equal, and is used
17+
/// by `==`.
18+
#[must_use]
19+
#[stable(feature = "rust1", since = "1.0.0")]
20+
fn eq(&self, other: &Rhs) -> bool;
21+
22+
/// This method tests for `!=`.
23+
#[inline]
24+
#[must_use]
25+
#[stable(feature = "rust1", since = "1.0.0")]
26+
fn ne(&self, other: &Rhs) -> bool {
27+
!self.eq(other)
28+
}
29+
}
30+
31+
#[derive(PartialEq)]
32+
enum Foo {
33+
A { a: i32, b: i32 },
34+
B(i32, i32),
35+
C,
36+
}
37+
38+
extern "C" {
39+
fn puts(s: *const i8);
40+
}
41+
42+
fn print(b: bool) {
43+
if b {
44+
unsafe { puts("true" as *const str as *const i8) }
45+
} else {
46+
unsafe { puts("false" as *const str as *const i8) }
47+
}
48+
}
49+
50+
fn main() -> i32 {
51+
let x = Foo::A { a: 15, b: 14 };
52+
53+
let b1 = x == Foo::A { a: 15, b: 14 };
54+
let b12 = x == Foo::A { a: 15, b: 19 };
55+
let b13 = x == Foo::A { a: 19, b: 14 };
56+
let b2 = x == Foo::B(15, 14);
57+
let b3 = x == Foo::C;
58+
59+
print(b1);
60+
print(b12);
61+
print(b13);
62+
print(b2);
63+
print(b3);
64+
65+
0
66+
}

0 commit comments

Comments
 (0)