Line data Source code
1 : // Copyright (C) 2025-2026 Free Software Foundation, Inc.
2 :
3 : // This file is part of GCC.
4 :
5 : // GCC is free software; you can redistribute it and/or modify it under
6 : // the terms of the GNU General Public License as published by the Free
7 : // Software Foundation; either version 3, or (at your option) any later
8 : // version.
9 :
10 : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 : // for more details.
14 :
15 : // You should have received a copy of the GNU General Public License
16 : // along with GCC; see the file COPYING3. If not see
17 : // <http://www.gnu.org/licenses/>.
18 :
19 : #include "rust-derive-partial-eq.h"
20 : #include "rust-ast.h"
21 : #include "rust-expr.h"
22 : #include "rust-item.h"
23 : #include "rust-operators.h"
24 : #include "rust-path.h"
25 : #include "rust-pattern.h"
26 : #include "rust-system.h"
27 :
28 : namespace Rust {
29 : namespace AST {
30 204 : DerivePartialEq::DerivePartialEq (location_t loc, Builder::Source item_source)
31 204 : : DeriveVisitor (loc, item_source)
32 204 : {}
33 :
34 : std::vector<std::unique_ptr<AST::Item>>
35 204 : DerivePartialEq::go (Item &item)
36 : {
37 204 : item.accept_vis (*this);
38 :
39 204 : return std::move (expanded);
40 : }
41 :
42 : std::vector<std::unique_ptr<Item>>
43 204 : DerivePartialEq::partialeq_impls (
44 : std::unique_ptr<AssociatedItem> &&eq_fn, std::string name,
45 : const std::vector<std::unique_ptr<GenericParam>> &type_generics)
46 : {
47 204 : auto eq = [this] () { return builder.type_path (LangItem::Kind::EQ); };
48 204 : auto speq = builder.type_path (LangItem::Kind::STRUCTURAL_PEQ);
49 :
50 204 : auto trait_items = vec (std::move (eq_fn));
51 :
52 : // no extra bound on StructuralPeq
53 425 : auto peq_generics = setup_impl_generics (name, type_generics, [&, this] () {
54 17 : return builder.trait_bound (eq ());
55 204 : });
56 204 : auto speq_generics = setup_impl_generics (name, type_generics);
57 :
58 408 : auto peq = builder.trait_impl (eq (), std::move (peq_generics.self_type),
59 : std::move (trait_items),
60 204 : std::move (peq_generics.impl));
61 :
62 204 : auto structural_peq
63 408 : = builder.trait_impl (speq, std::move (speq_generics.self_type), {},
64 204 : std::move (speq_generics.impl));
65 :
66 204 : return vec (std::move (peq), std::move (structural_peq));
67 612 : }
68 :
69 : std::unique_ptr<AssociatedItem>
70 204 : DerivePartialEq::eq_fn (std::unique_ptr<BlockExpr> &&block,
71 : std::string type_name)
72 : {
73 204 : auto self_type
74 204 : = std::unique_ptr<TypeNoBounds> (new TypePath (builder.type_path ("Self")));
75 :
76 204 : auto params
77 408 : = vec (builder.self_ref_param (),
78 408 : builder.function_param (builder.identifier_pattern ("other"),
79 408 : builder.reference_type (
80 204 : std::move (self_type))));
81 :
82 816 : return builder.function ("eq", std::move (params),
83 408 : builder.single_type_path ("bool"),
84 204 : std::move (block));
85 204 : }
86 :
87 : std::unique_ptr<Expr>
88 218 : DerivePartialEq::build_eq_expression (
89 : std::vector<SelfOther> &&field_expressions)
90 : {
91 : // for unit structs or empty tuples, this is always true
92 218 : if (field_expressions.empty ())
93 18 : return builder.literal_bool (true);
94 :
95 200 : auto cmp_expression
96 200 : = builder.comparison_expr (std::move (field_expressions.at (0).self_expr),
97 200 : std::move (field_expressions.at (0).other_expr),
98 200 : ComparisonOperator::EQUAL);
99 :
100 793 : for (size_t i = 1; i < field_expressions.size (); i++)
101 : {
102 393 : auto tmp = builder.comparison_expr (
103 393 : std::move (field_expressions.at (i).self_expr),
104 393 : std::move (field_expressions.at (i).other_expr),
105 786 : ComparisonOperator::EQUAL);
106 :
107 393 : cmp_expression
108 393 : = builder.boolean_operation (std::move (cmp_expression),
109 : std::move (tmp),
110 393 : LazyBooleanOperator::LOGICAL_AND);
111 393 : }
112 :
113 200 : return cmp_expression;
114 200 : }
115 :
116 : void
117 69 : DerivePartialEq::visit_tuple (TupleStruct &item)
118 : {
119 138 : auto type_name = item.get_struct_name ().as_string ();
120 69 : auto fields = SelfOther::indexes (builder, item.get_fields ());
121 :
122 207 : auto fn = eq_fn (builder.block (build_eq_expression (std::move (fields))),
123 69 : type_name);
124 :
125 69 : expanded
126 138 : = partialeq_impls (std::move (fn), type_name, item.get_generic_params ());
127 69 : }
128 :
129 : void
130 95 : DerivePartialEq::visit_struct (StructStruct &item)
131 : {
132 190 : auto type_name = item.get_struct_name ().as_string ();
133 95 : auto fields = SelfOther::fields (builder, item.get_fields ());
134 :
135 285 : auto fn = eq_fn (builder.block (build_eq_expression (std::move (fields))),
136 95 : type_name);
137 :
138 95 : expanded
139 190 : = partialeq_impls (std::move (fn), type_name, item.get_generic_params ());
140 95 : }
141 :
142 : MatchCase
143 0 : DerivePartialEq::match_enum_identifier (
144 : PathInExpression variant_path, const std::unique_ptr<EnumItem> &variant)
145 : {
146 0 : auto inner_ref_patterns
147 0 : = vec (builder.ref_pattern (
148 0 : std::unique_ptr<Pattern> (new PathInExpression (variant_path))),
149 0 : builder.ref_pattern (
150 0 : std::unique_ptr<Pattern> (new PathInExpression (variant_path))));
151 :
152 0 : auto tuple_items = std::make_unique<TuplePatternItemsNoRest> (
153 0 : std::move (inner_ref_patterns));
154 :
155 0 : auto pattern = std::make_unique<TuplePattern> (std::move (tuple_items), loc);
156 :
157 0 : return builder.match_case (std::move (pattern), builder.literal_bool (true));
158 0 : }
159 :
160 : MatchCase
161 0 : DerivePartialEq::match_enum_tuple (PathInExpression variant_path,
162 : const EnumItemTuple &variant)
163 : {
164 0 : auto self_patterns = std::vector<std::unique_ptr<Pattern>> ();
165 0 : auto other_patterns = std::vector<std::unique_ptr<Pattern>> ();
166 :
167 0 : auto self_other_exprs = std::vector<SelfOther> ();
168 :
169 0 : for (size_t i = 0; i < variant.get_tuple_fields ().size (); i++)
170 : {
171 : // The patterns we're creating for each field are `self_<i>` and
172 : // `other_<i>` where `i` is the index of the field. It doesn't actually
173 : // matter what we use, as long as it's ordered, unique, and that we can
174 : // reuse it in the match case's return expression to check that they are
175 : // equal.
176 :
177 0 : auto self_pattern_str = "__self_" + std::to_string (i);
178 0 : auto other_pattern_str = "__other_" + std::to_string (i);
179 :
180 0 : self_patterns.emplace_back (
181 0 : builder.identifier_pattern (self_pattern_str));
182 0 : other_patterns.emplace_back (
183 0 : builder.identifier_pattern (other_pattern_str));
184 :
185 0 : self_other_exprs.emplace_back (SelfOther{
186 0 : builder.identifier (self_pattern_str),
187 0 : builder.identifier (other_pattern_str),
188 : });
189 : }
190 :
191 0 : auto self_pattern_items = std::unique_ptr<TupleStructItems> (
192 0 : new TupleStructItemsNoRest (std::move (self_patterns)));
193 0 : auto other_pattern_items = std::unique_ptr<TupleStructItems> (
194 0 : new TupleStructItemsNoRest (std::move (other_patterns)));
195 :
196 0 : auto self_pattern = std::unique_ptr<Pattern> (
197 0 : new ReferencePattern (std::unique_ptr<Pattern> (new TupleStructPattern (
198 0 : variant_path, std::move (self_pattern_items))),
199 0 : false, false, loc));
200 0 : auto other_pattern = std::unique_ptr<Pattern> (
201 0 : new ReferencePattern (std::unique_ptr<Pattern> (new TupleStructPattern (
202 0 : variant_path, std::move (other_pattern_items))),
203 0 : false, false, loc));
204 :
205 0 : auto tuple_items = std::make_unique<TuplePatternItemsNoRest> (
206 0 : vec (std::move (self_pattern), std::move (other_pattern)));
207 :
208 0 : auto pattern = std::make_unique<TuplePattern> (std::move (tuple_items), loc);
209 :
210 0 : auto expr = build_eq_expression (std::move (self_other_exprs));
211 :
212 0 : return builder.match_case (std::move (pattern), std::move (expr));
213 0 : }
214 :
215 : MatchCase
216 0 : DerivePartialEq::match_enum_struct (PathInExpression variant_path,
217 : const EnumItemStruct &variant)
218 : {
219 0 : auto self_fields = std::vector<std::unique_ptr<StructPatternField>> ();
220 0 : auto other_fields = std::vector<std::unique_ptr<StructPatternField>> ();
221 :
222 0 : auto self_other_exprs = std::vector<SelfOther> ();
223 :
224 0 : for (auto &field : variant.get_struct_fields ())
225 : {
226 : // The patterns we're creating for each field are `self_<field>` and
227 : // `other_<field>` where `field` is the name of the field. It doesn't
228 : // actually matter what we use, as long as it's ordered, unique, and that
229 : // we can reuse it in the match case's return expression to check that
230 : // they are equal.
231 :
232 0 : auto field_name = field.get_field_name ().as_string ();
233 :
234 0 : auto self_pattern_str = "__self_" + field_name;
235 0 : auto other_pattern_str = "__other_" + field_name;
236 :
237 0 : self_fields.emplace_back (builder.struct_pattern_ident_pattern (
238 0 : field_name, builder.identifier_pattern (self_pattern_str)));
239 0 : other_fields.emplace_back (builder.struct_pattern_ident_pattern (
240 0 : field_name, builder.identifier_pattern (other_pattern_str)));
241 :
242 0 : self_other_exprs.emplace_back (SelfOther{
243 0 : builder.identifier (self_pattern_str),
244 0 : builder.identifier (other_pattern_str),
245 : });
246 0 : }
247 :
248 0 : auto self_elts = StructPatternElements (std::move (self_fields));
249 0 : auto other_elts = StructPatternElements (std::move (other_fields));
250 :
251 0 : auto self_pattern = std::unique_ptr<Pattern> (
252 0 : new ReferencePattern (std::unique_ptr<Pattern> (new StructPattern (
253 0 : variant_path, loc, std::move (self_elts))),
254 0 : false, false, loc));
255 0 : auto other_pattern = std::unique_ptr<Pattern> (
256 0 : new ReferencePattern (std::unique_ptr<Pattern> (new StructPattern (
257 0 : variant_path, loc, std::move (other_elts))),
258 0 : false, false, loc));
259 :
260 0 : auto tuple_items = std::make_unique<TuplePatternItemsNoRest> (
261 0 : vec (std::move (self_pattern), std::move (other_pattern)));
262 :
263 0 : auto pattern = std::make_unique<TuplePattern> (std::move (tuple_items), loc);
264 :
265 0 : auto expr = build_eq_expression (std::move (self_other_exprs));
266 :
267 0 : return builder.match_case (std::move (pattern), std::move (expr));
268 0 : }
269 :
270 : void
271 40 : DerivePartialEq::visit_enum (Enum &item)
272 : {
273 40 : auto cases = std::vector<MatchCase> ();
274 80 : auto type_name = item.get_identifier ().as_string ();
275 :
276 94 : auto eq_expr_fn = [this] (std::vector<SelfOther> &&fields) {
277 54 : return build_eq_expression (std::move (fields));
278 40 : };
279 :
280 40 : auto let_sd
281 40 : = builder.discriminant_value (DerivePartialEq::self_discr, "self");
282 40 : auto let_od
283 40 : = builder.discriminant_value (DerivePartialEq::other_discr, "other");
284 :
285 40 : auto discr_cmp
286 80 : = builder.comparison_expr (builder.identifier (DerivePartialEq::self_discr),
287 80 : builder.identifier (
288 40 : DerivePartialEq::other_discr),
289 40 : ComparisonOperator::EQUAL);
290 :
291 156 : for (auto &variant : item.get_variants ())
292 : {
293 116 : auto enum_builder
294 232 : = EnumMatchBuilder (type_name, variant->get_identifier ().as_string (),
295 116 : eq_expr_fn, builder);
296 :
297 116 : switch (variant->get_enum_item_kind ())
298 : {
299 39 : case EnumItem::Kind::Tuple:
300 39 : cases.emplace_back (enum_builder.tuple (*variant));
301 39 : break;
302 15 : case EnumItem::Kind::Struct:
303 15 : cases.emplace_back (enum_builder.strukt (*variant));
304 15 : break;
305 : case EnumItem::Kind::Identifier:
306 : case EnumItem::Kind::Discriminant:
307 : // We don't need to do anything for these, as they are handled by the
308 : // discriminant value comparison
309 : break;
310 : }
311 116 : }
312 :
313 : // In case the two instances of `Self` don't have the same discriminant,
314 : // automatically return false.
315 40 : cases.emplace_back (
316 80 : builder.match_case (builder.wildcard (), std::move (discr_cmp)));
317 :
318 40 : auto match
319 80 : = builder.match (builder.tuple (vec (builder.identifier ("self"),
320 80 : builder.identifier ("other"))),
321 40 : std::move (cases));
322 :
323 120 : auto fn = eq_fn (builder.block (vec (std::move (let_sd), std::move (let_od)),
324 : std::move (match)),
325 40 : type_name);
326 :
327 40 : expanded
328 80 : = partialeq_impls (std::move (fn), type_name, item.get_generic_params ());
329 40 : }
330 :
331 : void
332 0 : DerivePartialEq::visit_union (Union &item)
333 : {
334 0 : rust_error_at (item.get_locus (),
335 : "derive(PartialEq) cannot be used on unions");
336 0 : }
337 :
338 : } // namespace AST
339 : } // namespace Rust
|