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