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-eq.h"
20 : #include "rust-ast.h"
21 : #include "rust-expr.h"
22 : #include "rust-item.h"
23 : #include "rust-path.h"
24 : #include "rust-pattern.h"
25 : #include "rust-system.h"
26 :
27 : namespace Rust {
28 : namespace AST {
29 :
30 : static TypePath
31 296 : get_eq_trait_path (Builder &builder)
32 : {
33 1184 : return builder.type_path ({builder.get_path_start (), "cmp", "Eq"}, true);
34 : }
35 :
36 133 : DeriveEq::DeriveEq (location_t loc, Builder::Source item_source)
37 133 : : DeriveVisitor (loc, item_source)
38 133 : {}
39 :
40 : std::vector<std::unique_ptr<AST::Item>>
41 133 : DeriveEq::go (Item &item)
42 : {
43 133 : item.accept_vis (*this);
44 :
45 133 : return std::move (expanded);
46 : }
47 :
48 : std::unique_ptr<AssociatedItem>
49 133 : DeriveEq::assert_receiver_is_total_eq_fn (
50 : std::vector<std::unique_ptr<Type>> &&types)
51 : {
52 133 : auto stmts = std::vector<std::unique_ptr<Stmt>> ();
53 :
54 133 : stmts.emplace_back (assert_param_is_eq ());
55 :
56 320 : for (auto &&type : types)
57 187 : stmts.emplace_back (assert_type_is_eq (std::move (type)));
58 :
59 133 : auto block = std::unique_ptr<BlockExpr> (
60 133 : new BlockExpr (std::move (stmts), nullptr, {}, {}, tl::nullopt, loc, loc));
61 :
62 133 : auto self = builder.self_ref_param ();
63 :
64 532 : return builder.function ("assert_receiver_is_total_eq",
65 399 : vec (std::move (self)), {}, std::move (block));
66 133 : }
67 :
68 : std::unique_ptr<Stmt>
69 133 : DeriveEq::assert_param_is_eq ()
70 : {
71 133 : auto eq_bound = std::unique_ptr<TypeParamBound> (
72 133 : new TraitBound (get_eq_trait_path (builder), loc));
73 :
74 133 : auto sized_bound = std::unique_ptr<TypeParamBound> (
75 266 : new TraitBound (builder.type_path (LangItem::Kind::SIZED), loc, false,
76 133 : true /* opening_question_mark */));
77 :
78 133 : auto bounds = vec (std::move (eq_bound), std::move (sized_bound));
79 :
80 133 : auto assert_param_is_eq = "AssertParamIsEq";
81 :
82 133 : auto t = std::unique_ptr<GenericParam> (
83 266 : new TypeParam (Identifier ("T"), loc, std::move (bounds)));
84 :
85 399 : return builder.struct_struct (
86 266 : assert_param_is_eq, vec (std::move (t)),
87 : {StructField (
88 399 : Identifier ("_t"),
89 266 : builder.single_generic_type_path (
90 : LangItem::Kind::PHANTOM_DATA,
91 133 : GenericArgs (
92 399 : {}, {GenericArg::create_type (builder.single_type_path ("T"))}, {})),
93 399 : Visibility::create_private (), loc)});
94 133 : }
95 :
96 : std::unique_ptr<Stmt>
97 187 : DeriveEq::assert_type_is_eq (std::unique_ptr<Type> &&type)
98 : {
99 187 : auto assert_param_is_eq = "AssertParamIsEq";
100 :
101 : // AssertParamIsCopy::<Self>
102 187 : auto assert_param_is_eq_ty
103 : = std::unique_ptr<TypePathSegment> (new TypePathSegmentGeneric (
104 374 : PathIdentSegment (assert_param_is_eq, loc), false,
105 561 : GenericArgs ({}, {GenericArg::create_type (std::move (type))}, {}, loc),
106 374 : loc));
107 :
108 : // TODO: Improve this, it's really ugly
109 187 : auto type_paths = std::vector<std::unique_ptr<TypePathSegment>> ();
110 187 : type_paths.emplace_back (std::move (assert_param_is_eq_ty));
111 :
112 187 : auto full_path
113 187 : = std::unique_ptr<Type> (new TypePath ({std::move (type_paths)}, loc));
114 :
115 187 : return builder.let (builder.wildcard (), std::move (full_path));
116 187 : }
117 :
118 : std::vector<std::unique_ptr<Item>>
119 133 : DeriveEq::eq_impls (
120 : std::unique_ptr<AssociatedItem> &&fn, std::string name,
121 : const std::vector<std::unique_ptr<GenericParam>> &type_generics)
122 : {
123 133 : auto eq = [this] () { return get_eq_trait_path (builder); };
124 30 : auto eq_bound = [&, this] () { return builder.trait_bound (eq ()); };
125 :
126 133 : auto steq = builder.type_path (LangItem::Kind::STRUCTURAL_TEQ);
127 :
128 133 : auto trait_items = vec (std::move (fn));
129 :
130 133 : auto eq_generics = setup_impl_generics (name, type_generics, eq_bound);
131 133 : auto steq_generics = setup_impl_generics (name, type_generics);
132 :
133 266 : auto eq_impl = builder.trait_impl (eq (), std::move (eq_generics.self_type),
134 : std::move (trait_items),
135 133 : std::move (eq_generics.impl));
136 :
137 : // StructuralEq is a marker trait
138 133 : decltype (trait_items) steq_trait_items = {};
139 :
140 133 : auto steq_impl
141 266 : = builder.trait_impl (steq, std::move (steq_generics.self_type),
142 : std::move (steq_trait_items),
143 133 : std::move (steq_generics.impl));
144 :
145 133 : return vec (std::move (eq_impl), std::move (steq_impl));
146 399 : }
147 :
148 : void
149 18 : DeriveEq::visit_tuple (TupleStruct &item)
150 : {
151 18 : auto types = std::vector<std::unique_ptr<Type>> ();
152 :
153 36 : for (auto &field : item.get_fields ())
154 18 : types.emplace_back (field.get_field_type ().reconstruct ());
155 :
156 36 : expanded = eq_impls (assert_receiver_is_total_eq_fn (std::move (types)),
157 18 : item.get_identifier ().as_string (),
158 36 : item.get_generic_params ());
159 18 : }
160 :
161 : void
162 83 : DeriveEq::visit_struct (StructStruct &item)
163 : {
164 83 : auto types = std::vector<std::unique_ptr<Type>> ();
165 :
166 214 : for (auto &field : item.get_fields ())
167 131 : types.emplace_back (field.get_field_type ().reconstruct ());
168 :
169 166 : expanded = eq_impls (assert_receiver_is_total_eq_fn (std::move (types)),
170 83 : item.get_identifier ().as_string (),
171 166 : item.get_generic_params ());
172 83 : }
173 :
174 : void
175 32 : DeriveEq::visit_enum (Enum &item)
176 : {
177 32 : auto types = std::vector<std::unique_ptr<Type>> ();
178 :
179 123 : for (auto &variant : item.get_variants ())
180 : {
181 91 : switch (variant->get_enum_item_kind ())
182 : {
183 58 : case EnumItem::Kind::Identifier:
184 58 : case EnumItem::Kind::Discriminant:
185 : // nothing to do as they contain no inner types
186 58 : continue;
187 32 : case EnumItem::Kind::Tuple:
188 32 : {
189 32 : auto &tuple = static_cast<EnumItemTuple &> (*variant);
190 :
191 68 : for (auto &field : tuple.get_tuple_fields ())
192 36 : types.emplace_back (field.get_field_type ().reconstruct ());
193 : break;
194 : }
195 1 : case EnumItem::Kind::Struct:
196 1 : {
197 1 : auto &tuple = static_cast<EnumItemStruct &> (*variant);
198 :
199 3 : for (auto &field : tuple.get_struct_fields ())
200 2 : types.emplace_back (field.get_field_type ().reconstruct ());
201 :
202 : break;
203 : }
204 58 : }
205 : }
206 :
207 96 : expanded = eq_impls (assert_receiver_is_total_eq_fn (std::move (types)),
208 32 : item.get_identifier ().as_string (),
209 64 : item.get_generic_params ());
210 32 : }
211 :
212 : void
213 0 : DeriveEq::visit_union (Union &item)
214 : {
215 0 : auto types = std::vector<std::unique_ptr<Type>> ();
216 :
217 0 : for (auto &field : item.get_variants ())
218 0 : types.emplace_back (field.get_field_type ().reconstruct ());
219 :
220 0 : expanded = eq_impls (assert_receiver_is_total_eq_fn (std::move (types)),
221 0 : item.get_identifier ().as_string (),
222 0 : item.get_generic_params ());
223 0 : }
224 :
225 : } // namespace AST
226 : } // namespace Rust
|