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 : 92 : DerivePartialEq::DerivePartialEq (location_t loc) : DeriveVisitor (loc) {}
31 : :
32 : : std::vector<std::unique_ptr<AST::Item>>
33 : 92 : DerivePartialEq::go (Item &item)
34 : : {
35 : 92 : item.accept_vis (*this);
36 : :
37 : 92 : return std::move (expanded);
38 : : }
39 : :
40 : : std::vector<std::unique_ptr<Item>>
41 : 92 : 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 : 92 : auto eq = builder.type_path (LangItem::Kind::EQ);
46 : 92 : auto speq = builder.type_path (LangItem::Kind::STRUCTURAL_PEQ);
47 : :
48 : 92 : auto trait_items = vec (std::move (eq_fn));
49 : :
50 : : // no extra bound on StructuralPeq
51 : 92 : auto peq_generics
52 : 184 : = setup_impl_generics (name, type_generics, builder.trait_bound (eq));
53 : 92 : auto speq_generics = setup_impl_generics (name, type_generics);
54 : :
55 : 184 : auto peq = builder.trait_impl (eq, std::move (peq_generics.self_type),
56 : : std::move (trait_items),
57 : 92 : std::move (peq_generics.impl));
58 : :
59 : 92 : auto structural_peq
60 : 184 : = builder.trait_impl (speq, std::move (speq_generics.self_type), {},
61 : 92 : std::move (speq_generics.impl));
62 : :
63 : 92 : return vec (std::move (peq), std::move (structural_peq));
64 : 276 : }
65 : :
66 : : std::unique_ptr<AssociatedItem>
67 : 92 : DerivePartialEq::eq_fn (std::unique_ptr<BlockExpr> &&block,
68 : : std::string type_name)
69 : : {
70 : 92 : auto self_type
71 : 92 : = std::unique_ptr<TypeNoBounds> (new TypePath (builder.type_path ("Self")));
72 : :
73 : 92 : auto params
74 : 184 : = vec (builder.self_ref_param (),
75 : 184 : builder.function_param (builder.identifier_pattern ("other"),
76 : 184 : builder.reference_type (
77 : 92 : std::move (self_type))));
78 : :
79 : 368 : return builder.function ("eq", std::move (params),
80 : 184 : builder.single_type_path ("bool"),
81 : 92 : std::move (block));
82 : 92 : }
83 : :
84 : : std::unique_ptr<Expr>
85 : 107 : DerivePartialEq::build_eq_expression (
86 : : std::vector<SelfOther> &&field_expressions)
87 : : {
88 : : // for unit structs or empty tuples, this is always true
89 : 107 : if (field_expressions.empty ())
90 : 9 : return builder.literal_bool (true);
91 : :
92 : 98 : auto cmp_expression
93 : 98 : = builder.comparison_expr (std::move (field_expressions.at (0).self_expr),
94 : 98 : std::move (field_expressions.at (0).other_expr),
95 : 98 : ComparisonOperator::EQUAL);
96 : :
97 : 167 : for (size_t i = 1; i < field_expressions.size (); i++)
98 : : {
99 : 69 : auto tmp = builder.comparison_expr (
100 : 69 : std::move (field_expressions.at (i).self_expr),
101 : 69 : std::move (field_expressions.at (i).other_expr),
102 : 138 : ComparisonOperator::EQUAL);
103 : :
104 : 69 : cmp_expression
105 : 69 : = builder.boolean_operation (std::move (cmp_expression),
106 : : std::move (tmp),
107 : 69 : LazyBooleanOperator::LOGICAL_AND);
108 : 69 : }
109 : :
110 : 98 : return cmp_expression;
111 : 98 : }
112 : :
113 : : void
114 : 9 : DerivePartialEq::visit_tuple (TupleStruct &item)
115 : : {
116 : 18 : auto type_name = item.get_struct_name ().as_string ();
117 : 9 : auto fields = SelfOther::indexes (builder, item.get_fields ());
118 : :
119 : 27 : auto fn = eq_fn (builder.block (build_eq_expression (std::move (fields))),
120 : 9 : type_name);
121 : :
122 : 9 : expanded
123 : 18 : = partialeq_impls (std::move (fn), type_name, item.get_generic_params ());
124 : 9 : }
125 : :
126 : : void
127 : 61 : DerivePartialEq::visit_struct (StructStruct &item)
128 : : {
129 : 122 : auto type_name = item.get_struct_name ().as_string ();
130 : 61 : auto fields = SelfOther::fields (builder, item.get_fields ());
131 : :
132 : 183 : auto fn = eq_fn (builder.block (build_eq_expression (std::move (fields))),
133 : 61 : type_name);
134 : :
135 : 61 : expanded
136 : 122 : = partialeq_impls (std::move (fn), type_name, item.get_generic_params ());
137 : 61 : }
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<TuplePatternItemsMultiple> (
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 TupleStructItemsNoRange (std::move (self_patterns)));
190 : 0 : auto other_pattern_items = std::unique_ptr<TupleStructItems> (
191 : 0 : new TupleStructItemsNoRange (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<TuplePatternItemsMultiple> (
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<TuplePatternItemsMultiple> (
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 : 22 : DerivePartialEq::visit_enum (Enum &item)
269 : : {
270 : 22 : auto cases = std::vector<MatchCase> ();
271 : 44 : auto type_name = item.get_identifier ().as_string ();
272 : :
273 : 59 : auto eq_expr_fn = [this] (std::vector<SelfOther> &&fields) {
274 : 37 : return build_eq_expression (std::move (fields));
275 : 22 : };
276 : :
277 : 22 : auto let_sd
278 : 22 : = builder.discriminant_value (DerivePartialEq::self_discr, "self");
279 : 22 : auto let_od
280 : 22 : = builder.discriminant_value (DerivePartialEq::other_discr, "other");
281 : :
282 : 22 : auto discr_cmp
283 : 44 : = builder.comparison_expr (builder.identifier (DerivePartialEq::self_discr),
284 : 44 : builder.identifier (
285 : 22 : DerivePartialEq::other_discr),
286 : 22 : ComparisonOperator::EQUAL);
287 : :
288 : 81 : for (auto &variant : item.get_variants ())
289 : : {
290 : 59 : auto enum_builder
291 : 118 : = EnumMatchBuilder (type_name, variant->get_identifier ().as_string (),
292 : 59 : eq_expr_fn, builder);
293 : :
294 : 59 : switch (variant->get_enum_item_kind ())
295 : : {
296 : 22 : case EnumItem::Kind::Tuple:
297 : 22 : cases.emplace_back (enum_builder.tuple (*variant));
298 : 22 : 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 : 59 : }
309 : :
310 : : // In case the two instances of `Self` don't have the same discriminant,
311 : : // automatically return false.
312 : 22 : cases.emplace_back (
313 : 44 : builder.match_case (builder.wildcard (), std::move (discr_cmp)));
314 : :
315 : 22 : auto match
316 : 44 : = builder.match (builder.tuple (vec (builder.identifier ("self"),
317 : 44 : builder.identifier ("other"))),
318 : 22 : std::move (cases));
319 : :
320 : 66 : auto fn = eq_fn (builder.block (vec (std::move (let_sd), std::move (let_od)),
321 : : std::move (match)),
322 : 22 : type_name);
323 : :
324 : 22 : expanded
325 : 44 : = partialeq_impls (std::move (fn), type_name, item.get_generic_params ());
326 : 22 : }
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
|