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